Vue Component 之 Prop

栏目: JavaScript · 发布时间: 6年前

内容简介:Component 若只有一層,那問題不大,若牽涉到 component 包含 component,就會牽涉到一個基本問題:該如何將 data 由外層 component 傳給內層 component ?這時候就要使用 Vue Component 的 Prop,這也是 Vue 從 React 學來的部分。Vue 2.5.17

Component 若只有一層,那問題不大,若牽涉到 component 包含 component,就會牽涉到一個基本問題:該如何將 data 由外層 component 傳給內層 component ?

這時候就要使用 Vue Component 的 Prop,這也是 Vue 從 React 學來的部分。

Version

Vue 2.5.17

Static Prop

一樣是老梗 Hello World,但這次 data 並不是在 Vue Instance 內定義,而是由外層傳進來。

Static Prop

靜態資料 由 prop 傳進 component

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Static Prop</title>
</head>
<body>
  <div id="app">
    <hello-world greeting="Hello" user-name="World"></hello-world>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="HelloWorld.js"></script>
<script src="index.js"></script>
</html>

第 9 行

<hello-world greeting="Hello" user-name="World"></hello-world>

一樣使用 <hello-world></hello-world> Component,但這次透過自訂的 greetinguser-name 將 data 由 component 的外層傳進來。

index.js

new Vue({
  el: '#app'
});

建立 Vue Instance。

HelloWorld.js

Vue.component('HelloWorld', {
  props: [
    'greeting',
    'userName'
  ],
  template: `
    <span>{{ greeting }} {{ userName }}</span>
   `,
});

第 2 行

props: [
  'greeting',
  'userName',
],

若要由 Component 的外層傳 data 進來,則要在 Vue Instance 使用 props property。

props 為 array,每個 prop 使用 string 定義。

第 6 行

template: `
  <span>{{ greeting }} {{ userName }}</span>
`,

props 宣告過 greetinguserName prop 之後,就可在 template 如同使用 data 的 model 了。

在 prop 使用上,有一點要注意:

  • Props 若在 JavaScript 使用了 CamelCase,在 Vue Template 會自動改成 kebab-case 才能用 (W3C 建議)

Vue Template 能綁定的資料,除了能使用 datacomputed 外,目前還多了 props

Dynamic Prop

剛剛傳進 prop 的值是寫死的,能夠動態以 MVVM 的 model 結合 prop 嗎 ?

Dynamic Prop

動態資料 (MVVM 的 model ) 傳進 prop

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Dynamic Prop</title>
</head>
<body>
<div id="app">
  <ul>
    <hello-world v-for="userName in userNames" greeting="Hello" :user-name="userName"></hello-world>
  </ul>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="HelloWorld.js"></script>
<script src="index.js"></script>
</html>

第 9 行

<ul>
  <hello-world v-for="userName in userNames" greeting="Hello" :user-name="userName"></hello-world>
</ul>

想將 userName 綁定到 user-name prop,必須使用 : Attribute Binding。

userName 則由 v-for 來自於 userNames

index.js

new Vue({
  el: '#app',
  data: {
    userNames: [
      'Sam',
      'Kevin',
      'John'
    ]
  }
});

userNames 是 Vue Instance 的 data 所定義的 model。

HelloWorld.js

Vue.component('HelloWorld', {
  props: [
    'greeting',
    'userName'
  ],
  template: `
    <li>{{ greeting }} {{ userName }}</li>
   `
});

與 Static Prop 的 HelloWorld.js 完全一樣。

透過 Dynamic Prop,我們就能將 component 外層的 model 透過 prop 傳進 component

Unidirectional Dataflow

Vue Prop 是 單向數據流 ,也就是 data 只能從 component 外層傳進 component,而無法由內層 component 傳到外層 component。

若要將 data 從內層 component 傳到外層 component,則要使用 event

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Unidirectional Dataflow (Warning)</title>
</head>
<body>
  <div id="app">
    {{ counter }}
    <button @click="add">+</button>
    <my-counter :inner-counter="counter"></my-counter>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="Counter.js"></script>
<script src="index.js"></script>
</html>

第 9 行

{{ counter }}
<button @click="add">+</button>

外層有自己 counter 計算。

11 行

<my-counter :inner-counter="counter"></my-counter>

想要將 counter model 透過 inner-counter prop 傳進 MyCounter component。

index.js

new Vue({
  el: '#app',
  data: {
    counter: 0
  },
  methods: {
    add() {
      this.counter++;
    }
  }
});

第 3 行

data: {
  counter: 0
},
methods: {
  add() {
    this.counter++;
  }
}

上層有自己的 counter 計算。

Counter.js

Vue.component('MyCounter', {
  template: `
    <div>
      <h2>{{ innerCounter }}</h2>
      <button @click="add">+</button>
    </div>
   `,
  props: [
    'innerCounter'
  ],
  methods: {
    add() {
      this.innerCounter++;
    }
  }
});

第 8 行

props: [
  'innerCounter'
],

定義 innerCounter prop。

11 行

methods: {
  add() {
    this.innerCounter++;
  }
}

直接 innterCounter prop 做累加。

Vue Component 之 Prop

這種寫法雖然可以執行,但有個淺在問題:由於 Vue 的 Unidirectional Dataflow,每次 component 外層的 model 改變,都會傳入內層 component,因而會覆蓋掉原本 component 的資料。

Vue 也在 run-time 提出警告,建議不要對 prop 直接修改,因為 data 隨時會被外層 component 蓋掉。

由於不建議直接改 prop,Vue 官網建議兩種 Pattern 使用 prop:

  • 改用 Data
  • 改用 Computed

改用 Data

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Unidirectional Dataflow (Data)</title>
</head>
<body>
  <div id="app">
    {{ counter }}
    <button @click="add">+</button>
    <p></p>
    <my-counter :start-counter="counter"></my-counter>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="Counter.js"></script>
<script src="index.js"></script>
</html>

12 行

<my-counter :start-counter="counter"></my-counter>

inner-counter 改成 start-counter prop。

index.js

new Vue({
  el: '#app',
  data: {
    counter: 0
  },
  methods: {
    add() {
      this.counter++;
    }
  }
});

與之前的 index.js 完全一樣。

Counter.js

Vue.component('MyCounter', {
  template: `
    <div>
      <h2>{{ innerCounter }}</h2>
      <button @click="add">+</button>
    </div>
   `,
  props: [
    'startCounter'
  ],
  data() {
    return {
      innerCounter: this.startCounter
    }
  },
  methods: {
    add() {
      this.innerCounter++;
    }
  }
});

第 8 行

props: [
  'startCounter'
],

改成 startCounter prop。

11 行

data() {
  return {
    innerCounter: this.startCounter
  }
},

由於 prop 不適合直接修改,因此我們另外宣告了 innerCounter model。

startCounter 的用途只在於初始化 innerCounter model。

由原本直接修改 prop,改成修改 Data,prop 只退化用來初始化 model

改用 Computed

使用 Data 的優點內層 component 的資料不會受外層影響,但缺點是內層 component 的資料不會與外層連動。

若有內外層 data 連動的需求,Vue 則建議改用 computed。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Unidirectional Dataflow (Computed)</title>
</head>
<body>
  <div id="app">
    {{ counter }}
    <button @click="add">+</button>
    <my-counter :start-counter="counter"></my-counter>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="Counter.js"></script>
<script src="index.js"></script>
</html>

11 行

<my-counter :start-counter="counter"></my-counter>

一樣使用 start-counter prop 傳入資料。

index.js

new Vue({
  el: '#app',
  data: {
    counter: 0
  },
  methods: {
    add() {
      this.counter++;
    }
  }
});

index.js 一樣也沒變。

Counter.js

Vue.component('MyCounter', {
  template: `
    <div>
      <h2>{{ countDoubled }}</h2>
    </div>
   `,
  props: [
    'startCounter'
  ],
  computed: {
    countDoubled() {
      return this.startCounter * 2;
    }
  }
});

10 行

computed: {
  countDoubled() {
    return this.startCounter * 2;
  }
}

由原本的 innerCounter 改成 countDoubled()

第 2 行

template: `
  <div>
    <h2>{{ countDoubled }}</h2>
  </div>
`,

Data Binding 改成 countDoubled()

如此內層 component 的 data 就與外層同步

2 種寫法都各有適用場景,視需求決定要使用

Conclusion

  • 透過 prop,data 能由外層傳進 Component
  • Dynamic Prop 能將 MVVM 的 model 也綁定 prop,不再只是寫死的資料
  • Prop 只支援 Unidirectional Dataflow,也就是外層的 data 改變,會影響到內層 component,但內層 component 的 data 改變,不會影響到外層 component
  • 若要內層 component 的 data 改變,會影響到外層 component,就必須使用 event

Sample Code

完整的範例可以在我的 GitHub 上找到

Reference

Vue , Props


以上所述就是小编给大家介绍的《Vue Component 之 Prop》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

格蠹汇编

格蠹汇编

张银奎 / 电子工业出版社 / 2013-3-1 / 66.00元

《格蠹汇编——软件调试案例集锦》以案例形式讨论了使用调试技术解决复杂软件问题的工具和方法。全书共36章,分为四篇。前两篇每章讲述一个有代表性的真实案例,包括从堆里抢救丢失的博客,修复因误杀而瘫痪的系统,徒手战木马,拯救“发疯”的windows7,经典阅读器的经典死锁,拯救挂死的powerpoint,转储分析之双误谜团,是谁动了我的句柄,寻找系统中的“耗电大王”,解救即将被断网的系统,转储分析之系统......一起来看看 《格蠹汇编》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换