一、#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><template v-slot:head(插槽名)></template></div> <template v-slot:head="slotProps"> <strong v-if="slotProps.innerItem.id == 2">{{slotProps.innerItem.name}}</strong> </template> <div><template v-slot="slotProps(插槽所在的作用域)"></template></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> (2)this.$router.push