目录
路由导航守卫
简介
vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
每个守卫接受三个参数:
(1)to:即将要进入的目标路由对象
(2)from:当前导航正要离开的路由
(3) next:一定要调用该方法来resolve这个钩子。执行效果依赖next方法的调用参数。如果next函数没有执行或是传入了false等值,这个跳转就会被终止掉。
2.全局守卫
只要触发了路由就会触发路由前置和后置守卫
(1)全局前置守卫
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫resolve完之前一直处于等待中。只有等所有守卫resolve之前一直处于等待中。
用途:可以用来判断进入的路由是否想让一开始就进入的,如果不是可以让它跳转过去。
// 全局守卫,前置守卫 在路由跳转之前进行判断
router.beforeEach(async (to, from, next) => {
//to:可以获取到你要跳转到哪个路由信息
// from::可以获取到你从哪个路由来的信息
// next : 放行函数 可以放行到指定的路由
let token = store.state.user.token
let name = store.state.user.userinfo.name;
if (token) {
//用户已经登录了,去login(不让去,停留在首页)
if (to.path == '/login') {
next('/')
} else {
// 登录去的不是login,
if (name) {
next()
} else {
// 没有用户信息。派发action ,让仓库存储用户信息 进行跳转
try {
await store.dispatch('asyncUserInfo')
next()
} catch (e) {
// token 失效,获取不到用户信息,清除token 重新登录,
await store.dispatch('asyncUserOut')
}
}
}
} else {
// 未登录不能去 支付 个人中心 去登录页
let toPath = to.path
console.log(toPath);
if (toPath.indexOf('/myOrder') != -1 || toPath.indexOf('/ShopCart') != -1 || toPath.indexOf('/Center') != -1) {
console.log('未登录');
//未登录的时候想去而没有去成的信息,存储于地址栏中【路由】
next('/login?redirect=' + toPath)
} else {
console.log('放行');
next()
}
}
})
3.路由独享守卫(beforeEnter)
写在routes中的,每个路由独有的,只在当前路由中生效。
{
path: '/Trade',
component: Trade,
meta: { show: true },
beforeEnter: (to, from, next) => {
//去交易页必须从购物车来
if (from.path == '/ShopCart') {
next()
} else {
//停留在当前页
next(false)
}
}
},
4.组件内的守卫(3个)
直接写在对应组件页面中。
beforeRouterEnter:进入该组件的对应路由后触发
beforeRouterUpdate:当同一个组件,path参数不同时,进行切换的时候触发。比如这种:path:/music/:id
beforeRouterLeave:要离开该组件的对应路由时触发。
(1)beforeRouteEnter
在这里不能使用this,这时实例还没有被创建
如果要使用this。用下面这种办法:在next中通过vm来代替this
//组件内守卫 组件实例还没有被创建
beforeRouteEnter(to, from, next) {
if (from.path == "/Pay") {
next();
} else {
next(false);
}
},
(2)beforeRouteUpdate
beforeRouteLeave(to,from,next){
const answer = window.confirm("你确定要离开吗")
if(answer){
next()
}else {
next(false)
}
}
在当前路由改变,但是只有在该组件被复用时调用。
举例来说:对于一个带有动态参数的路径/foo/:id 在/foo/1与/foo/2之间进行切换跳转的时候会复用foo组件,所以才会触发这个钩子。
(3)beforeRouteLeave
案例:当所在组件的路由要离开时,给个弹窗,是否退出,是就退出,next中值为false则不退出。
beforeRouteLeave(to,from,next){
const answer = window.confirm("你确定要离开吗")
if(answer){
next()
}else {
next(false)
}
}
Vue - 自定义插件
插件通常用来为 Vue 添加全局功能,例如数据字典插件等。
1 2 3 |
|
一、使用插件
通过全局方法 Vue.use()
使用插件。它需要在你调用 new Vue()
启动应用之前完成:
1 2 3 4 5 6 |
|
也可以传入一个可选的选项对象:
1 |
|
Vue.use
会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件,在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use()。
当 install 方法被同一个插件多次调用,插件将只会被安装一次。
二、开发插件
Vue.js 的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 2. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 3. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
注意:如果插件是一个对象,必须提供 install
方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。
三、开发实例
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
main.js里面安装插件:
1 2 |
|
插件使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
注意:插件与组件的区别:
组件 (Component) 是用来构成你的 App 的业务模块,它的目标是 App.vue
。
插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身。
vue自定义指令使用
vue中除了核心功能内置的指令外,也允许注册自定义指令。有的情况下,对普通DOM元素进行底层操作,这时候就会用到自定义指令。
全局自定义指令
是通过Vue.directive(‘第一个参数是指令的名称’,{第二个参数是一个对象,这个对象上有钩子函数})
下边举例说明:
Vue.directive('focus', {
// el:指令所绑定的元素,可以用来直接操作 DOM。
//binding:一个对象,包含以下 property:
inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用
el.focus();
}
});
局部自定义指令
局部注册通过在组件options选项中设置directive属性
是定义在组件内部的,只能在当前组件中使用
下边举例说明:
directives: {
// 指令名称
dir1: {
inserted(el) {
// 指令中第一个参数是当前使用指令的DOM
console.log(el);
console.log(arguments);
// 对DOM进行操作
el.style.width = '200px';
el.style.height = '200px';
el.style.background = '#000';
}
},
color: { // 为元素设置指定的字体颜色
bind(el, binding) {
el.style.color = binding.value;
}
}
}
自定义组件的钩子函数
自定义指令也像组件那样存在钩子函数:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
项目中:拖拽
三、自定义组件的应用场景
使用自定义组件组件可以满足我们日常一些场景,这里给出几个自定义组件的案例:
1.防抖
2.图片懒加载
3.一键 Copy的功能
二、 vue自定义指令的应用场景
使用自定义指令背景
代码复用和抽象的主要形式是组件。
当需要对普通 DOM 元素进行底层操作,此时就会用到自定义指令
但是,对于大幅度的 DOM 变动,还是应该使用组件
常用案例
1、 输入框自动聚焦
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
<input v-focus>
2 下拉菜单
点击下拉菜单本身不会隐藏菜单
点击下拉菜单以外的区域隐藏菜单
Vue.directive('clickoutside', {
bind(el, binding) {
function documentHandler(e) {
if (el.contains(e.target)) {
return false
}
if (binding.expression) {
binding.value(e)
}
}
el.__vueMenuHandler__ = documentHandler
document.addEventListener('click', el.__vueMenuHandler__)
},
unbind(el) {
document.removeEventListener('click', el.__vueMenuHandler__)
delete el.__vueMenuHandler__
}
})
new Vue({
el: '#app',
data: {
show: false
},
methods: {
handleHide() {
this.show = false
}
}
})
<div class="main" v-menu="handleHide">
<button @click="show = !show">点击显示下拉菜单</button>
<div class="dropdown" v-show="show">
<div class="item"><a href="#">选项 1</a></div>
<div class="item"><a href="#">选项 2</a></div>
<div class="item"><a href="#">选项 3</a></div>
</div>
</div>
<span v-relativeTime="time"></span>
new Vue({
el: '#app',
data: {
time: 1565753400000
}
})
Vue.directive('relativeTime', {
bind(el, binding) {
// Time.getFormatTime() 方法,自行补充
el.innerHTML = Time.getFormatTime(binding.value)
el.__timeout__ = setInterval(() => {
el.innerHTML = Time.getFormatTime(binding.value)
}, 6000)
},
unbind(el) {
clearInterval(el.innerHTML)
delete el.__timeout__
}
})