[TOC]
## 前言
继续总结vue项目实践中的优化和思考
## 实践问题
### 批量对象属性赋值
使用场景:主要是针对需要把对象的一些属性批量的赋值到另外一个对象上,然后如果你的属性很多可能要写很多赋值语句。(前提是属性名一般是相同的)
> 说明:可能有人会问为什么不直接用这个对象,答案也很简单,如果可以直接用,当然直接用是最好的,我自己在写接口param的时候,就会注意这些,需要传参的部分封装到一个特殊的对象里,然后进行data的绑定,这样需要的时候直接用传参对象。但这里讨论的不是这种情况。
```
//优化前
let data = {}
data.name = this.form.name
data.len = this.form.len
data.amount = this.form.amount
//优化版本一 :利用对象的解构
let {name,len,amount} = this.form 
//利用对象解构还可以支持属性名变更的情况
let {name,len:length,amount:money} = this.form
let data = {name,length,money}
//优化版本二 :可以支持批量的导入需要赋值的,对于拷贝对象,用source属性承接,而需要赋值的属性用propArr承接
//在方法中用json的相关方法支持了简单的对象深拷贝
// 批量加载对象属性,支持传入数组[{source:sourceObj,propArr:[]}]  
setProps(arr) {
    if (arr.length <= 0) return {}
    return arr.reduce((acc, item) => {
         item.propArr.reduce((acc, prop) => {
          if (typeof item.source[prop] === 'object') {
            acc[prop] = JSON.parse(JSON.stringify(item.source[prop]))
         } else {
                acc[prop] = item.source[prop]
                }
            return acc
            }, acc)
        return acc
    }, {})
}
```
**拓展思考**:像这种代码如果你爹vue代码里经常写,不妨在你的mixins中混入这个方法,可以为你的页面节省大量的代码空间。
### 批量变量重置
在我们的代码中经常会遇到吧一些变量进行重置,这部分代码重复率很高又没有技术含量,所以我写一个工具方法进行简单的支持,代码优化。
```
//优化前
this.search = false 
this.data = []
this.cur_page = 1
this.pageNo = 1
this.totalCount = 0
this.processType = ''
this.person = ''
this.keyword = ''
this.taskStatus = ''
this.stdate = []
this.processStatus = ''
 /**
      * @author zhangbing 
      * @param [] arr 需要重置的数组变量
      * @param {*} options 配置对象 对于这里的重置规则如果不符合需求的可以自定义option字典,然后用instanceof 判断类型(todo)
      */   
    resetVars(arr, options) { 
        if (!arr || arr.length === 0) return 
        let _options = {
            object: {},
            string: '',
            number: 0,
            boolean: true,
            null: null,
            undefined: undefined
        }
        _options = options ? Object.assign({}, _options, options) : _options
        return arr.map(item => { 
            if (_options.includes(typeof item)) {
                item = _options[typeof item]
            } else { 
                // 不存在重置类型的 重置为字符串
                item = ''
            }
            return item
        })
    }
```
**拓展思考**:像这种代码如果你爹vue代码里经常写,不妨在你的mixins中混入这个方法,可以为你的页面节省大量的代码空间。
### 骨架屏的相关连接
- [骨架屏](https://juejin.im/post/5b79a2786fb9a01a18267362)
### axios配置的拦截
- [axios模块介绍](https://npm.taobao.org/package/axios)
模块的过多介绍这里就不讲了,这里说明的是一个非http 200状态码的错误解析,一般情况下我们会针对response部分做异常解析。
```
// 配置返回拦截器
_axios.interceptors.response.use(function (response) {
  return response
}, function (error) {
  if (error.response) {
    console.warn(error.response)
    return Promise.reject(error.response)
  } else {
    return Promise.reject(error)
  }
 
})
```
那么这里就会有一个问题,首先报错中的error是不能直接打印的,如果你写会报错如下:
```
Request failed with status code 404
    at createError (createError.js?8da8:16)
    at settle (settle.js?664b:18)
    at XMLHttpRequest.handleLoad (xhr.js?ddba:77)
```
然后针对response存在的情况下,因为这部分的处理是一样的,返回也都在catch里解决的,所以我个人建议直接把错误的提示在这里解决掉,比如通过console.warn的方式或者ui的message.error的方式,这样节省了业务方面的处理错误代码。
但如果你一定希望在接口调用位置处理这部分非http 200的错误,要知道这部分是在catch,error中的,并不是在then中的作用域内。
```
api.xxx().then(res=> {
//http 200 处理代码
}).catch(error=> {
//非 200处理代码
})
```
### vue元素标签带空格部分使用loader配置去掉
有些时候我们在写模板时不想让元素和元素之间有空格,可能会写成这样:
```
<ul>
  <li>1111</li><li>2222</li><li>333</li>
</ul>
```
当然还有其他方式,比如设置字体的font-size: 0,然后给需要的内容单独设置字体大小,目的是为了去掉元素间的空格。其实我们完全可以通过配置 vue-loader 实现这一需求。
```
{
  vue: {
    preserveWhitespace: false
  }
}
```
它的作用是阻止元素间生成空白内容,在 Vue 模板编译后使用 _v(" ") 表示。如果项目中模板内容多的话,它们还是会占用一些文件体积的。例如 Element 配置该属性后,未压缩情况下文件体积减少了近 30Kb。
 
### vue-cli 脚手架之后待办事项
- 默认情况下没有样式预处理器的loader ,我用的scss,不加会报错,所以需要
```
npm i sass-loader node-sass --save-dev
```
- 默认况下,没有页面文件夹,在src目录下新加pages文件夹
- 默认情况下,没有全局的services、filter全局文件,可以分别用来是存放axios请求服务,过滤器的
- 默认情况下assets目录下没有分样式,脚本,图片的文件夹,需要加的
- 默认情况下,路由部分只有index,没有路由守卫,路由子模块,建议分别加入,当然我还有另外的import懒加载方法,filter路由配置文件要加
- 默认的@符号没有联想提示路径,需要加jsconfig.json
```
{
    "compilerOptions": {
      "target": "es2017",
      "allowSyntheticDefaultImports": false,
      "baseUrl": "./",
      "paths": {
        "@/*": ["src/*"],
      }
    },
    "exclude": ["node_modules", "dist"],
    "include": ["src"]
  }
```
- 默认的axios没有我们需要的业务网关配置和请求拦截
 - 默认的mixins,你一定有很多工具方法和数据需要全局配置使用
- 默认情况下,没有业务枚举数据,建议新加一个枚举文件夹,用来存放各个业务的枚举数据
- 默认情况下,api服务没有mock设置和请求,可以根据自己需求设置
其中baseUrl需要设置为自己的域名地址,可以根据process.node.env控制,可以根据域名判断。其中axios需要加必要的请求前后的拦截配置,其中用户id的部分在必要的时候需要加入。
```
const transformRequest = (data = {}, headers) => {
  if (typeof data === 'string') return data
  const loginId = getUid()
  return JSON.stringify({...data, loginId})
}
let _axios = axios.create({
  baseURL: apiProxyUrl,
  headers: { 'Content-Type': 'application/json' },
  transformRequest: [transformRequest],
  timeout: 10000
})
// 配置返回拦截器
_axios.interceptors.response.use(function (response) {
  return response
}, function (error) {
  if (error.response) {
    console.warn(error.response)
    return Promise.reject(error.response)
  } else {
    return Promise.reject(error)
  }
})
```
- 默认的app跟组件可能没有设置data为返回函数 ,返回对象
### vue-router 路由死循环
下面这个报错是因为路由进入了死循环,需要纠正查看下路由的守卫部分有没有循环,以及设置的拦截、非拦截路径是否正确。
```
[vue-router] uncaught error during route navigation:
<failed to convert exception to string>
```
### data属性没有设置为函数并返回对象的报错
显性的返回对象就可以了
```
[Vue warn]: data functions should return an object:
```
### eslint配置自动验证和自动修复
> 前提:配置了eslint插件并且开启了eslint对文件的格式验证。
默认加了很多eslint规则之后,项目运行就会报错,但实际上肯定是期望软件帮我们自动修正,那么其设置的方法是什么呢?分为两部分,一部分是软件的设置,一部分插件的设置,这里以mac --vscode为例,说明下如何设置自动纠正:
> 1、window电脑:
> 文件 > 首选项 > 设置 打开 VSCode 配置文件
> 2、mac电脑
> code>首选项 >设置
```
"eslint.autoFixOnSave": true,
"eslint.validate": [
    "javascript",{
        "language": "vue",
        "autoFix": true
    },"html",
    "vue"
],
```
备注:如果你不想在项目中使用eslint,其在config/index.js,dev配置中,useEslint: true ,设置为false即可。
### vue路由拦截实现保存用户信息
场景:为了防止用户突然离开,没有保存已输入的信息。
```
 //在路由组件中:mounted(){},
  beforeRouteLeave (to, from, next) {
      if(用户已经输入信息){
        //出现弹窗提醒保存草稿,或者自动后台为其保存
      }else{
        next(true);//用户离开
      }
  }
```
                    
        - 前端工程化
 - 架构总纲
 - 001
 - 美团技术架构
 - 前端工程化说明
 - 历史背景说明
 - 架构说明
 - 前端工程化技术栈
 - 技术文档说明
 - 功能模块说明
 - 前端模块管理器简介
 - 框架对比分析
 - vue&react&ng对比分析(一)
 - vue&react&ng对比分析(二)
 - vue&react&ng对比分析(三)
 - 工程化专题系列
 - 需要解决的问题
 - 001
 - 002
 - 003
 - 常见代码错误
 - jslint中常见的错误
 - css规范常见错误
 - html规范常见错误
 - 工程化目录
 - 工程化初始化
 - 项目构建流程
 - 项目打包优化
 - 上线与迭代注意事项
 - 前端部署发布
 - jetkins部署
 - 部署需求整理
 - 前端监控
 - 工程化实践指南
 - dock持续部署
 - 系列文章
 - 插拔式前端的设计
 - 其他实践
 - 工程化的前端管理
 - 宋小菜借鉴
 - 大前端团队介绍
 - 人员组成
 - 人员发展
 - 研发流程
 - 任务分类
 - 前端基础建设与架构
 - 技术栈以及技术方案
 - 业务目录大纲
 - 前端大纲
 - api管理
 - 后端api工具
 - 前端easymock
 - api拦截与代理
 - api优化
 - api请求时长策略设计
 - 前端架构专题
 - 架构专题一
 - 产品原型对接
 - 与ui对接
 - 图片专题
 - 图片工程化大纲
 - 图片优化
 - 图标字体
 - 图标字体vs雪碧图
 - 工程化的前端矩阵
 - 蚂蚁金服前端矩阵分享
 - BFF架构
 - 概念解析
 - 前端脚手架
 - 初始化项目
 - 个性化配置
 - 部署与发布
 - 性能优化专题
 - http专题
 - https常识
 - http优化1
 - http优化2
 - http优化3
 - http缓存
 - 常规web性能优化攻略
 - 性能优化大纲
 - 样式优化
 - js优化
 - 第三方依赖优化
 - 代码分割优化
 - 图片优化
 - 打包优化
 - 服务器优化
 - 缓存优化
 - 交互优化
 - pc事件优化
 - 手机事件优化
 - 推荐文章
 - 01
 - 前端安全专题
 - 前端安全大纲
 - 前端第三方库
 - seo优化
 - web框架的对比
 - 001
 - 学习资源
 - 珠峰前端架构
 - npm教程
 - npm入门
 - cnpm入门
 - cnpm搭建
 - 你该知道的js模块
 - browserSync
 - opn
 - js-cookie
 - npm-script进阶
 - 入门篇
 - 进阶篇
 - 高阶篇
 - 实践篇
 - yarn入门
 - nodejs教程
 - axios&&fetch
 - xhr
 - axios
 - fetch
 - babel专题
 - babel入门
 - profill入门
 - nodejs入门
 - 快速入门
 - 大纲介绍
 - node基础
 - global obj
 - assert断言
 - procss-进程
 - child_process子进程
 - cluster集群
 - console控制台
 - crypto-加密
 - dgram-数据报
 - dns-域名服务器
 - error-异常
 - events-事件
 - global-全局变量
 - http-基本协议
 - https-安全协议
 - modules-模块
 - os-操作系统
 - path-路径
 - querystring-查询字符串
 - readline-逐行读取
 - fs-文件系统
 - net-网络操作
 - 命令行工具
 - 内存泄露
 - 代码的组织与部署
 - 异步编程
 - orm模块
 - 异步编程解决方案
 - node-lessons
 - 环境准备
 - nodejs实践
 - 项目搭建
 - 异步优化
 - 创建web和tcp服务器
 - 终端问答程序
 - 爬虫系统
 - mongleDb
 - mongoDB简介
 - 基本使用
 - 实用技巧
 - 汇总001
 - 饿了么后台搭建
 - nodejs干货
 - 沪江基于node的实践
 - 苏宁基于nodejs优化
 - 基于nodejs开发脚手架
 - 书籍干货
 - 深入浅出nodejs
 - 异步I/O(一)
 - gulp教程
 - gulp入门
 - gulp常用插件(1)
 - gulp常用插件(2)
 - gulp创建目录
 - 经验普及贴
 - webpack教程
 - webpack入门
 - 简单入门
 - entry配置
 - output配置
 - 插件使用01
 - 插件使用02
 - loader使用
 - dev-server介绍
 - 构建css
 - css模块化
 - 使用less和sass
 - 构建图片
 - 引入字体
 - babel配置攻略
 - eslint
 - 001
 - webpack进阶
 - 分不同文件检出
 - 优化打包大小
 - 优化打包速度
 - 自定义配置
 - 单页以及多页如何配置
 - 优化实践
 - 文章导读
 - 001
 - 优化指南
 - 参考列表
 - webpack4
 - 多入口程序构建
 - 参考教程
 - 项目实践
 - 环境区分
 - 常见问题
 - 解读webpack
 - 从vuejs权威指南中解决
 - 深入浅出webpack
 - rollup
 - 入门
 - parcel
 - 入门篇
 - express教程
 - nuxt教程
 - 入门
 - 基本入门
 - koa教程
 - koa基本入门
 - koa开发注意事项
 - koa实践指南
 - 关于路由
 - koa优化指南
 - 001
 - Vuejs
 - vuejs入门系列
 - vue-cli入门
 - vue2基本认识
 - vuejs入门教程
 - 样式绑定
 - vuex入门学习笔记
 - vue组件生命周期
 - 组件的使用
 - vue-router入门
 - vue-filter
 - 计算属性使用
 - 开发注意事项
 - mixins
 - 组件通讯
 - vuejs进阶
 - 进阶资源
 - router进阶
 - 官网介绍
 - 前进与后退优化
 - keep-alive基本使用
 - keep-alive原理详解
 - 钩子函数进阶
 - 计算属性&监听&方法
 - vue服务端渲染技术
 - 项目实践之路
 - 实践大纲
 - 插槽专题篇
 - vue-cli升级
 - 进阶入门
 - vuejs架构
 - nuxt
 - vuejs项目实践
 - vue实践常见问题
 - 001
 - 002
 - 003
 - 004
 - 005
 - 改造api参数探索
 - 007
 - 008
 - 009
 - 010
 - 项目技术栈
 - vue性能问题以及优化方案
 - vue-spa应用的理解
 - vue-ssr的部署与使用
 - 滴滴出行实践案例
 - 2.0重构
 - vue-element-admin实践
 - 准备工作
 - 菜单设计
 - 权限设计
 - 依赖模块
 - vue-betterScroll
 - 性能优化懒加载
 - 京东组件实践
 - vue2项目小结
 - vue探索与实践
 - 去哪实践
 - 介绍
 - 饿了么项目实践
 - 项目解析
 - vue骨架屏实践
 - vue生态推荐
 - ui框架
 - elementUI
 - 001
 - 002
 - VUE-material
 - vant-ui
 - 解读入门
 - iview
 - 使用问题汇总
 - vux
 - mint-ui
 - loadmore
 - vue资源导航
 - vueconf
 - 源码解读
 - vm
 - 双向绑定
 - 基本原理
 - 数组双向绑定
 - 报错机制
 - 封装方法
 - 运行环境
 - 入门
 - 指令
 - vue-router解读
 - util
 - vue-props
 - 流程逻辑
 - 推荐文章
 - 源码解读
 - 文章导读
 - 001
 - vuejs实战
 - 基础篇
 - 进阶篇
 - 实践篇
 - 面试专题
 - angularjs教程
 - angularjs入门系列
 - 基本入门
 - ng2入门
 - ng进阶
 - ng项目实践
 - 源码解读
 - typescript
 - reactjs教程
 - reactjs入门系列
 - react的基本入门
 - react组件
 - virtalDom认识
 - react-cli入门
 - react组件的生命周期
 - 基本知识点
 - react-router教程
 - react进阶
 - 基本实践
 - react加载性能优化指南
 - react属性封装
 - 进阶45讲
 - 01概述
 - 02jsx
 - 06高阶组件&函数子组件
 - contextApi
 - react-router
 - 入门章节
 - 进阶
 - 高阶组件
 - react进阶组件
 - 基本介绍
 - render props
 - render props的封装
 - render props getter
 - react-native入门
 - 源码解读
 - 001
 - 002-reactDemo
 - 参考教程
 - 参考教程1
 - 了解react-hooks
 - ui框架
 - pc端ui框架推荐
 - 项目实践
 - weatherApp
 - 001
 - 002
 - 不同生命周期使用场景
 - react项目结构和组件的命名
 - 常见问题解答
 - 参考书籍
 - react全栈
 - 前言
 - react与redux进阶
 - 常见误解
 - 反模式
 - react设计模式与最佳实践
 - 7美化组件
 - 7.2行内样式
 - 7.4css模块
 - 深入react技术栈
 - react学习手册
 - 序
 - mobx教程
 - 入门
 - 大佬推荐
 - 001
 - react面试
 - 001
 - linux教程
 - linux入门
 - 基本入门
 - 文件管理
 - 文件传输
 - 文档编辑
 - 磁盘管理
 - 磁盘维护
 - 网络通讯
 - 系统管理
 - 系统设置
 - 备份压缩
 - 设备管理
 - 查看系统信息
 - linux其他
 - webhook
 - rsync入门教程
 - ssh免登陆设置
 - 安装nodejs
 - nginx教程
 - 入门教程
 - 安装
 - 基本配置
 - 服务基本使用
 - 高性能nginx
 - 001
 - pm2教程
 - shell教程
 - 入门大纲
 - echo命令
 - 参考文献
 - linux常用命令2
 - linux常见问题
 - 001
 - python
 - 入门教程
 - 机器学习
 - 准备工作
 - 服务器常识
 - tomcat
 - 入门常识
 - iis
 - redis教程
 - 入门第一篇
 - redis进阶
 - 项目实践
 - redis使用问题
 - mongleDB
 - 入门
 - 使用进阶
 - 项目实践
 - 常见问题
 - electron
 - 入门系列
 - 前言
 - 小程序
 - 入门
 - 准备工作
 - 路由
 - 参考文档
 - 001
 - 小程序开发--双路视频调研
 - 准备工作
 - 参考资源
 - 参考网址
 - docker
 - 入门
 - 基本认识
 - 安装与使用
 - docker安装nginx
 - docker安装jetkins(1)
 - docker部署jenkins(2)
 - 进阶
 - 实践总结
 - docker群分享
 - docker部署前端应用
 - 文章导读
 - docker其他
 - 网络安全
 - 入门
 - 大纲
 - 项目解析
 - schoolpal.web
 - 功能模块大纲
 - 目录结构大纲
 - 前端国际化
 - 国际化方案
 - 其他
 - bower入门教程
 - weex
 - 入门
 - memcached
 - 入门
 - sails
 - 入门
 
