切换路由时重新渲染页面
我创建和编辑的页面使用的是同一个component,默认情况下当这两个页面切换时并不会触发vue的created或者mounted钩子,官方说你可以通过watch $route的变化来做处理,但其实说真的还是蛮麻烦的。后来发现其实可以简单的在 router-view上加上一个唯一的key,来保证路由切换时都会重新渲染触发钩子了。这样简单的多了。
<router-view :key="key"></router-view>
computed: {
key() {
return this.$route.name !== undefined? this.$route.name + +new Date(): this.$route + +new Date()
}
}
登录权限验证思路
不同的权限对应着不同的路由,同时侧边栏也需根据不同的权限,异步生成。这里先简单说一下,我实现登录和权限验证的思路。
- 登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。
- 权限验证:通过token获取用户对应的 role,动态根据用户的 role 算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。
上述所有的数据和操作都是通过vuex全局管理控制的。(补充说明:刷新页面后 vuex的内容也会丢失,所以需要重复上述的那些操作)接下来,我们一起手摸手一步一步实现这个系统。
- 创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。
- 当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。
- 调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
- 使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
// main.js
router.beforeEach((to, from, next) => {
if (store.getters.token) { // 判断是否有token
if (to.path === '/login') {
next({ path: '/' });
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(res => { // 拉取info
const roles = res.data.role;
store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
}).catch(err => {
console.log(err);
});
} else {
next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next();
} else {
next('/login'); // 否则全部重定向到登录页
}
}
});
作者:花裤衩
链接:https://juejin.im/post/6844903478880370701
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Element Table 数据更新操作
//添加数据
this.list.unshift(this.temp);
//删除数据
const index = this.list.indexOf(row); //找到要删除数据在list中的位置
this.list.splice(index, 1); //通过splice 删除数据
//修改数据
const index = this.list.indexOf(row); //找到修改的数据在list中的位置
this.list.splice(index, 1,this.updatedData); //通过splice 替换数据 触发视图更新
重新指向一个新的引用
我们在dialog里面改变状态的时候,遮罩下面的table里面该行的状态也在那里跟着一只变化着。原因想必大家都猜到了。赋值的数据是一个objec引用类型共享一个内存区域的。所以我们就不能直接连等复制,需要重新指向一个新的引用,方案如下:
//赋值对象是一个obj
this.objData=Object.assign({}, row) //这样就不会共用同一个对象
//数组我们也有一个巧妙的防范
newArray = oldArray.slice(); //slice会clone返回一个新数组
新建和编辑通过meta数据区分
computed: {
isEdit() {
return this.$route.meta.isEdit // 根据meta判断
// return this.$route.path.indexOf('edit') !== -1 // 根据路由判断
}
},
created() {
if (this.isEdit) {
this.fetchData();
}
},
在不刷新页面的情况下,更新页面
// 先注册一个名为 `redirect` 的路由
<script>
export default {
beforeCreate() {
const { params, query } = this.$route
const { path } = params
this.$router.replace({ path: '/' + path, query })
},
render: function(h) {
return h() // avoid warning message
}
}
</script>
// 手动重定向页面到 '/redirect' 页面
const { fullPath } = this.$route
this.$router.replace({
path: '/redirect' + fullPath
})
Vue 命名规范
所有的Component文件都是以大写开头 (PascalCase),这也是官方所 推荐的。
但除了 index.vue。
所有的.js文件都遵循横线连接 (kebab-case)。
例子:
@/src/utils/open-window.js
@/src/views/svg-icons/require-icons.js
@/src/components/MarkdownEditor/default-options.js
Views
在views文件下,代表路由的.vue文件都使用横线连接 (kebab-case),代表路由的文件夹也是使用同样的规则。
例子:
@/src/views/svg-icons/index.vue
@/src/views/svg-icons/require-icons.js
使用横线连接 (kebab-case)来命名views主要是出于以下几个考虑。
- 横线连接 (kebab-case) 也是官方推荐的命名规范之一 文档
- views下的.vue文件代表的是一个路由,所以它需要和component进行区分(component 都是大写开头)
- 页面的url 也都是横线连接的,比如https://www.xxx.admin/export-excel,所以路由对应的view应该要保持统一
- 没有大小写敏感问题
// good
watch: {
searchText: {
handler: 'fetchUserList',
immediate: true,
}
}
减少全局操作
我们现在虽然用 vue 写代码了,核心思想转变为用数据驱动 view,不用像jQuery时代那样,频繁的操作 DOM 节点。但还是免不了有些场景还是要操作 DOM 的。我们在组件内选择节点的时候一定要切记避免使用 document.querySelector()等一系列的全局选择器。你应该使用this.
e
l
或
者
t
h
i
s
.
r
e
f
s
.
x
x
x
.
el或者this.refs.xxx.
el或者this.refs.xxx.el的方式来选择 DOM。这样就能将你的操作局限在当前的组件内,能避免很多问题。
我们经常会不可避免的需要注册一些全局性的事件,比如监听页面窗口的变化window.addEventListener(‘resize’, this.__resizeHandler),但再声明了之后一定要在 beforeDestroy或者destroyed生命周期注销它。window.removeEventListener(‘resize’, this.__resizeHandler)避免造成不必要的消耗。
避免过多的全局状态,不是所有的状态都需要存在 vuex 中的,应该根据业务进行合理的进行取舍。如果不可避免有很多的值需要存在 vuex 中,建议使用动态注册的方式。相关文档。只是部分业务需要的状态处理,建议使用 Event Bus或者使用 简单的 store 模式。
css 也应该尽量避免写太多的全局性的样式。除了一些全局公用的样式外,所以针对业务的或者组件的样式都应该使用命名空间的方式或者直接使用 vue-loader 提供的 scoped写法,避免一些全局冲突。
我们其实可以基于 webpack 的require.context来实现自动加载组件并注册的全局的功能。相关原理在之前的文章中已经阐述过了。具体代码如下
我们可以创建一个GlobalComponents文件夹,将你想要注册到全局的组件都放在这个文件夹里,在index.js里面放上如上代码。之后只要在入口文件main.js中引入即可。
//main.js
import './components/Table/index' // 自动注册全局业务组件
// 这样我们可以在模板中直接使用这些全局组建了。不需要再繁琐的手动引入了。
<template>
<div>
<user-select/>
<status-button/>
</div>
</template>
当然你也不要为了省事,啥组件都往全局注册,这样会让你初始化页面的时候你的初始init bundle很大。你应该就注册那些你经常使用且体积不大的组件。那些体积大的组件,如编辑器或者图表组件还是按需加载比较合理。而且你最好声明这些全局组件的时候有一个统一的命名规范比如:globel-user-select这样的,指定一个团队规范,不然人家看到你这个全局组件会一脸懵逼,这个组件是哪来的。
作者:花裤衩
链接:https://juejin.im/post/6844903840626507784
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。