如今前端框架和以前的前端开发方式有一个重要的区别————基于数据驱动。咱们不须要再去关注dom自己,而是将主要精力放在如何操做数据上面。实际开发中,能够抽象成css
既然所有在完数据, 数据类型、算法就跑不掉了。html
本片介绍一个基于引用类型的vue黑科技, 在使用vue开发的时候能够更加方便。前端
首先, 抄一段别人的博客vue
1.JavaScript中的变量类型有哪些?
(1)值类型:字符串(string)、数值(number)、布尔值(boolean)、none、undefined
(2)引用类型:对象(Object)、数组(Array)、函数(Function)
2.值类型和引用类型的区别
(1)值类型:一、占用空间固定,保存在栈中(当一个方法执行时,每一个方法都会创建本身的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将天然销毁了。所以,全部在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为什么修改引用类型总会影响到其余指向这个地址的引用变量。)
二、保存与复制的是值自己
三、使用typeof检测数据的类型
四、基本类型数据是值类型
(2)引用类型:
一、占用空间不固定,保存在堆中(当咱们在程序中建立一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(由于对象的建立成本一般较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即便方法结束后,这个对象还可能被另外一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。)
二、保存与复制的是指向对象的一个指针
三、使用instanceof检测数据类型
四、使用new()方法构造出的对象是引用型
复制代码
基础知识就是这些了。 举个小栗子。算法
在vue中的数据传递过程当中, 是不涉及深拷贝的。 是经过props、vuex、v-bind等方法传递的引用类型都是传递的内存指针 在来个小栗子vuex
<template>
<div class="content">
<ul>
<li v-for="(item, index) in list" :key="index" >
<span @click="changeItemValue(item)">{{item.title}}</span>
<span @click="deleteItem(index, list)">删除</span>
</li>
<li @click="addItem(list)">添加item</li>
</ul>
</div>
</template>
<script>
export default {
name: 'index',
data () {
return {
list: [
{
title: 'index0',
},
{
title: 'index1'
},
{
title: 'index2'
},
{
title: 'index3'
},
{
title: 'index4'
}
]
}
},
methods: {
changeItemValue(item) {
item.title = item.title += '--|'
},
deleteItem(index, list) {
list.splice(index, 1)
},
addItem(list) {
list.push({
title: 'index' + list.length
})
}
}
}
</script>
<style lang="scss" scoped>
ul {
width: 500px;
margin: 200px auto;
li {
width: 200px;
height: 50px;
line-height: 50px;
border: 1px solid pink;
span:nth-child(2){
margin-left: 10px;
color:red;
}
}
}
</style>
复制代码
在上面的例子中, 咱们都没有使用this.list[index]
的方式来获取须要修改的对象, 实际上, 方法里面传入的item就是this.list
里对应的item的引用
这样书写会比经过传入索引--> 经过索引在list寻找该对象--> 修改该对象要方便的多。 特别是在数据层级比较深的时候。经过索引来查找可能会出现小程序
changeItemValue(itemAIndex, itemBIndex, itemCindex, itemDIndex, value) {
this.list[itemAIndex].childList[itemBIndex].childList[itemCindex].childList[itemDIndex].title = value
}
复制代码
这酸爽~微信小程序
咱们举一个引用的小场景数组
<template>
<div class="content">
<ul>
<li v-for="(item, index) in list" :key="index" >
<span>{{item.title}}</span>
<span @click="changeItemValue(item)">{{item.isSelect ? '选中' : '未选中'}}</span>
</li>
<li @click="save">保存</li>
</ul>
</div>
</template>
<script>
export default {
name: 'index',
data () {
return {
list: [
{
title: 'index0',
isSelect: false
},
{
title: 'index1',
isSelect: false
},
{
title: 'index2',
isSelect: false
},
{
title: 'index3',
isSelect: false
},
{
title: 'index4',
isSelect: false
}
]
}
},
methods: {
changeItemValue(item) {
item.isSelect = !item.isSelect
},
save() {
const data = this.list.filter(_ => _.isSelect)
console.log(data)
}
}
}
</script>
复制代码
接下来咱们讲一讲经过props的方式向子组件传递的状况, 众所周知,vue是不容许在组件内修改经过props传入的值的。实际中呢:
若是传入的数据是值类型的, 那么不容许修改这个值 例如 this.string = ''
若是传入的数据是引用类型, 那么不容许修改这个数据的内存地址,反之呢,咱们能够修改这个数据中的子数据
复制代码
感受上这种操做是违反vue的单向数据流思想的, 可是实在是在开发中太好用了, 因此我只能说这是一种黑科技 来个例子, 咱们修改一下上面的代码, 将li做为一个组件来管理一个对象
<template>
<div class="content">
<ul>
<Item v-for="(item, index) in list" :key="index" :item="item" />
<li @click="save">保存</li>
</ul>
</div>
</template>
<script>
import Item from './Item'
export default {
name: 'index',
components: { Item },
data () {
return {
list: [
{
title: 'index0',
isSelect: false
},
{
title: 'index1',
isSelect: false
},
{
title: 'index2',
isSelect: false
},
{
title: 'index3',
isSelect: false
},
{
title: 'index4',
isSelect: false
}
]
}
},
methods: {
save() {
const data = this.list.filter(_ => _.isSelect)
console.log(data)
}
}
}
</script>
复制代码
<template>
<li>
<span>{{item.title}}</span>
<span @click="changeItemValue">{{item.isSelect ? '选中' : '未选中'}}</span>
</li>
</template>
<script>
export default {
name: 'Item',
props: ['item'],
methods: {
changeItemValue() {
this.item.isSelect = !this.item.isSelect
// 注意 如上面所说 在这里直接修改item就会报错, 反之 只修改item下面的值并不会
}
}
}
</script>
复制代码
运行起来, 和以前并无差别, 实际上props传进去的也是这个对象的引用, 修改的时候父组件的值也被同步修改了。这样咱们能够在子组件里面修改对应的值, 而不须要$emit到父组件去修改。在处理复杂数据的时候, 能够减小不少负担 基于这种模式, 咱们在处理一个复杂数据的编辑的时候, 就能够将每一块相对独立的子数据分别用组件去维护。 并且子组件的数据相对对立, 层级浅的时候, 咱们还能够方便的使用computed计算属性来实现一些数据的校验,UI的处理。
在使用vudex作状态管理的时候, 状况和pros差很少。
若是绑定的的数据是值类型的, 那么不容许修改这个值 例如 this.string = ''
若是绑定的的数据是引用类型, 那么不容许修改这个数据的内存地址,反之呢,咱们能够修改这个数据中的子数据
复制代码
可是有一点, 在使用vue-devtools工具的中会有点差别,简单来讲经过这种方式修改了state中的值,在vue-devtools工具的vuex部分是不会更新的, 可是实际上数据是已经改变了。。 依旧是先前的那个例子, 咱们将数据源从data改成vuex
computed: {
list() {
return this.$store.state.list
}
}
复制代码
咱们经过这种方式改变值以后,
mutations: {
changeList(state, list) {
state.list = list
}
},
this.$store.commit('changeList', this.$store.state.list)
复制代码
基于这种方法, 咱们在处理复杂数据的时候, 能够将相对独立的数据块分割出来用一个单独的vue组件来维护和修改。最后的修改结果均可以在原有的数据树中体现,在提交的时候对这个跟数据进行处理就好。而不用每一次修改都emit到父组件中处理。
如上图, 计算属性的值正常更新了, 经过deep watch的值, 两个都是新的值, 没法取得oldVal, 而不用deep的时候, 这个watch根本不会触发。
经过这种方式, 在处理比较复杂的数据的时候有奇效, 可是隐隐约约仍是有些怪异,表面稳如老狗,实际慌得不行。 也请大佬解惑
你们都在说复杂的引用类型难以维护的状况,我不得不吐槽一下了。。 咱们常常拿到的数据是这样的
[
{
"id": 592,
"catalogueCode": "catalogueCode",
"catalogueRule": "catalogueRule",
"catalogueName": "catalogueName",
"days": "3",
"expectedDate": null,
"groups": [
{
"groupName": "groupName",
"subsets": [
{
"items": [
{
"catalogueRule": "catalogueRule",
"ruleId": 1,
"ruleName": "ruleName",
"catalogueCode": "catalogueCode",
"ruleScore": 2
},
{
"catalogueRule": "catalogueRule",
"ruleId": 77,
"ruleName": "ruleName",
"catalogueCode": "catalogueCode",
"ruleScore": 2
}
]
}
]
}
],
"goals": [
{
"goalId": 642,
"catalogueName": "catalogueName",
"catalogueRule": "catalogueRule",
"catalogueCode": "catalogueCode",
"remark": null,
"resultId": 592,
"sortNum": null,
"measures": [
{
"measureId": 2541,
"catalogueCode": "catalogueCode",
"catalogueRule": "catalogueRule",
"catalogueName": "catalogueName",
"customizeId": null,
"sort": 0,
"checked": true,
"shortActivityMap": {
"key1": [
{
"catalogueName": "catalogueName",
"catalogueRule": "catalogueRule",
"catalogueCode": "catalogueCode",
"resultId": 2541,
"longActivityList": [],
"specialSecondType": "3",
"frequencyName": "bid",
"executionTime": "08:00,16:00",
"shortActivityId": 82
}
],
"key2": [
{
"catalogueName": "catalogueName",
"catalogueRule": "catalogueRule",
"catalogueCode": "catalogueCode",
"resultId": 2541,
"longActivityList": [],
"specialSecondType": "3",
"frequencyName": "bid",
"executionTime": "08:00,16:00",
"shortActivityId": 82
}
]
}
}
],
"appraisals": [
{
"appraisalId": 2048,
"catalogueName": "catalogueName",
"catalogueRule": "catalogueRule",
"catalogueCode": "catalogueCode",
"remark": null,
"resultId": null,
"targetCode": "targetCode",
"sortNum": null
}
]
}
],
"totalScore": 4
},
]
复制代码
这个层级相对仍是比较少的, 最深数据接近6层。关键在于每个数据节点都是有对应的增删改的编辑需求, 而且不能分布提交。 那么这个页面的编辑。怎么处理?
不过如评论所说, 若是vue认为修改props内部数据是缺陷或者是BUG,之后会修复的话那,那毫无疑问我要加班了。。
我用的这种方法, 我以为不踏实,我写出来和你们一块儿讨论,抛砖引玉, 但愿有大佬能指点或者分享经验就是个人目的, 评论一上来就开骂是咋回事。