项目源码地址在文档最后
1.关于根据权限展示不同界面的实现
定义多个子组件,在父组件中引用
如图,红框中index.vue为父组件,上面文件夹均为子组件。
在父组件中引用并注册子组件
通过currentRole控制展示哪个组件
2.插槽 slot
- 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
- 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
如图,在父组件中引入子组件并在中放内容
刚才放置的内容将在子组件的slot标签位置展示。
结果如图:
关于插槽还有很多应用,具体请参考:https://www.cnblogs.com/lovey...
3.获取当前页面路由信息
完整url: window.location.href
路由路径: this.$route.path
路由路径参数: this.$route.params
4.结合element-ui实现左侧导航栏
定义好路由信息
- icon为对应图标
- leaf判断是否有二级菜单。为true表示没有
左侧导航栏部分代码如下:
<el-menu
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="rgb(191, 203, 217)"
router
unique-opened
active-text-color="rgb(64, 158, 255)"
:default-active="$route.path"
@open="handleOpen"
@close="handleClose">
<template v-for="(item,index) in $router.options.routes" v-key='item.path'>
<el-submenu :index="index+''" v-if="!item.leaf">
<template slot="title"><i :class="'iconfont '+item.icon"></i>{{item.name}}</template>
<el-menu-item v-for='(child,index) in item.children' :index='child.path' :key='index'>
<template slot="title">
<span>{{child.name}}</span>
</template>
</el-menu-item>
</el-submenu>
<el-menu-item :index='item.children[0].path' v-if="item.leaf">
<template slot="title">
<i :class="'iconfont '+item.icon"></i>
<span>{{item.name}}</span>
</template>
</el-menu-item>
</template>
</el-menu>
- router : 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转
- unique-opened : 是否只保持一个子菜单的展开
- default-active : 默认高亮菜单
解析:遍历全部路由信息 $router.options.routes,通过leaf值判断是否有二级菜单。有二级菜单需用el-submenu。
效果图如下:
5.导航栏增加展开收起功能
el-menu增加collapse
属性,通过控制该值控制导航栏展开收起。
通过点击图标控制isCollapse。左侧导航栏收起时 右侧宽度也需改变,所以此项目选用flex布局,右侧设置样式flex:1
需增加样式
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
}
效果图如下:
6.浏览器顶部进度条nprogress
安装:npm install \--save nprogress
使用:
//route.js
//导入
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
router.beforeEach((to, from, next) => {
NProgress.start()
next()
})
router.afterEach(() => {
NProgress.done()
})
效果图:
可手动修改颜色:
#nprogress .bar {
background: red !important; //自定义颜色
}
7.screenfull
实现全屏操作并监听ESC
安装 npm install --save screenfull
引入 import screenfull from 'screenfull'
通过fullFlag展示当前状态(展开/收起)
full方法实现全屏:
full:function(){
if (!screenfull.isEnabled) { // 如果不允许进入全屏,发出不允许提示
this.$message({
message: '不支持全屏',
type: 'warning'
})
return false
}
this.fullFlag=!this.fullFlag
screenfull.toggle();
},
当点击ESC退出全屏时,需改变当前状态(即收起要变成展开),这里通过监听浏览器大小变化结合screenfull.isFullscreen
实现
mounted(){
let me=this;
window.onresize=function(){
// 全屏下监控是否按键了ESC
if (!me.checkFull()) {
// 全屏下按键esc后要执行的动作
me.fullFlag = false
}
}
},
checkFull方法如下:
checkFull() {
var isFull = screenfull.isFullscreen;
if (isFull === undefined) {
isFull = false;
}
return isFull;
}
全屏状态实现效果:
8.关于弹框el-dialog
及自定义标题
自定义标题:
通过dialogVisible
值控制弹框展示/隐藏:
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%" v-dialogDrag>
<div slot="title" class="header-title">
<span class="title-name">
<i class='iconfont iconapplications'></i>
自定义标题
</span>
</div>
<span>这是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size='mini'>取 消</el-button>
<el-button type="primary" @click="dialogVisible = false" size='mini'>确 定</el-button>
</span>
</el-dialog>
9.Vue.directive
自定义指令实现可拖动的弹框el-dialog
我们先来说说Vue.directive
Vue.directive:自定义指令,类似内置的v-if,v-show。即可根据自己需求增加指令。
来看下官网的案例:
需求:实现在打开页面后还没点击过任何内容,这个输入框就处于聚焦状态。
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
再来介绍下他的钩子函数:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
-
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 -
inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 -
update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。 -
componentUpdated
:指令所在组件的 VNode及其子 VNode全部更新后调用。 -
unbind
:只调用一次,指令与元素解绑时调用。
接下来我们来看一下钩子函数的参数 (即el
、binding
、vnode
和oldVnode
)。
指令钩子函数会被传入以下参数:
钩子函数参数:
-
el
:指令所绑定的元素,可以用来直接操作 DOM。 -
binding
:一个对象,包含以下 property:-
name
:指令名,不包括v-
前缀。 -
value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为2
。 -
oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。 -
expression
:字符串形式的指令表达式。例如v-my-directive="1 + 1"
中,表达式为"1 + 1"
。 -
arg
:传给指令的参数,可选。例如v-my-directive:foo
中,参数为"foo"
。 -
modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为{ foo: true, bar: true }
。
-
-
vnode
:Vue 编译生成的虚拟节点。移步VNode API来了解更多详情。 -
oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用。
除了el
之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的dataset
来进行。
具体请看官网:https://cn.vuejs.org/v2/guide...
接下来实现弹框的拖拽:
main.js中定义:
//main.js
Vue.directive('dialogDrag', {
bind(el, binding, vnode, oldVnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft;
const disY = e.clientY - dialogHeaderEl.offsetTop;
const screenWidth = document.body.clientWidth;
const screenHeight = document.body.clientHeight;
const minDragDomLeft = dragDom.offsetLeft;
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDom.offsetWidth;
const minDragDomTop = dragDom.offsetTop;
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDom.offsetHeight;
// 获取到的值带px 正则匹配替换
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +screenWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +screenHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
var l = e.clientX - disX;
var t = e.clientY - disY;
// 边界处理
if (-(l) > minDragDomLeft) {
l = -minDragDomLeft
} else if (l > maxDragDomLeft) {
l = maxDragDomLeft
}
if (-(t) > minDragDomTop) {
t = -minDragDomTop
}
else if (t > maxDragDomTop) {
t = maxDragDomTop
}
// 移动当前元素
dragDom.style.left = `${l + styL}px`
dragDom.style.top = `${t + styT}px`
}
document.onmouseup = function(e) {
document.onmousemove = null
document.onmouseup = null
}
}
}
})
dialog中增加该属性,就可以实现啦。
基于上面的自定义拖拽方法,画了个简图以便理解(top同理):
10.router.beforeEach
结合addRouters
实现根据用户权限控制路由(导航栏)
先来简单介绍下router.beforeEach
导航守卫
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
每个守卫方法接收三个参数:
-
to: Route
: 即将要进入的目标 -
from: Route
: 当前导航正要离开的路由 -
next: Function
: 一定要调用该方法来resolve这个钩子。执行效果依赖next
方法的调用参数。-
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是confirmed(确认的)。 -
next(false)
: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from
路由对应的地址。 -
next('/')
或者next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next
传递任意位置对象,且允许设置诸如replace: true
、name: 'home'
之类的选项以及任何用在router-link的toprop中的选项。 -
next(error)
: (2.4.0+) 如果传入next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()注册过的回调。
-
确保要调用next
方法,否则钩子就不会被 resolved。
好吧 我摊牌了 我是从官网复制来的,想看更多欢迎去官网:https://router.vuejs.org/zh/g...
接下来我们来看看具体如何实现:
定义路由的文件中分成几个数组
图中constantRoutes
为所有用户都可以访问的路由,adminRoutes
为用户名为‘admin’登录才可以访问的路由。
先赋值当前可以访问的路由:
const router = new Router({
routes: constantRoutes,
});
export default router;
登录时,在session里存入用户名,用来判断是否已登录及用户名
login:function(){
let me=this;
me.$refs.ruleForm.validate((valid) => {
if (valid) {
sessionStorage.setItem('user',me.loginForm.user);
if(sessionStorage.getItem('user')){
me.$router.push({path:"/index"})
}
}
})
}
main.js中控制路由
let flag=false;//此字段用来防止刷新时重复添加路由
router.beforeEach((to, from, next) => {
NProgress.start()
let user=sessionStorage.getItem('user');
if(to.path=='/login'){//用来防止一直跳入login,进入死循环
next();
}
//判断是否登录了,当然真实项目判断权限不会这么简单,此案例只提供思路及基本使用
if(user){
if(to.path=='/login'){
next('/');//登录后在想跳入login时直接跳入首页
}
if(flag){
next();
}
else {
let routes=[];
if(user=='admin'){//判断为管理员
routes=adminRoutes;
router.addRoutes(routes);//添加管理员的路由信息
router.options.routes = router.options.routes.concat(routes);
//由于addRoutes只会注册路由表,并没有更新router.options.routes的数据
}
flag=true;
next({...to, replace: true});
}
}
else {
if(to.path!='/login'){
next('/login');
}
NProgress.done()
}
})
成果:当没有登陆时会强制跳转至登录页,登录后用户名为admin
时展示:
当不为admin时:
11.密码的显示隐藏
//通过控制type属性实现控制密码的展示隐藏
<el-form-item label="" prop="password">
<el-input placeholder="请输入密码" v-model="loginForm.password" :type="passwordType" auto-complete="new-password">
<i slot="prefix" class="iconfont iconmima"></i>
<i slot="suffix" class="iconfont iconbiyan pointer" @click='passwordType=""' v-if='passwordType=="password"'></i>
<i slot="suffix" class="iconfont iconeye pointer" @click='passwordType="password"' v-else></i>
</el-input>
</el-form-item>
实现效果:
12.登出功能
使用element的el-dropdown
<el-dropdown class='avaImg' trigger="click">
//trigger 设置下拉框展示触发方式,默认为触摸展示
<span class="el-dropdown-link">
<img src="../assets/img.png" alt="">
<div>
<i class="iconfont iconxiala" style='padding:0 5px;font-size:15px;'></i>
</div>
</span>
<el-dropdown-menu slot="dropdown" >
<el-dropdown-item>
<span @click='logOut'>登出</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
登出方法:
logOut:function(){
let me=this;
this.$confirm('确认要登出吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
sessionStorage.setItem('user','');
me.$router.push('/login');
window.location.reload();//更新main.js的flag值,重新根据角色获取路由
}).catch(() => {
});
}
实现效果:
13.结合breadcrumb
实现展示面包屑
<transition mode="out-in">
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/index' }">首页</el-breadcrumb-item>
<el-breadcrumb-item v-for='item in breadcrumb' :key='item.name'>{{item.name}}</el-breadcrumb-item>
</el-breadcrumb>
</transition>
监听路由变化实时更新(进入界面也要初始化,方法同):
watch: {
$route(route) {
let match=route.matched;
match=match.filter(item => item.name&&item.name!='首页' );
this.breadcrumb=match;
}
}
效果图:
14.结合clipboard
实现文本复制
实现步骤:
安装clipboard
npm install clipboard --save
初始化
import Clipboard from 'clipboard'
var clipboard = new Clipboard('.btn');
<el-input id="foo" placeholder="请输入内容" v-model="ipt">
<el-tooltip class="item" effect="dark" content="点我复制哦" placement="top" slot="append">
<el-button class="btn" data-clipboard-target="#foo">
<i class='iconfont iconfuzhi'></i>
</el-button>
</el-tooltip>
</el-input>
定义回调函数
clipboard.on('success', function(e) {
me.$message({
message: '复制成功',
type: 'success'
});
e.clearSelection();
});
clipboard.on('error', function(e) {
me.$message({
message: '复制失败',
type: 'success'
});
});
实现效果:
详细请看:http://www.clipboardjs.cn/
源码地址:https://github.com/myweiwei/vue-
将不断更新完善,期待您的批评指正!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。