vue的数据赋值联动改变解决方案

最近连着做了好几个vue项目,从0到版本迭代,vue教程算是好理解,把vue官方文档看一遍下来,基本上不会有什么大问题(嗯如果你看的够仔细够透彻的话),此篇是记录vue踩过的坑以及可以优化的地方。

1.踩坑

1.1.深拷贝/浅拷贝

这实际上算不上vue的问题,算是js基础没打好的坑吧。

先来看一个简单的例子:

let obj = {name:'fiona-SUN'};
let copyObj = obj;
copyObj.name = 'fiona';
console.log(copyObj.name);  // 'fiona'
console.log(obj.name);     // 'fiona'

在js中也有栈(stack)和堆(heap)的概念:

  • 栈:自动分配的内存空间,大小确定会自动释放。存放变量/局部变量/形参等。在js中存放简单数据段(五种基本数据类型:Number、String、Boolean、Null、Undefined),他们是按值存放的,可以直接访问。
  • 堆:动态分配的内存,大小不定并且不会自动释放。存放在堆内存中的对象,栈中的变量实际保存的是一个指针,这个指针指向堆中的某一个位置。

所以上述例子中,属于浅拷贝,当我们声明一个对象,由于他不属于五种基本数据类型(即非简单数据段),栈中会存放一个我们声明的obj变量,它指向了堆中实际的这个对象的地址。当我们把这个引用地址赋值给了copyObj,实际它获得的是一个与obj一致的指向堆中的地址。当copyOjb改变了指向的对象地址的实际的值的时候,obj拿到的值也就自然而然变化了。看图理解⬇

image

嗯,道理我都懂,但是写代码我就自然而然的忽略了,该反思。。。

深拷贝的方法

  • 方法一:逐个去拿到简单数据项(网上可以搜到递归解决,思路类似)
let obj = {name:'fiona-SUN'};

let copyFunc = (originObj) => {
  let copyObj = {};
  for(let key in originObj){
    copyObj[key] = originObj[key];
  }
  return copyObj;
};

let copyObj = copyFunc(obj);
copyObj.name = 'fiona';
console.log(copyObj.name);  // 'fiona'
console.log(obj.name);     // 'fiona-SUN'
  • 方法二:通过JSON去解析
let obj = {name:'fiona-SUN'};

let copyObj = JSON.parse(JSON.stringify(obj));

copyObj.name = 'fiona';
console.log(copyObj.name);  // 'fiona'
console.log(obj.name);     // 'fiona-SUN'
  • 方法三:es6之展开Object.assign(拷贝obj的内容到一个新的堆内存,copyObj存储新内存的引用)
let obj = {name:'fiona-SUN'};

let copyObj = Object.assign({}, obj);

copyObj.name = 'fiona';
console.log(copyObj.name);  // 'fiona'
console.log(obj.name);     // 'fiona-SUN'
  • 方法四:es6之展开运算符(仅用于数组)
let arr = [1,2,3];
let copyArr = [...obj];
copyArr[2] = 0;
console.log(copyArr[2]);  // 0
console.log(arr[2]);     // 2

数组的深拷贝:

方法一:使用slice

var arr = [1,2,3];
var newArr = arr.slice(0);

方法二:使用concat

var arr = [1,2,3];
var newArr = arr.concat();

1.2.列表更新检测

1.2.1数组更新检测

以下摘自vue官网API

由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  1. 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如:vm.items.length = newLength

为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)

为了解决第二类问题,你可以使用 splice:

example1.items.splice(newLength)

触发视图更新的方法:

  1. 变异方法
  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()
  1. vue提供的set方法
  • Vue.set( target, key, value )
1.2.2对象更新检测

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

解决方法:

  1. vue提供的set方法
  • Vue.set( target, key, value )
  1. Object.assign()
  • bject.assign({}, target, {key:value})

1.3.页面刷新vuex被清空

这真的是遇到一个很坑的问题,同一个页面(router未改变),一旦刷新(刷新或深度刷新),存储的vuex就马上和你说拜拜

  • localStorage
    网上推荐最多的方法就是用localStorage。但是我个人觉得不太合适,还得看项目吧。localStorage是永久存储的。

  • 数据重新获取
    我使用的方法是在需要某些数据之前先判断一下数据是否存在,如果不存在重新获取。

1.4nextTick适当使用

将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

简而言之,等待DOM更新之后再进行操作。

1.5.异步问题

这个是一个亘古不变的话题。

请求后台数据异步,常不经意的带来了问题。(处理异步的方法就不详细描述了,网上一搜一大堆)

1.6.组件之间的调用方式

1.6.1.父子组件
  • prop向下传递,事件向上传递
  • 子组件添加ref属性,父组件可以获取到子组件的实例(不建议)
  • 插槽slot 作用域插槽
1.6.2.非父子组件
  • 使用状态管理
  • 实例化一个公共vue实例

1.7.计算属性设置值

计算属性是基于它们的依赖进行缓存的,一旦依赖发生变化,计算属性会重新计算

想要改变计算属性的值。要通过set方法去触发它所依赖的变量,(类似于触发它重新计算,单纯赋予一个新值,在取的时候也是不会被改变的)

1.8.vue文件中内联样式中有无scoped属性的差别

  • 有scoped属性:
    当前仅当该vue文件可以使用这个样式。
  • 无scoped属性:
    影响其他文件

1.9 v-for v-key

当 Vue.js 用v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的且唯一的 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值 (在这里使用简写):

1.10 v-for 和 v-if

当它们处于同一节点,v-for的优先级比v-if更高。

1.11 js文件中引入的css不会自动加前缀

无论是开发环境还是生成环境都不会自动加前缀,因为vue-loader只管.vue文件里面的样式,没有自动执行autoprefixer loader

参考链接

在build/utils.js下引入postcss-loader

var postcssLoader = {
    loader: 'postcss-loader',
    options: {
        plugins: (loader) => [
            require('autoprefixer')()
        ],
        sourceMap: true
    }
}

如果还有问题在改成

var postcssLoader = {
    loader: 'postcss-loader',
    options: {
        plugins: (loader) => [
            require('autoprefixer')({
                browsers: [
                    // 加这个后可以出现额外的兼容性前缀
                    "> 0.01%"
                ]
            })
        ],
        sourceMap: true
    }
}

1.12 组件、prop大小写不敏感,事件敏感

对于组件和prop而言,html上用kebab-case (短横线分隔命名) ,其对应的js上要用

(HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:)

【但是:如果你使用字符串模板,那么这个限制就不存在了。】

components: {
    kebabCase
}

---

prop: ['kebabCase']

跟组件和 prop 不同,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。

跟组件和 prop 不同,事件名不会被用作一个 JavaScript 变量名或属性名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。

因此,我们推荐你始终使用 kebab-case 的事件名。

1.13 refs是静态节点

refs是静态节点

1.14 prop值的改变--不是立即

如果父组件中给子组件传递了一个prop的值,然后调用子组件的方法去获取该值,会发现值没有立即改变。

解决方法:

  1. 可以监听值的改变去调用相应子组件的方法
  2. 将子组件相关方法的调用放在nextTick里面

1.15 elmentui里面的el-form '就地复用'

和v-for一样,更新已渲染过的元素时,它默认用‘就地复用’策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单服用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

1.16 elementui中的el-table的列显示与隐藏

如果有一组按钮组,点击不同的tab的时候显示不同的列,列会更换位置。默认用‘就地复用’,不会更新,需要加一个key值取随机数

1.17 fetch兼容

在vue-cli中使用fetch方式请求的时候。存在一定的兼容问题。

可以在build/webpack.base.conf.js中添加一个plugins

plugins:[
new webpack.ProvidePlugin({
  fetch: 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch',
  Promise:  'imports-loader?this=>global!exports-loader?global.Promise!es6-promise',
})
]

1.18 字符串模板

字符串模板

ps:注意依赖包的下载

2.优化

2.1.错误处理

错误处理很重要但是这是最容易让开发忽略的点。

2.1.1.请求接口错误

由于我的请求是使用axios插件或者fetch单独写在了一个js,可以对其进行响应拦截。一旦失败,或者后台报错,就进行响应的错误处理以及友好提示,也避免了重复的代码,提高可维护性

2.1.2.页面错误处理(404)
  1. nginx未匹配到路由走404路由
  2. router.beforeEach是否匹配到响应的路由,否则走错误路由。
2.1.3 错误提示封装

将错误提示模块化,通过vuex来操作错误的显示以及信息等内容。

2.2.减少不必要的依赖包

性能优化是很重要的,特别是对于vue这种首屏加载时间长的。

例如有些项目用到了图表(echarts),可以选择加载依赖包,不用加载整个echarts库。

2.3.不发送多个相同的请求

不发送多个相同的请求,在点击触发请求的同时锁定请求,直至给出响应/错误解锁。

以上内容,如有错误请指出,不甚感激。
如需转载,请注明出处

2.4.组件中引入css的css依赖 -- sass-resources-loader

为了让SCSS之类的文件在CSS中引入中不需要每次都引入var.scss文件,可以引入一个sass-resources-loader解决。

2.4.为了解决组件内引入的外部css文件没有做css兼容处理 -- postcss-loader

在build/utils中引入postcss-loader

loader: 'postcss-loader',
options:{
  plugins: (loader) => [
      require('autoprefixer')()
  ],
  sourceMap: true 
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • vue概述 在官方文档中,有一句话对Vue的定位说的很明确:Vue.js 的核心是一个允许采用简洁的模板语法来声明...
    li4065阅读 7,176评论 0 25
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,040评论 0 29
  • 第二章 细心八戒发现端倪 只身赴寺有去无回 我们很多人只记得现在这个好吃懒做的八戒,却忘了那个曾...
    一个正经的作家阅读 210评论 0 1
  • 我会给你波澜不惊的爱情,陪你看世界的风景,许你一世欢颜。 栗子小姐和洋葱先生又吵架了,闹得特别不开心要分手。两人相...
    握不住的ta阅读 621评论 0 0
  • 人们往往追求缤纷绚烂,光彩夺目的事物,但渐渐地,在追求的过程中突然发现,这些东西只是虚有其表,非常不真实,而且会让...
    缘起缘灭_0bb8阅读 56评论 0 0