iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
0
自我挑戰組

跟 VueJS 認識的30天系列 第 10 篇

[DAY10]跟 Vue.js 認識的30天 - Vue 的基本模組(`component`)概念

  • 分享至 

  • xImage
  •  

Vue 的模組 - component 作用

https://ithelp.ithome.com.tw/upload/images/20201013/2012755327dB0Zbdo6.png

Vue 的模組 component 是可以重複使用的 Vue 實例,所以也擁有 data、computed、watch、methods 以及生命周期鉤子等,目的是可以將網頁分割成不同區塊以便管理。

如何創建一個模組

這邊介紹的是全域註冊的模組,區域俟深入 component 時再行介紹。

註冊模組的寫法

Vue.component('註冊名稱',{模組內容})

component 內的 data 必須是函式

如果 component 內的 data 使用物件,就會出錯。

  • component 內的 data 使用物件,會出現錯誤提示 data 須使用 function。
    https://ithelp.ithome.com.tw/upload/images/20201013/20127553zCjAwv4TaQ.png

  • 並且會找不到錯誤的 data 裡的值。
    https://ithelp.ithome.com.tw/upload/images/20201013/20127553Oy3FlL8bLf.png

component 內的 data 須使用函式取得一個獨立的位址(重新賦值),不受其他物件的影響。

template 只能有一個根元素

如果在 component 的 template 裡有多個元素的話,就必須利用一個根元素將所有元素包裹起來,否則就會出錯。

https://ithelp.ithome.com.tw/upload/images/20201013/20127553Pu4PlPOMdg.png

錯誤寫法(沒有根元素或 data使用物件):

//template
<button type="button" @click="counter++">增加</button>
<p>counter:{{counter}}</p>

//data
data:{...}

應改成

//template
<div>
  <button type="button" @click="counter++">增加</button>
  <p>counter:{{counter}}</p>
</div>

//data
data(){return{}}

component 範例

// 單個元素
Vue.component("button-counter", {
  template: `
      <button type="button" @click="counter++">counter:{{counter}}</button>`,
  data(){
    return {
      counter: 0
    }
  }
})

// 多個元素
Vue.component("button-counter2", {
  template: `
    <div>
      <button type="button" @click="counter++">增加</button>
      <p>counter:{{counter}}</p>
    </div>`,
  data() {
    return {
      counter: 0
    };
  }
});

將模組應用在HTML文件中

每個被使用的模組都是一個新的 Vue 實例,也都擁有自己的 data、computed、watch、methods 以及生命周期鉤子等,不會互相干擾彼此的資料。

<div id="vm">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

傳送數據

https://ithelp.ithome.com.tw/upload/images/20201013/20127553hUCj7MkUPz.png

只要記得上到下(外到內)用 props ,下到上(內到外)用 $emit 就可以了。

props 向內層模組傳送資料

資料不是 component 本身自己擁有的,而是透過外層給予的時,就必須使用 props 來取得資料。

props 就是自定義的 HTML Attribute ,代表著必須要先定義(註冊)才能使用。

如何定義及使用 props:

定義props

將自定義的 HTML Attribute 註冊在 component 內的 props 中,例如下方的 plan 就是我定義的一個 HTML Attribute ,記得利用陣列註冊 HTML Attribute 的話,要使用字串註冊。

//定義
Vue.component("my-plan", {
  props:['plan']
});

設定 props 的值

在 component 內的 props 中註冊好自定義的 HTML 屬性後,就可以在 HTML 中使用該 component 的地方加入這個屬性並給予值,如下,加入 plan 屬性並給予值 go to market 。

<my-plan plan="go to market"></my-plan>

使用 props 的值

使用 props 的值跟使用 data 的方法相同,只不過 props 的值是從外面傳入的(就是在 HTML 中設定的值),如上在 HTML 中,給予 plan 的值就是 go to market ,所以可以把 props 當成另一類的 data 來使用。

Vue.component("my-plan", {
  props:['plan'],
  template: `
    <div>
      <p>{{counter}}</p>
      <p>{{plan}}</p>
    </div>`,
  data(){
    return {
      counter: 0
    }
  }
});

透過 v-bind 來傳遞 props 的值

如果 props 的值是從外層的 data 中產生的就必須使用 v-bind ,就如同之前所說把 props 當成一般的 HTML Attribute 看待,因此當該 Attribute 需要使用到 Vue 實例裡的資料時就必須使用 v-bind ,讓 Vue 知道這邊使用的資料不是單純的字串,而是 Vue 實例裡的 data 。

<my-plan v-for="plan of plans" :plan="plan" :key="plan"></my-plan>

<script>
Vue.component("my-plan", {
  props:['plan'],
  template: `
    <div>
      <p>{{plan}}</p>
    </div>`,
});

const vm = new Vue({
  el: "#vm",
  data:{
    plans:['go swimming','see a movie','study']
  }
});
</script>

$emit 向外層模組傳送資料

在模組內觸發了某個事件,再透過 $emit 傳送自定義的事件名稱到外層,最後透過這個自定義的事件去觸發外層的函式。

<p :style={fontSize:`${emitFontSize}em`}>使用 `$emit`</p>
<my-emit @large-text="emitFontSize+=0.1"></my-emit>

<script>
Vue.component("my-emit", {
  template: `
    <div>
      <button type="button" @click.prevent="$emit('large-text')">加大文字</button>
    </div>`
});
const vm = new Vue({
  el: "#vm",
  data:{
    emitFontSize:0.8
  }
});
</script>

https://ithelp.ithome.com.tw/upload/images/20201013/20127553PusEheZanQ.png

$emit 資料傳遞分為幾個階段:

  1. 在 component 內利用 v-on 監聽鍵盤、滑鼠或其他事件。
  2. 在鍵盤、滑鼠或其他事件發生後,觸發 $emit('自定義事件名稱') 事件到外層。
  3. 外層利用 v-on 監聽並觸發自定義事件名稱事件。
  4. 執行函式。

$emit 參數傳遞

利用 $event 取得參數值
<my-emit @large-text="emitFontSize+=$event"></my-emit>
<script>
Vue.component("my-emit", {
  template: `
    <div>
      <button type="button" @click.prevent="$emit('large-text', 0.2)">加大文字</button>
    </div>`
});
const vm = new Vue({
  el: "#vm",
  data:{
    emitFontSize:0.8
  }
});
</script>

外層使用 $event 即可取得 $emit 的第2個參數值。

https://ithelp.ithome.com.tw/upload/images/20201013/20127553BuAcM53VOi.png

利用函式取得參數值

自定義事件被觸發後,$emit('自定義事件', 參數2) 的第2個參數即會被當成引數帶入被執行的函式的參數。

<my-emit @large-text="enlargeText"></my-emit>
<script>
Vue.component("my-emit", {
  template: `
    <div>
      <button type="button" @click.prevent="$emit('large-text', 0.2)">加大文字</button>
    </div>`
});
const vm = new Vue({
  el: "#vm",
  data:{
    emitFontSize:0.8
  },
  methods:{
    enlargeText(amount){
      console.log(amount)
      this.emitFontSize += amount
    }
  }
});
</script>

如上,當自定義事件 large-text 被觸發後,就會執行函式 enlargeText ,而 $emit('large-text', 0.2) 中的 0.2 就會被代入到函式 enlargeText 的參數 amount 中。

利用 slot 傳送內容

在 component 中透過 <slot></slot> 把 HTML 中該 component 所包裹的值代入。

<my-slot>
  <p>Using slot</p>
</my-slot>
<script>
Vue.component("my-slot", {
  template: `
    <div>
      <slot></slot>
    </div>`
});
</script>

https://ithelp.ithome.com.tw/upload/images/20201013/20127553Sv30Ykxzup.png

Demo:[DAY10]跟 Vue.js 認識的30天 - Vue 的模組

參考文件:

Vue.js - 组件基础component

Vue.js Components Fundamentals

Yes


上一篇
[DAY09]跟 Vue.js 認識的30天 - Vue 的資料雙向綁定
下一篇
[DAY11]跟 Vue.js 認識的30天 - Vue 的模組註冊(`component`)
系列文
跟 VueJS 認識的30天 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言