14、VUE之指令缩写、ref、实例和组件的异同、滚动加载、#app,computed与methods的区别,5个内置组件,动态组件效果的实现方案,插槽slot,vue组件的七种写法,vuex,前后端路由拦截、vue-cli-4.0以上版本的安装(win10系统)、前端路由及触发条件
ajax请求放在created里,因为此时已经可以访问this和操作DOM了。
App.vue组件中的’#app’替换掉了index.html中的’#app’,成为最终的’#app’
一、指令缩写、$refs、实例和组件的异同、滚动加载、#app
1、完整与缩写
(1)v-bind完整语法如下:<a v-bind:href="url">...</a>,href是指令v-bind的参数
(2)v-bind缩写语法如下:<a :href="url">...</a>
(3)v-on完整语法如下:<a v-on:click="doSomething">...</a>
(4)v-on缩写语法如下:<a @click="doSomething">...</a>
(5)<template v-slot:head="slotProps"></template>
2、$refs 获取DOM元素或组件的引用。
(1)$refs 加在普通的元素上,用this.$refs.name 获取到的是dom元素
(2)$refs 加在组件上,用this.$refs.name 获取到的是组件实例,可以使用组件的所有方法。
3、实例和组件的异同
(1)相同:两者接收相同的配置,例如 data、computed、watch、methods 以及生命周期钩子等。
(2)不同点:A、自定义组件没有el配置项。B、自定义组件中的data 必须是一个函数。原因:如果data是对象,那么组件实例在不同的地方调用,data指向的是相同的地址,此处数据改变,它处数据也改变;如果data是函数,那么组件实例在不同的地方调用,data指向data此次的执行结果,是不同的地址,此处数据改变,它处数据不改变。
4、滚动加载(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}岁`;
}
/*
computeNameAndAge: {
get(){
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(插槽所在的作用域)"'>'</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前调用,即通常初始化某些属性值,然后再渲染成视图
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实例的数据变动,后执行的方法
//...
}
};
七、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