如今前端框架和以前的前端開發方式有一個重要的區別————基於數據驅動。咱們不須要再去關注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
}
複製代碼
這酸爽~微信小程序
咱們舉一個引用的小場景數組
頁面的列表中, 每個item有一個開關, 須要在保存的時候取出所有所有選中的<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
}
}
複製代碼
咱們經過這種方式改變值以後,
在組建視圖, 咱們能看到組建內的isSelect值已經更新了, 父組件的計算屬性中 第一個對象的值也更新了 可是在vuex視圖中 這個值沒有被更新, 打印出來的值也是更新了的。。 若是有強迫症的話, 能夠手動更新一下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,之後會修復的話那,那毫無疑問我要加班了。。
我用的這種方法, 我以爲不踏實,我寫出來和你們一塊兒討論,拋磚引玉, 但願有大佬能指點或者分享經驗就是個人目的, 評論一上來就開罵是咋回事。