FE-工程与实践部分
-
表单和表格
表格 增、删、改 后需要对数据进行更新
表单 增改使用同一表单的 注意初始化表单,注意参数值和表单组件值之间的转换 -
页面选择项的初始化和持久化
初始化采用vue组件中的data选项来设置,持久化使用vuex+vuex-persistence(cookie,sessionStorage,localStorage) -
异步路由,参考vue-element-admin
掘金-Panjiachen(花裤cha)-手摸手,带你用vue撸后台 系列二(登录权限篇)- 在
router/index.js中存放着静态路由数据 (constantRouteMap) ,并通过它初始化路由表router,关键代码
const createRouter = () => new Router({ // mode: 'history', // require service support scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) const router = createRouter() export function resetRouter() { const newRouter = createRouter() router.matcher = newRouter.matcher // reset router } export default router- 在
store/module/permission.js中请求(dispatch)着路由(异步),在请求完成后在Mutation中SET_ROUTERS,新增的异步路由数据存放到state.permission.addRouters, 静态路由concat异步路由后的数据存放到state.permission.routers。 - 在
permission.js(由main.js加载),通过router守卫router.beforeEach触发过程2,在过程2完成后将过程1中的router进行router.addRoutes操作得到最终路由表 - 在
store/module/user.js用户身份切换后通过resetRouter清除注册的路由,vue-router本身是没有removeRoutes方法的 这个hack参考 手摸手,带你用vue撸后台 系列五(v4.0新版本)-addRoutes && removeRoutes - 在
layout/components/Sidebar/index.vue中利用state.permission.routers路由数据生成左侧菜单
- 在
-
路由与菜单的合并
通过添加route一个属性hidden,决定是否将路由item列入到菜单,并在meta中存入menu数组和menuitem的一些属性数据
参考 手摸手,带你用 vue 撸后台 系列四 (vueAdmin 一个极简的后台基础模板)-导航 -
国际化
主要代码Vue.use(VueI18n) const i18n = new VueI18n({ locale: 'zh', messages })参考panjiachen.github.io/vue-element…
代码见 github.com/vue-element…
Vue18n API 见 kazupon.github.io/vue-i18n/zh… -
自动导入自定义Svg图标,使用Webpack的require.context打包svg依赖,参考vue-element-admin
掘金-Panjiachen(花裤cha)-手摸手,带你优雅的使用 icon-自动导入 -
scoped样式穿透
博客园-=.=(blogs-xlf)-如何解决vue项目中 scss 不支持 scoped 的 /deep/ 穿透写法
* { /deep/ { @import "@/path/to/style.scss" } }
* {
::v-deep {
.subVDomClass {
//...
}
}
}
-
Element-UI自定义样式,通过scss自定义组件样式,有如下几种方式
- 我的做法, 将node_modules/element-ui/packages/theme-chalk/src/common/var.scss内容复制到工程目录@/assets/scss/var-theme-dark.scss中,按照实际需要修改变量值,然后再建立一个scss如下:
.theme-dark { @import "var-theme-dark"; //方式一,更改变量值 @import "element-ui/packages/theme-chalk/src/table";//按需引用 @import "element-ui/packages/theme-chalk/src/mixins/mixins"; @include b(table) { tr { background-color: $--custom-background-color ;//方式二 覆盖样式 $--color-white改为自定义背景色, input[type="checkbox"] { margin: 0; } } } }- 第二种做法,先引入变量文件,再手动引入组件scss样式
dev.to-Tim Bendt-Overriding the Default Theme in Element UI with SCSS - 第三种做法,使用ChavesGu开发的babel-plugin-component-scss插件
Chaves Gu-babel-plugin-component按需加载组件及自定义主题对应的scss样式
-
茴字的四种写法-关于指令式和服务式(函数/方法式),loading组件的两种用法
Github.io-Alfxjx-从ElementUI的loading组件说起 -
Vuex的使用,什么数据才应该放store?
正方segmentfault-vilien-flux架构浅谈:什么数据才应该放store
反方csdn-陈铭-机器学习-redux的所有state都需要放到store里吗?
讨论知乎-redux中所有state都要放在store里吗? -
控制事件频率-防抖与节流
Github.io-Alfxjx-函数防抖与函数节流
FE-算法部分
- 不含Array对象的深拷贝objectDeepClone,无递归,含数组的对象其数组类型会发生变化,若要保持数组类型不变见deepClone
function objectDeepClone(json) {
var result = Array.isArray(json) ? [] : {}
//原始数据栈
var stack = [json];
//目标数据栈
var mirrorStack = [result];
while (stack.length > 0) {
// // 深度优先 数据出栈
// var item = stack.pop();
// var targetItem = mirrorStack.pop();
// 广度优先
var item = stack.shift();
var targetItem = mirrorStack.shift();
for (var key in item) {
var val = item[key]
if (typeof val !== 'object') {
//然后一个个的引用对象的值修变成基本数据类型
targetItem[key] = val;
} else {
//数据入栈
stack.push(val);
// console.log(key,targetItem)
targetItem[key] = Array.isArray(val) ? [] : {};
//先建立引用对象
mirrorStack.push(targetItem[key]);
}
}
}
return result;
}
function deepClone(obj) {
function clone(node) { let result ={};
for (var prop in node){
if (node[prop] instanceof Object) {
result[prop] = deepClone(node[prop]);
} else {
result[prop] = node[prop];
}
}
return result;
}
if( Array.isArray(obj)){
return obj.map(v=> deepClone(v))
} else if( obj instanceof Object ){
return clone(obj)
} else{
return obj
}
}
- 遍历树-需求:处理组织结构数据中组织的一些属性,如删除空组织,更改组织中的属性键名 。以下实现为非递归、原始数据有损(直接操作)方式
function walkTree(json) {
//原始数据栈
var stack=[json]
while(stack.length>0) {
//数据出栈
var item = stack.pop();
//console.log(JSON.stringify(item))
var children = item.children;
if(children!=null){
//do sth...
for (let child of children)
//数据入栈
stack.push(child);
}
else{
//do sth...
}
}
}
//递归无损方式
const process= function (node) {
let result = {}
result.title = node.orgName
result.id = node.id
result.pid = node.pid
result.expanded = true
if(node.children!=null&&node.children.length>0){
result.children = node.children.map(item=> process(item))
}
return result
}
- 扁平化JSON
function flatten(json) {
let result={}
//原始数据栈
var stack=[json]
while(stack.length>0) {
//数据出栈
var item = stack.pop();
for(let k of Object.keys(item)){
let sub=item[k]
if(typeof sub=="object" && !Array.isArray(sub)){
let tempObj={}
for(let subk of Object.keys(sub)){
tempObj[k+'.'+subk]=sub[subk]
//数据入栈
stack.push(tempObj);
}
}else{
result[k] = sub
}
}
}
return result
}
//flatten({a:{b:{c:1},a:{b:11},c:[1,2]},b:{c:3},c:3}) -> {"c":3,"b.c":3,"a.c":[1,2],"a.a.b":11,"a.b.c":1}
参考