首頁  >  文章  >  web前端  >  詳細解讀vue.js中props如何傳遞參數

詳細解讀vue.js中props如何傳遞參數

亚连
亚连原創
2018-06-21 14:33:402162瀏覽

給大家詳細分析了vue.js之props傳遞參數的相關知識以及問題解決方法,需要的朋友參考下。

這篇文章透過demo實例給大家詳細分析了props傳遞參數的用法以及遇到問題後的解決辦法,以下是全部內容。

前段時間用vue做一個後台管理系統,其中每一頁都需要一個表格來展示資訊。自然就想到了將表格提取出來做成公共元件,將不同頁面的資料傳入進行渲染,達到復用的目的。

demo位址

1. 問題發現

在父元件中,需要傳遞給表格元件的資料有表格的內容資料tableData,表格的頁面資料page。

<p>
 <my-table :table-data="tableData" :page-info="pageInfo" id="myTable"></my-table>
</p>

其中tableData是個Array對象,是所有需要在表格中展示的資料對象所組成的陣列。而pageInfo是個Object對象,包含了表格頁面資訊。在父元件對兩個資料對如下初始化,形式如下

tableData:[],
pageInfo: {
 current: 1, // 当前是第几页
 total: 100, // 数据对象的总数
 size: 20 // 每页显示的数量
}

按照官方文件上的說明,prop是單向綁定的,不應該在子元件內部改變prop。之所以有想修改prop中資料的衝動,主要是prop作為初始值傳入後,子元件想把它當作局部資料來用。對於這種情況,官方的說法是定義一個局部變量,並用prop 的值初始化它:

props: [&#39;tableData&#39;, &#39;pageInfo&#39;],
data() {
 return {
  tData: this.tableData,
  page: this.pageInfo
 }
}

然後根據官方文件的說法,當每次父組件更新時,子組件的所有prop都會更新為最新值。而tableData和pageInfo的資訊是非同步透過api從server端取得的:

{
 error: 0,
 msg: "调用成功.",
 data: {
  restrictioninfo: [...],
  total: 42
 }
}

因此當取得到資料時父元件需要改變傳入子元件中的值:

me.tableData = Json.data.restrictioninfo;
me.pageInfo.total = Json.data.total;

依理說這時候子元件中的值應該更新成server回傳的值,但是子元件頁面的總數更新了,但table資料依然是初始化時的空數組。 (黑人問號???)


2.賦值與綁定

#首先需要定位資料是在哪個地方出了問題,於是我做了一個demo來定位問題。

首先看父元件與子元件中各元素的初始值:

#然後只改變父元件中陣列的參考時可以看到子元件的props數組隨之改變,而子元件中綁定的數組確並沒有隨之改變

因此,可以發現,問題是出在了這一步

props: [&#39;tableData&#39;, &#39;pageInfo&#39;],
data() {
 return {
  tData: this.tableData,
  page: this.pageInfo
 }
}

而要弄清楚問題的根源,就得弄清楚vue文件中深入響應式原理。

"在Vue實例的data選項中,Vue將遍歷此物件所有的屬性,並使用Object.defineProperty將這些屬性全部轉為getter/setter","每個元件實例都有對應的watcher 實例對象,它會在元件渲染的過程中把屬性記錄為依賴,之後當依賴項的setter 被呼叫時,會通知watcher 重新計算,從而致使它關聯的元件得以更新。」文件中說了這麼一大堆,簡單理解就是Vue將data選項中的vm.$data.a與DOM中的vm.a進行了雙向綁定,即其中一個變化,另一個也會跟著變化。在Vue原始碼中是由defineReactive$$1函數實現的:

但在子其中主要利用了Object.defineProperty的get和set方法實現了雙向綁定。而在子元件中,pros資料與子元件的$data則是透過以下方式連結在一起的:

tData: this.tableData

查詢Vue原始碼可知this.tableData與tData之間僅是賦值,即"="關係

而上述的initData函數是在元件建置時候執行的,因此只會在create時執行一次。這也是為什麼官方文件中"作為初始值傳入"這一說法,因為他本來就只會執行一次。當元件建置完成後,this.tableData與tData就沒有半毛錢關係了,其中一個的變化不會造成另一個變化。當然,這種說法並不準確,因為在上文中,我們動態改變父組件傳入的total,子組件也"隨之"改變,感覺就像是綁定在一起了啊,這又是怎麼回事呢?

3.引用型別帶來的假象

#當然,我們還是要從官方文件出發來解決這個問題。文檔中有這樣一個提示:

这里就需要理解引用类型的概念,引用数据类型值指保存在堆内存中的对象。也就是,变量中保存的实际上的只是一个指针,这个指针指向内存中的另一个位置,该位置保存着对象。访问方式是按引用访问。例如一个js对象a,他在内存中的存储形式如下图所示:

var a = new Object();

当操作时,需要先从栈中读取内存地址,然后再延指针找到保存在堆内存中的值再操作。

a.name = &#39;xz&#39;;


引用类型变量赋值,本质上赋值的是存储在栈中的指针,将指针复制到栈中未新变量分配的空间中,而这个指针副本和原指针指向存储在堆中的同一个对象;赋值操作结束后,两个变量实际上将引用同一个对象。因此,在使用时,改变其中的一个变量的值,将影响另一个变量。

var b = a;


在了解了引用类型之后,我们在来看看上文提到的动态改变传入子组件前后内存中的情况:

me.tableData = Json.data.restrictioninfo;
me.pageInfo.total = Json.data.total;
========================================
props: [&#39;tableData&#39;, &#39;pageInfo&#39;],
data() {
 return {
  tData: this.tableData,
  page: this.pageInfo
 }
}

首先对tableData的改变是改变了其引用的指针,而对pageInfo则改变了其中一个属性的值,因此动态改变前:

动态改变后:

这样就解释了为什么子组件页面的总数更新了,但table数据依然是初始化时的空数组。因为引用类型的存在,我们动态改变父组件传入的total,子组件也"随之"改变了。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在jQuery中如何实现点击DIV触发点击CheckBox

使用JS如何实现点击复选框修改显示状态

在Vue中标准的处理方法(详细教程)

以上是詳細解讀vue.js中props如何傳遞參數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn