[TOC]
### 前言
本篇主要介绍模块中的常见的报错,希望列举不正确的以及不完善的大家帮忙提出。
### npm run dev报错找不到localhost:
报错 如下 :原因是因为localhost解析不到对应的ip
~~~
Error: getaddrinfo ENOTFOUND localhost
at errnoException (dns.js:50:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26)
~~~
解决方式 :找到根目录 /etc/hosts,它是计算机进行域名解析服务的一个本地映射,写入如下的解析,就可以完美的解决这个问题。
`127.0.0.1 localhost`
提示:如果你需要定制很多host,可以下载一个switchHosts的软件,可以切换不同测试环境下添加不同的域名解析机制。如果你是shell面板,可以cd 切换到/etc,然后mac利用 vi或者win利用vm修改这个文本文件(需要管理员权限进行修改)。
### 关于异步获取数据时渲染报错
**问题场景**:一般情况下,页面需要用的数据项是data中会定义一份,然后大部分数据肯定是接口异步获取的,在组件模板编码中,一般都习惯于直接基于已有数据正确的情况下去实现,在初始数据为空渲染空对象属性的属性下就会报错(直接空属性不会报错哦)。
~~~
Vue.component("row",{
template:"<li>{{item.account.name}}</li>",
props:{
item:{
type:Object,
default:[],
required:true
}
},
})
// 父组件中初始状态
<row :item="item"></row>
data:{
item :{}
},
created(){
// 模拟异步接口
setTimeout(()=>{
this.dataReady = true;
this.item =
{ account:{
name:8576
}}
},2000)
}
// vue warn 报错
VM1873 console_runner-ce3034e6bde3912cc25f83cccb7caa2b0f976196f2f2d52303a462c826d54a73.js:1 [Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"
found in
---> <Row>
~~~
**解决方案** :这样的报错主要是因为数据在渲染时没有保证其是在数据准备好的情况下,所以需要在组件渲染的做一些必要的准备工作。比如我们可以加下数据加载好的标志位。dataReady:false
~~~
<li is="row" :item="item" v-if="dataReady"></li>
// 父组件中
data:{
item:{},
dataReady:true,
}
created(){
// 模拟异步接口
setTimeout(()=>{
this.dataReady = true;
this.item =
{ account:{
name:8576
}}
},2000)
}
~~~
- 拓展认知1:如果你的数据是Array类型,也许不会有这样问题,因为Array类型默认用的[],所以没有内容不会渲染,内容有的时候才会进行渲染并进行循环,不过为了安全,element等框架还是进行了安全校验,v-if="data&&data.length>0",数据是对象的,加v-if="item" 以此来保证数据是有的情况。
- 拓展认识2 :即使是数据在正常得到的情况下,如果你的属性值也可能是空的,那么需要你在可能有属性报错或者没有的情况下,追加属性存在的判断,比如:`if(item.account&&item.account.name){//codes here}`
- [codepen案例地址:dataRenderError](https://codepen.io/robinson90/pen/dKONLQ)
### watch使用特性:更好的支持异步,可以支持深度监测
**问题场景**:这点主要是讲watch以及computed的区别,在watch使用场景中,我们可以针对某属性的变化,进行一些额外的异步或者同步逻辑或者事件,而计算属性本身只关注其最后的结果。而且计算属性时建立在watch基础上的,在进行计算的时候实际等同于对每个可影响的属性增加了watch监听。
那么具体的问题就是指当我们改变对象的非第一层属性或者值时,虽然值改变了,但是并未触发其watch方法监听。如此,我们就需要修改为第三种写法。
三种基本写法 :
~~~
watch: {
//第一种写法 适用于普通变量(简单类型的值的观测写法)
a: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
},
// 第二种写法:方法名
b: 'someMethod',
// 第三种写法:深度 watcher(能观测对象c下多重属性变化)(复杂类型的值的观测写法)
c: {
//当c变化后会回调handler函数
handler: function (val, oldVal) { /* ... */ },
deep: true
}
}
~~~
**解决方案** :使用deep,并且改变数值的方式要使用this.$set(this.obj,key,value)
~~~
data:{
pserson:''
},
watch:{
person:{
handler(){
console.log(111)
},
deep:true,
immediate:true
}
},
created(){
this.tip='变更数据'
setTimeout(()=>{
this.name = this.name2='zhang san'
this.tip='变化数据完成'
// this.$set(this.person,'tip',45);
this.person= Object.assign({},this.person,{tip:45});
this.person.account.name=['li定位si'];
},2000)
}
~~~
- [vueWatchDemo--codepen地址](https://codepen.io/robinson90/pen/JZEepN)
- 拓展:Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。不能用箭头函数,因为箭头函数会绑定父级的作用域,导致功能失败。
- 如果希望是第一次data的时候就监听,需要增加immediate:true (如果你是在created生命周期里就加了执行事件,是根据某监听属性来的,那么可以改到这个位置)
- 如果是新增属性,原来对象中没有的,需要用到前面的知识,用this.$set(),或者Object.assiagn()实现。如果是原来就有这个属性,直接用赋值方式就可以。
- 不要混淆watch监听与对数据的改变,直接赋值是任何时候都可以改变值的,只不过没触发监听事件
- watch默认就会返回其最新的val,不需要人为多一行代码去处理,但是如果你想返回其他值就需要加中间逻辑,并显性的返回需要的值。
### 移动端使用rem
一般情况下可能会自己做适配,也可以使用阿里的模块。amfe-flexible
- [amfe-flexible模块地址](https://npm.taobao.org/package/amfe-flexible)
~~~
//main.js 引入依赖
import 'amfe-flexible'
//_base.scss 设计图宽度除以10,假如设计图宽度是750px那么,基础宽度就是75
$baseWidthSize: 75 !default;
@function to($px) {
@return $px / $baseWidthSize * 1rem;
}
//组件和页面使用; to()里面的数值是photoshop里测量的值
<style lang="scss">
@import "../scss/_base.scss";
.box{
width: to(750);
height: to(100);
}
</style>
~~~
### 移动端使用vw布局
- [手淘vw适配方案](https://www.w3cplus.com/mobile/vw-layout-in-vue.html)
### 使用语言包 i18n
场景 :希望在项目中支持国际化 。
解决方案 :详细的见文章,描述较为详细。其中语言包可以根据路由的需要决定是否懒加载。
- [vue-i18n 使用](https://juejin.im/post/5aa7e18ff265da2384404334)
### watch 6位数字
**场景** :我们一般都需要对数字做验证,在没有其他外界环境的情况下,一般我们是通过正则进行验证的,但是现在产品对需求交互进行了细化,要求如下:在没有数字键盘,选择控件的情况下,还是比较麻烦的。
1 不能输入非数字,也就是只能输入数字
2 不能输入超过6位
**解决方案** :主要通过正则以及Number的相关方法实现。
~~~
number(newval){
let reg = /^[0-9]+$/ ;
let val = parseInt(newval) ;
if(reg.test(newval)){
this.number = newval.toString().substring(0,6);
}else if(isNaN(val)){
this.number = ''
}else{
this.number = val
}
}
~~~
- [numberWatch](https://codepen.io/robinson90/pen/RJLNYx)
### 兼容问题
在进行项目开发的时候,在ie9或者其他浏览器可能会遇到兼容问题,那么需要看下以下的几种可能,es6不支持 ,promise不支持 ,babel的相关设置不对 。
es6 不支持:
~~~
npm install babel-polyfill --save-dev
entry: {
'babel-polyfill': 'babel-polyfill',
app: './src/main.js'
},
.babelrc 文件的设置
"presets": [
"es2015",
"stage-2"
],
"plugins": ["transform-runtime"],
~~~
promise不支持 :
~~~
import promise from 'es6-promise';
promise.polyfill();
~~~
### 使用eventBus跨页面传参错误
场景:假设我们没有使用vuex,而需要在a页面跳转到b页面的时候进行大量的参数传递,可以使用eventBus事件进行,于是在a页面mounted 周期里提交事件,在b页面mounted周期接收事件。于是发现两个bug :
- 第一次出发并没有执行接收
- 后续的触发都会积累之前的
对于第一点是因为生命周期的问题,在进行页面跳转的时候,会先进行a页面的beforeDestroy周期,然后进行b页面的creadted,,在beforeMount之后才唤醒a页面的beforeDestroy,destroyed的周期,然后把提交事件放到beforeDestroy周期就可以了。
对于第二点是因为全局的eventBus定义之后,没有在destroyed周期里销毁对应的事件,所以针对这种情况需要.$off销毁对应的事件。那么在销毁的时候需要拿到其当前页面的路径,this.$route.path作为参数传递,this.bus.$off(this.$route.path).
### 页面刷新每次都要执行一个方法或者代码
场景:如上描述 ,如果这段代码写在常规的mounted的周期里不会每次刷新页面都执行,也有试过去执行某些方法无效。
解决方案 :
~~~
this.$nextTick(function(){
//codes here
})
~~~
备注:关于this.$nextTick后续会深入研究源码以及其解决的实际问题。
### 按需加载组件库
一般按需加载都是为了节省带宽,避免网络资源浪费,提高页面性能。下面以vant为例:
- 安装: cnpm i vant -S
- 安装babel-plugin-import插件使其按需加载: cnpm i babel-plugin-import -D
- 在 .babelrc文件中中添加插件配置 :
~~~
libraryDirectory {
"plugins": [
// 这里是原来的代码部分
// …………
// 这里是要我们配置的代码
["import",
{
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}
]
]
}
~~~
- 在main.js中按需加载你需要的插件:
~~~
// 按需引入vant组件
import {
DatetimePicker,
Button,
List
} from 'vant';
~~~
- 使用组件:
~~~
// 使用vant组件
Vue.use(DatetimePicker)
.use(Button)
.use(List);
~~~
- 页面中使用
`<van-button type="primary">按钮</van-button>`
**备注** :出来vant库外,像antiUi、elementUi等,很多ui库都支持按需加载,可以去看文档,上面都会有提到。基本都是通过安装babel-plugin-import插件来支持按需加载的,使用方式与vant的如出一辙,可以去用一下。
### 优雅的只在当前页面中修改ui库样式
很多情况下我们引入了组件,需要修改样式为我们需求的,但是因为如果加scoped的关键字,就会找不到对应的库样式,一般我们是采用非scoped的样式去覆盖,但这样会造成样式污染,而且其他人是不知情的。
所以建议可能会有一种是:
在样式公共目录下统一的修改组件样式,然后大家共用,同时与产品、设计约定好这样的规则 。
**还有一种就是本文推荐的,深度选择器,我们可以在当前页面修改库样式:**
`.van-tabs /deep/ .van-ellipsis { color: blue};`
官方文档:[deep选择器](https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors)
### 轮播的技术选型
如果你只是想使用轮播的组件,这里推荐Vue-Awesome-Swiper。
- [vue-awesome-swiper](https://npm.taobao.org/package/vue-awesome-swiper)
- [swiper文档说明](http://www.swiper.com.cn/api/index.html)
### 定位分析大文件
在进行项目优化的时候,我们需要针对性的分析出哪些文件大,以及如何优化 。
如果你是vue-cli初始化的项目,会默认安装webpack-bundle-analyzer插件,该插件可以帮助我们查看项目的体积结构对比和项目中用到的所有依赖。也可以直观看到各个模块体积在整个项目中的占比。
![](https://user-gold-cdn.xitu.io/2018/6/12/163f310014cc9b59?imageslim)
npm run build --report // 直接运行,然后在浏览器打开http://127.0.0.1:8888/即可查看(先把run dev关掉)
### 开启gzip压缩代码
spa这种单页应用,首屏由于一次性加载所有资源,所有首屏加载速度很慢。解决这个问题非常有效的手段之一就是前后端开启gizp(其他还有缓存、路由懒加载等等)。gizp其实就是帮我们减少文件体积,能压缩到30%左右,即100k的文件gizp后大约只有30k。
vue-cli初始化的项目中,是默认有此配置的,只需要开启即可。但是需要先安装插件:
`cnpm i compression-webpack-plugin`
然后在config/index.js中开启即可:
~~~
build: {
// 其他代码
…………
productionGzip: true, // false不开启gizp,true开启
// 其他代码
}
~~~
现在打包的时候,除了会生成之前的文件,还是生成.gz结束的gzip过后的文件。具体实现就是如果客户端支持gzip,那么后台后返回gzip后的文件,如果不支持就返回正常没有gzip的文件。
**注意**:这里前端进行的打包时的gzip,但是还需要后台服务器的配置。配置是比较简单的,配置几行代码就可以了,可以让运维操作下。(待完善具体的配置)
### 浏览器前进后退刷新数据的问题
keep-alive 不能完全解决你的问题的话,参考这里的文章实践:[浏览器刷新时的数据与位置](https://juejin.im/post/5b2ce07ce51d45588a7dbf76)
- 前端工程化
- 架构总纲
- 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
- 入门