14、Vue之#app|指令縮寫|ref|實例和組件的異同|滾動加載、computed與methods的區別、5個內置組件、動態組件效果的實現方案、插槽slot、vue組件的七種寫法、子組件向父組件傳值、vuex、前后端路由攔截、vue-cli-4.0以上版本的安裝(win10系統)、前端路由及觸發條件


一、#app、指令縮寫、$refs、實例和組件的異同、滾動加載
1、App.vue組件中的’#app’替換掉了index.html中的’#app’,成為最終的’#app’ 
2、指令縮寫
(1)v-bind
完整語法如下:<a v-bind:href="url">...</a>,href是指令v-bind的參數
縮寫語法如下:<a :href="url">...</a>2)v-on
完整語法如下:<a v-on:click="doSomething">...</a>
縮寫語法如下:<a @click="doSomething">...</a>3)<template v-slot:head="slotProps"></template>
3、$refs 獲取DOM元素或組件的引用。
(1)$refs 加在普通的元素上,用this.$refs.name 獲取到的是dom元素
(2)$refs 加在組件上,用this.$refs.name 獲取到的是組件實例,可以使用組件的所有方法。
4、實例和組件的異同
(1)相同:兩者接收相同的配置,例如 data、computed、watch、methods 以及生命周期鈎子等。
(2)不同點:A、自定義組件沒有el配置項。B、自定義組件中的data 必須是一個函數。原因:如果data是對象,那么組件實例在不同的地方調用,data指向的是相同的地址,此處數據改變,它處數據也改變;如果data是函數,那么組件實例在不同的地方調用,data指向data此次的執行結果,是不同的地址,此處數據改變,它處數據不改變。
5、滾動加載(vue-infinite-scroll)
<div v-infinite-scroll="loadMore" //無限滾動的回調函數是loadMore。其內部判斷:如果當前頁大於總頁數則return,否則再次執行loadMore
   infinite-scroll-throttle-delay="500" //下次檢查和這次檢查之間的間隔
   infinite-scroll-disabled="isBusy" //isBusy為false,執行無限滾動的回調函數loadMore,即不繁忙的時候執行。
   infinite-scroll-distance="10"> //這里10決定了頁面滾動到離頁尾多少像素的時候觸發回調函數,10是像素值。通常我們會在頁尾做一個幾十像素高的“正在加載中...”,這樣的話,可以把這個div的高度設為infinite-scroll-distance的值即可。
  <div v-for="item in data" :key="item.index">{{item.name}}</div>
</div>
export default {
  data(){
    return{
      data:[],
      isBusy:false,
      itemsNumber:5,
      pageIndex:1
    };
  },   
  methods:{
    loadMore:function () {
      var self = this;
      if(this.pageIndex>response.data.total_pages){
        this.isBusy = true;
      }else{
        this.ajax.get('https:Xxxx',{
          params:{
            page:self.pageIndex,
            page_size:self.itemsNumber
          }
        }).then(function (response) {
          this.data.push({name:response.data.list});
          this.pageIndex++;
        }).catch(function (error) {
          this.error = error;
        })
      }
    }
  }
}

二、computed與methods的區別
1、正常情況下,二者沒區別;
2、computed是屬性調用,methods是方法調用;
3、computed在標簽(非屬性)上調用時不用加(),methods在標簽(非屬性)上調用時用加();
4、computed在關聯值發生改變時才調用,methods在不管關聯值是否發生改變都調用;
案例來源:https://www.jb51.net/article/137040.htm
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>computed的使用</title>
  <script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script>
</head>
<body>
  <div id="root">
  </div>
</body>
</html>
<script>
  var vm = new Vue({
    el: "#root",
    data: {
      name: "老夫",
      age: 40,
      hobby: '測試computed和methods的區別',
      nameAgeStyle: {
        fontSize: "20px",
        color: "#0c8ac5"
      },
      inputStyle: {
        display: "block",
        width: "350px"
      }
    },
    template: `<div>
        <div v-bind:style="nameAgeStyle">computed方式渲染: {{computeNameAndAge}}</div>
        <div v-bind:style="nameAgeStyle">methods方式渲染: {{methodNameAndAge()}}</div>
        <br>
        <input type="text" v-model="hobby"  v-bind:style="inputStyle">
        <div>愛好: {{hobby}}</div>
        <div>{{testComputeAndMethod()}}</div>
        </div>`,
    computed: {
      computeNameAndAge() {
        console.log('computed在運行');
        return `${this.name} == ${this.age}歲`;
      }
    },
    methods: {
      methodNameAndAge() {
        console.log('methods在運行');
        return `${this.name} == ${this.age}歲`;
      },
      testComputeAndMethod() {
        console.log("testComputeAndMethod在運行");
      }
    }
  })
</script>

三、5個內置組件
1、component
渲染一個“元組件”為動態組件。依 is 的值,來決定哪個組件被渲染。
2、transition
作為單個元素/組件的過渡效果。只會把過渡效果應用到其包裹的內容上,而不會額外渲染 DOM 元素,也不會出現在可被檢查的組件層級中。
3、transition-group
作為多個元素/組件的過渡效果。它渲染一個真實的 DOM 元素。默認渲染 <span>,可以通過 tag attribute 配置哪個元素應該被渲染。它每個子節點必須有獨立的 key,動畫才能正常工作。
4、keep-alive
包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。它是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在組件的父組件鏈中。
5、slot
作為組件模板之中的內容分發插槽。它自身將被替換。
(1)<base-layout>組件定義
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>2)<base-layout>組件使用
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

四、動態組件效果的實現方案
1、在內置組件<component>里面使用 v-bind: is。沒有keep-alive的配合,只能實現切換,不能實現緩存
<div id="app">
  <component v-bind:is="whichcomp"></component>
  <button v-on:click="choosencomp('a')">a</button>
  <button v-on:click="choosencomp('b')">b</button>
  <button v-on:click="choosencomp('c')">c</button>
</div>
var app=new Vue({
  el: '#app',
  components:{
  acomp:{
    template:`<p>這里是組件A</p>`
  },
  bcomp:{
    template:`<p>這里是組件B</p>`
  },
  ccomp:{
    template:`<p>這里是組件C</p>`
  }},
  data:{whichcomp:""},
  methods:{
    choosencomp:function(x){
    this.whichcomp=x+"comp"}
  }
})
2、把組件作為子組件放在內置組件<keep-alive>里,后者包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。
(1)include:字符串或正則表達式。只有名稱匹配的組件會被緩存。
(2)在 2.2.0 及其更高版本中,activated 和 deactivated 將會在 <keep-alive> 樹內的所有嵌套組件中觸發。
<keep-alive include="a,b" include='a' :include="/a|b/" :include="['a', 'b']">
/* 字符串、正則、數組,也可以沒有這些 */
  <component :is="view"></component>
</keep-alive>
<keep-alive>
  <comp-a v-if="a > 1"></comp-a>
  <comp-b v-else></comp-b>
</keep-alive>
<keep-alive>
  <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<transition>
  <keep-alive>
    <component :is="view"></component>
  </keep-alive>
</transition>

五、插槽slot
1、vue2.6.0及以后版本,
使用組件<base-layout>並定義插槽
<base-layout>
  <template v-slot:head="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</base-layout>
定義組件<base-layout>並使用插槽
<div>
  <slot name="head" v-bind:user="obj">
    {{ user.text }}<!-- 后備內容 -->
  </slot>
</div>
2、vue2.6.0以前版本,
使用組件<base-layout>並定義插槽 
<base-layout>
  <template slot="head" slot-scope="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</base-layout>
定義組件<base-layout>並使用插槽 
<div>
  <slot name="head" v-bind:user="obj">
    {{ user.text }}<!-- 后備內容 -->
  </slot>
</div>
3、插槽實例:
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title></title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- Vue.js v2.6.10 -->
</head>
<style type="text/css">

</style>
<body>
  <div id="app">
    <this-div :list="list">
      <div>&lt;template v-slot:head(插槽名)&gt;&lt;/template&gt;</div>
      <template v-slot:head="slotProps">
        <strong v-if="slotProps.innerItem.id == 2">{{slotProps.innerItem.name}}</strong>
      </template>
      <div>&lt;template v-slot="slotProps(插槽所在的作用域)"&gt;&lt;/template&gt;</div>
    </this-div>
  </div>
</body>
</html>
<script type="text/javascript">
  Vue.component('this-div', {
    props: ['list'],
    template: `<div>
            <slot/>
            <div style="margin:20px 0">以上是默認插槽內容。以下是具名插槽內容,每循環一次,插槽就渲染一次,如果插槽里沒有內容,就用后備內容</div>
            <div>
              <div :key='item.id' v-for='item in list'>
                <slot name='head' :innerItem='item'>{{item.name+',這是后備(備用)內容'}}</slot>
              </div>
            </div>
          </div>`,
  });
  var vm = new Vue({
    el: '#app', 
    data: {
      list: [{
        id: 1,
        name: 'apple'
      }, {
        id: 2,
        name: 'banane'
      }, {
        id: 3,
        name: 'orange'
      }]
    }
  });
</script>

六、vue組件的七種寫法
來源:https://www.cnblogs.com/hanguidong/p/9381830.html
1. 字符串
Vue.component('my-checkbox', {
    template: `<div class="checkbox-wrapper" @click="check"><div :class="{ checkbox: true, checked: checked }"></div><div class="title"></div></div>`,
    data() {
        return { checked: false, title: 'Check me' }
    },
    methods: {
        check() { this.checked = !this.checked; }
    }
});
2. 模板字面量
Vue.component('my-checkbox', {
    template: `<div class="checkbox-wrapper" @click="check">
            <div :class="{ checkbox: true, checked: checked }"></div>
            <div class="title"></div>
          </div>`,
    data() {
        return { checked: false, title: 'Check me' }
    },
    methods: {
        check() { this.checked = !this.checked; }
    }
});
3. x-template
<body>
  <div id="app">
    <my-component></my-component>
    <!-- 使用x-template -->
    <script type="text/x-template" id="my-component">
      <div>這是組件的內容</div>
    </script>
  </div>
  <script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
  <script>
    Vue.component('my-component', {
      template: '#my-component',   //將id賦給template
      data() {
        return { checked: false, title: 'Check me' }
      },
      methods: {
        check() { this.checked = !this.checked; }
      }
    });

    var app = new Vue({
      el: '#app',
    })
  </script>
</body>
/* Vue.component('my-checkbox', {
    template: '#checkbox-template',
    data() {
        return { checked: false, title: 'Check me' }
    },
    methods: {
        check() { this.checked = !this.checked; }
    }
});
<script type="text/x-template" id="checkbox-template">
    <div class="checkbox-wrapper" @click="check">
        <div :class="{ checkbox: true, checked: checked }"></div>
        <div class="title"></div>
    </div>
</script> */
4. 內聯模板
內聯模板不會把子組件的內容分發渲染到父組件中
而是需要在父組件中實現其內容的渲染
不使用父組件的數據
不是slot
(1)父組件
<template>
  <div>
  <my-checkbox inline-template>
    <div class="checkbox-wrapper" @click="check">
      <div :class="{ checkbox: true, checked: checked }"></div>
      <div class="title"></div>
    </div>
  </my-checkbox>
  </div>
</template>
<script>
import myCheckbox from './my-checkbox'
export default {
  components: {  myCheckbox },
  data() {
    return {
      name:'父組件數據name'
    }
  },
}
</script>2)子組件
Vue.component('my-checkbox', {
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  }
});
5. render 函數
render 函數需要你將模板定義為 JavaScript 對象,這顯然是最詳細和抽象的模板選項。
不過,優點是你的模板更接近編譯器,並允許你使用完整的 JavaScript 功能,而不是指令提供的子集。
Vue.component("my-checkbox", {
  data() {
    return { checked: false, title: "Check me" };
  },
  methods: {
    check() {
      this.checked = !this.checked;
    },
  },
  render(createElement) {
    return createElement(
      "div",
      {
        attrs: {
          class: "checkbox-wrapper",
        },
        on: {
          click: this.check,
        },
      },
      [
        createElement("div", {
          class: {
            checkbox: true,
            checked: this.checked,
          },
        }),
        createElement(
          "div",
          {
            attrs: {
              class: "title",
            },
          },
          [this.title]
        ),
      ]
    );
  },
});
6. JSX
Vue 中最有爭議的模板選項是 JSX,一些開發者認為它丑陋、不直觀,是對 Vue 精神的背叛。JSX 需要你先編譯,因為它不能被瀏覽器運行。
不過,如果你需要完整的 JavaScript 語言功能,又不太適應 render 函數過於抽象的寫法,那么 JSX 是一種折衷的方式。
Vue.component("my-checkbox", {
  data() {
    return { checked: false, title: "Check me" };
  },
  methods: {
    check() {
      this.checked = !this.checked;
    },
  },
  render() {
    return (
      <div class="checkbox-wrapper" onClick={this.check}>
        <div class={{ checkbox: true, checked: this.checked }}></div>
        <div class="title">{this.title}</div>
      </div>
    );
  },
});
7. 單文件組件(vue2.0之組件的es6寫法)
<template>
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title"></div>
  </div>
</template>
import comTab from '@/components/ComTab/com-tab'//導入別處組件
export default {
  components: {    
    comTab,//此組件依賴的組件
  },
  name: 'ComTpl',//組件名
  props: {   //用於接收父組件向子組件傳遞的數據
    tester: {
      type: Object
    }
  },
  data() {//本組件的數據
    return {
      tests: [],
      selectedTest: {}
    };
  },
  computed: {//計算屬性,所有get,set的this上下文都被綁定到Vue實例
    方法名() {
      //.....
    }
  },
  created() {//生命周期之一。在模板渲染成html前調用,即通常初始化某些屬性值,然后再渲染成視圖
    //ajax請求放在created里,因為此時已經可以訪問this和操作DOM了。
    this.classMap = ['a', 'b', 'c', 'd', 'e'];
    //如進行異步數據請求
    this.$http.get('/api/tests').then((response) => {
      response = response.body;
    if (response.errno === 0) {
      this.goods = response.data;
    }
  });
  },
  mounted() {   //在模板渲染成html后調用,通常是初始化頁面完成后,再對html的dom節點進行一些需要的操作
    this.$nextTick(() => {
      this._initScroll();
    this._initPics();
  });
  },
  methods: {//定義方法
    方法名(參數) {
      //...
    }
  },
  filters: {  //過濾器,可用來寫,比如格式化日期的代碼
    //
    formatDate(time) {
      let date = new Date(time);
      return formatDate(date, 'yyyy-MM-dd hh:mm');
    }
  },
  watch: {//用來觀察Vue實例的數據變動,后執行的方法
    //...
  }
};

七、子組件向父組件傳值
1、通過this
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Vue子組件給父組件傳值</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
  </head>
  <body>
    <div id="el">
      <p>{{total}}</p>
      <button-this v-bind:son-prop="parentAdd"></button-this>
    </div>
    <script>
    Vue.component('button-this', {
      template: '<button v-on:click="sonAdd">累加</button>',
      props: {       
        sonProp: {
          type: Function
        }
      },
      data: function() {
        return {
          counter: 0
        }
      },
      methods: { 
        sonAdd: function() {
          this.counter += 1;
          this.sonProp(this.counter);
        }                                 
      },
    })
    new Vue({
      el: '#el',
      data: {
        total: 0
      },
      methods: {
        parentAdd: function(counter) {
          this.total = counter
        }
      }
    })
    </script>
  </body>
</html>
2、通過$emit
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Vue子組件給父組件傳值</title>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
  </head>
  <body>
    <div id="el">
      <p>{{total}}</p>
      <button-counter v-on:son-event="parentAdd"></button-counter>
    </div>
    <script>
      Vue.component('button-counter', {
        template: '<button v-on:click="addCounter">clickButton</button>',
        props:['sonProp'],
        data: function() {
          return {
            counter: 0
          }
        },
        methods: { 
          addCounter: function() {
            this.counter += 1;
            this.$emit('son-event',this.counter);
          }                                  
        },
      })
      new Vue({
        el: '#el',
        data: {
          total: 0
        },
        methods: {
          parentAdd: function(counter) {
            this.total = counter
          }
        }
      })
    </script>
  </body>
</html>

八、vuex
1、示例:
注意:Vue實例是Vue應用的啟動器,Vue組件是Vue實例的擴展。
import Vue from 'vue'
import router from './router'
import store from './store'
import '@/permission'//router.beforeEach
<template>
 <div id="app">
   <router-view/>
 </div>
</template>
<script>
 export default {
   name: 'App'
 }
</script>
new Vue({ 
  el: '#app', 
  router, 
  store, 
  render: h => h(App) 
}) 
mutation:突變,改變 
2、VUEX簡介 
(1)redux:處理同步用 dispatch action(對象類型),處理異步用 dispatch action(函數類型) 
(2)Vuex:處理同步用 commit(mutations) ,處理異步用 dispatch(action),在action里執行 commit(mutations)
(3)store:在普通.JS中,執行 store.commit(mutation) 或者 store.dispatch(action) 
(4)$store:在.vue中,執行this.$store.commit(mutation) 或者 this.$store.dispatch(action) 
(5)store 實例
const store = new Vuex.Store({ 
  state: state, 
  mutations: mutations, 
  actions: actions, 
  getters: getters, 
  modules: { 
    app, 
    user, 
    permission 
  }
})
3、模塊(默認)
注意:Vuex允許我們將 store 分割成 module,每個模塊擁有自己的 state、mutation、action、getter、module。
(1)state
state: {amount: 0}
export default {
  computed:{
    ...mapState(['amount']) // 在html上用{{amount}}、在js中用this.amount 指向 store.state.amount。 
  }
}; 
(2)mutations
mutations: {
  mutationA (state,playLoad) {
    state.amount = playLoad.amount
  }
}
store.commit('mutationA', {
  amount: 10
})
export default { 
  methods: { 
    ...mapMutations([ 
      'mutationA',// 在html上用{{mutationA({amount:10})}}、在js中用this.mutationA({amount:10}) 指向 this.$store.commit('mutationA',{amount:10})  
    ])
  } 
}
(3)actions
actions: {
  actionA ({state, commit, rootState},playLoad) {
    var { amount } = playLoad;
    commit('mutationA', {
      amount: amount+10             
    })
  }
}
store.dispatch('actionA', {
  amount: 10
})
export default { 
  methods: { 
    ...mapActions([ 
      'actionA' // 在html上用{{actionA({amount:10})}}、在js中用this.actionA({amount:10}) 指向 this.$store.dispatch('actionA',{amount:10}) 
    ])
  } 
}
(4)getters
getters: { 
  getterA: state => { 
    return state.todos.filter(todo => todo.done) 
  }
}
export default {
  computed: {
    ...mapGetters({getterA}) // 在html上用{{getterA}}、在js中用this.getterA 指向 `this.$store.getters.getterA`
  },
}; 
4、map
(1)mapState:將store中的state映射到局部計算屬性。 
<p>mapState方式{{count}}</p> 
computed: {
  //將 mapState 的每一項作為 computed 對象的每一項,  
  ...mapState([ 'count'
  // 把 this.count 指向 store.state.count。  
  ]), 
} 
computed: mapState({
  //用 mapState 的整體來取代 computed 對象的整體, 
  count: state => state.count, 
  countAlias: 'count',// 這里的 'count' 等同於 `state => state.count`  
  countPlusLocalState (state) { 
    return state.count + this.localCount// 為了能夠使用 `this` 獲取局部狀態,必須使用常規函數  
  } 
}) 
(2)mapGetters:將store中的getter映射到局部計算屬性。 
<template> 
<div> 
<h4>測試1:Count is {{ count }}</h4> 
<P>通過屬性訪問:{{ doneTodosCount }}</p> 
<P>通過方法訪問:{{ doneTodos }}</p> 
</div> 
</template> 
<script> 
import { mapGetters } from "vuex";
export default {
 computed: {
   count() {
     return this.$store.state.count;
   },
   ...mapGetters(["doneTodos", "doneTodosCount"]),
   ...mapGetters({
     doneCount: "doneTodosCount", // 把 `this.doneCount` 指向 `this.$store.getters.doneTodosCount`
   }),
 },
};
</script> 
(3)mapMutations:將store 中的 mutations 映射到局部方法屬性。 
export default { 
  methods: { 
    ...mapMutations([ 
      'increment', // 把 `this.increment()` 指向 `this.$store.commit('increment')`
      'incrementBy'// 把 `this.incrementBy(amount)` 指向 `this.$store.commit('incrementBy', amount)`  
    ]), 
    ...mapMutations({ 
      add: 'increment' // 把 `this.add()` 指向 `this.$store.commit('increment')`  
    }) 
  } 
} 
(4)mapActions:將store 中的 actions 映射到局部方法屬性。 
export default { 
  methods: { 
   ...mapActions([ 'increment', 
    // 把 `this.increment()` 指向 `this.$store.dispatch('increment')` 'incrementBy' 
    // 把 `this.incrementBy(amount)` 指向 `this.$store.dispatch('incrementBy', amount)`  
   ]), 
   ...mapActions({ add: 'increment' 
    // 把 `this.add()` 指向 `this.$store.dispatch('increment')`  
   }) 
  } 
} 

九、vue-router 
1、示例: 
注意:前端單頁面應用,就是把組件和路由連起來 
import Vue from 'vue' 
import router from './router' 
import store from './store' 
import '@/permission'//router.beforeEach 
new Vue({ 
 el: '#app', 
 router, 
 store, 
 render: createElement => createElement(App)//render執行,即createElement執行 
}) 
“導航”表示路由正在發生改變。
2、一個路徑可以匹配多個路由,先定義的路由,優先級高。 
===路徑:this.$router.push('/user-admin') 
(1)路由1:{ path: '/user-a*' } 
(2)路由2:{ path: '/user-ad*' } 
3、route(無)、router、$route、$router 
(1)route:(無) 
(2)router:在普通.JS中,關於全局路由的對象,router.beforeEach 
(3)$router:在.vue子組件中,關於全局路由的對象,this.$router.push 
(4)$route:在.vue子組件中,關於當前路由的對象,this.$route.path 
4、vueRouter三大導航守衛 
(1)全局導航守衛,主要包括beforeEach、beforeResolve和aftrEach, 
 router.beforeEach((to, from, next) => { 
   // to: Route: 即將要進入的目標 路由對象 
   // from: Route: 當前導航正要離開的路由 
   // next: Function: 一定要調用該方法來 resolve 這個鈎子。執行效果依賴 next 方法的調用參數。 
   const route = ["index", "list"]; 
   let isLogin = store.state.token; // 是否登錄 // 未登錄狀態;當路由到route指定頁時,跳轉至login 
   if (route.indexOf(to.name) >= 0) { 
     if (isLogin == null) { 
       router.push({ path: "/login" }); 
     } 
   } // 已登錄狀態;當路由到login時,跳轉至home 
   localStorage.setItem("routerName", to.name); 
   if (to.name === "login") { 
     if (isLogin != null) { 
       router.push({ path: "/HomeMain" }); 
     } 
   } 
   next(); 
 }); 
(2)路由導航守衛 
 { 
   path: '/dashboard', 
   component: resolve => require(['../components/page/Dashboard.vue'], resolve), 
   meta: { title: '系統首頁'}, 
   beforeEnter: (to, from, next) => { } 
 }, 
(3)組件導航守衛 
const Foo = { 
  template: `...`, 
  beforeRouteEnter (to, from, next) { 
     //beforeRouteEnter 是支持給 next 傳遞回調的唯一守衛  
  }, 
  beforeRouteUpdate (to, from, next) { }, 
  beforeRouteLeave (to, from, next) { } 
} 
5、路由組件傳參 
 const router = new VueRouter({ 
   routes: [ 
    { 
      //布爾模式 props 被設置為 true,route.params 將會被設置為組件屬性。  
      path: '/user/:id', 
      component: User, 
      props: true 
    }, 
    { //對象模式 對於包含命名視圖的路由,你必須分別為每個命名視圖添加 `props` 選項:  
      path: '/user/:id', 
      components: { 
        default: User, 
        sidebar: Sidebar 
      }, 
      props: { 
        default: true, 
        sidebar: false 
      } 
    }, 
    { 
      //函數模式 URL /search?q=vue 會將 {q:'vue'} 作為屬性傳遞給 SearchUser 組件 
      path: '/search', 
      component: SearchUser, 
      props: (route) => ({ 
        query: route.query.q 
      }) 
    } 
   ] 
 })
6、VUE-Router嵌套與命名視圖 
  (1)router-link
  <router-link to="bbb">Home</router-link>
  <router-link :to="'bbb'">Home</router-link>
  <router-link :to="{ path: 'bbb' }">Home</router-link>
  <router-link :to="{ name: 'BBB', params: { userId: 123 }}">User</router-link>
  const router = new VueRouter({
    routes: [
      {
        path: '/bbb',
        component: BBB
      }
    ];
  })
  (2)router-view 命名視圖 
  <router-view></router-view>
  <router-view name="two"></router-view>
  <router-view name="three"></router-view>
  const router = new VueRouter({
    routes: [/* 多個視圖就需要多個組件。確保正確使用components配置(帶上s),如果 router-view 沒有設置名字,那么默認為 default。 */
      {
        path: '/',
        components: {
          default: AAA,
          two: BBB,
          three: CCC
        }
      }
    ]
  })
  (3)router-view 嵌套與命名視圖
  以下是總router
  const router = new VueRouter({
    routes: [
      {
        path: '/a',
        components: {
          default: A1,
          two: A2,
          three: A3
        },
        children: [
          {
            path: 'aa',
            components: {
              default: AA1,
              five: AA2,
              six: AA3
            }
          }
        ]
      }
    ]
  })
  以下是總router的說明
  在/a路由下,把父組件A1、A2、A3渲染到頁面的router-view標簽里,如下。
  <router-view></router-view>
  <router-view name="two"></router-view>
  <router-view name="three"></router-view>/a/aa路由下,把子組件AA1、AA2、AA3渲染到A1、A2或A3的router-view標簽里,如下。
  <router-view></router-view>
  <router-view name="five"></router-view>
  <router-view name="six"></router-view>
7、完整的導航解析流程 
(1)導航被觸發。 
(2)在失活的組件里調用 beforeRouteLeave 守衛。 
(3)調用全局的 beforeEach 守衛。 
(4)在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)。 
(5)在路由配置里調用 beforeEnter。 
(6)解析異步路由組件。 
(7)在被激活的組件里調用 beforeRouteEnter。 
(8)調用全局的 beforeResolve 守衛 (2.5+)。 
(9)導航被確認。 
(10)調用全局的 afterEach 鈎子。 
(11)觸發 DOM 更新。 
(12)用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。 
 
十、vue前后端路由攔截
1、vue-router前端路由攔截
(1)
function getClientType(data) {
  return service({
    url: '/warn/getClientType',
    method: 'post',
    data: data,
    dataTranform: true
  })
}
(2)
actions: {
  GenerateRoutes({
    commit
  }, data) {
    return new Promise(
      function (resolve) {
        const { roles } = data;
        const accessedRouters = asyncRouterMap.filter(function(v) {
          return makeChildRoute(roles, v)
        })
        makeRedirect(accessedRouters)
        commit('SET_ROUTERS', accessedRouters)
        resolve()
      })
  }
}
(3)
router.beforeEach(function (to, from, next) {
  NProgress.start();
  if (getToken()) {//是否已登錄
    if (store.getters.roles.length === 0) {//是否獲取了權限列表
      store
        .dispatch("GetInfo") //執行GetInfo函數,返回Promise實例的過程中,向后台發送請求
        .then(function (allResult) {
          getSystemTime()
            .then(function (thisResult) {
              store.commit("TIME", thisResult);
              return getClientType({
                ump: 0,
              });
            })
            .then(function (thisResult) {
              store.commit("GET_CLIENTS", thisResult);
              return getClientType({
                ump: 1,
              });
            })
            .then(function (thisResult) {
              store.commit("GET_UMPCLIENTS", thisResult);
              store
                .dispatch("GenerateRoutes", {
                  roles: allResult.resc,
                })
                .then(function () {//生成可訪問的路由表
                  router.addRoutes(store.getters.addRouters); //動態添加可訪問路由表
                  isLoginSucce(to, next);
                });
            });
        })
        .catch(function () {
          store.dispatch("FedLogOut").then(function () {
            next({
              path: "/",
            });
          });
        });
    } else {
      if (to.path === "/") {
        next({
          path: makeDefaultPageIndex(),
        });
        NProgress.done();
      } else {
        isLoginSucce(to, next, true);
      }
    }
  } else {
    if (to && whiteList.indexOf(to.path) !== -1) {
      next();
    } else {
      next(`/login`); // 否則全部重定向到登錄頁
      NProgress.done();
    }
  }
});
2、axios后端路由攔截
(1)獲取請求實例
var service = axios.create({
  baseURL: process.env.BASE_API,
  timeout: 15000
})
(2)獲取promise實例
var instance = service({
  url: '/warn/licenceUpload',
  method: 'post',
  data: data
})
(3)添加請求攔截器
service.interceptors.request.use(function (config) {
  // 在發送請求之前做些什么
  return config;
}, function (error) {
  // 對請求錯誤做些什么
  return Promise.reject(error);
});
(4)添加響應攔截器
axios.interceptors.response.use(function (response) {
  // 對響應數據做點什么
  return response;
}, function (error) {
  // 對響應錯誤做點什么
  return Promise.reject(error);
});

十一、vue-cli-4.0以上版本的安裝(win10系統)
https://cli.vuejs.org/zh/guide/
1、配置path(已配置的可跳過)
(1)運行,npm config get prefix
(2)得到,C:\Users\xxx\AppData\Roaming\npm
(3)前往,桌面>右鍵計算機>屬性>高級系統設置>環境變量-系統變量-(雙擊)path>新建-粘貼(得到的內容)-確定
2、安裝
(1)npm i npm -g
(2)npm i @vue/cli -g 或 npm install @vue/cli -g
3、package.json 
"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "lint": "vue-cli-service lint"//代碼檢測
  "111": "vue-cli-service inspect",
},
運行 npm run 111,可得出以下結論,
(1)config.module.rule('svg').exclude.add(resolve('src/icons')).end()
對vue-cli-4.0里內置的'svg'模塊規則進行修改
(2)config.module.rule('icons').test(/\.svg$/).include.add(resolve('src/icons')).end()
定義並向vue-cli-4.0里注入名為'icons'的模塊規則
4、lintOnSave
module.exports = {
  lintOnSave: process.env.NODE_ENV !== 'production'
}
(1)作用:是否在每次保存時 lint(應理解為"檢查") 代碼
(2)取值
(2-1)取值false:關閉每次保存都進行檢測
(2-2)取值true或'warning':開啟每次保存都進行檢測,lint 錯誤將顯示到控制台命令行,而且編譯並不會失敗
(2-3)取值'default''error':開啟每次保存都進行檢測,lint 錯誤將顯示到瀏覽器頁面上,且編譯失敗
 
十二、前端路由:url有變化,但不向后台發送請求,
1、它的作用是 
(1)記錄當前頁面的狀態; 
(2)可以使用瀏覽器的前進后退功能; 
2、hash模式幫我們實現這兩個功能,因為它能做到: 
(1)改變url且不讓瀏覽器向服務器發出請求; 
(2)監測 url 的變化; 
(3)截獲 url 地址,並解析出需要的信息來匹配路由規則。 
3、history 模式改變 url 的方式會導致瀏覽器向服務器發送請求。
4、vue前端路由觸發條件
(1)<router-link :to="'bbb'">Home</router-link>2this.$router.push

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM