[DAY10]跟 Vue.js 认识的30天 - Vue 的基本模组(`component`)概念

Vue 的模组 - component 作用

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

Vue 的模组 component 是可以重复使用的 Vue 实例,所以也拥有 datacomputedwatchmethods 以及生命周期钩子等,目的是可以将网页分割成不同区块以便管理。

如何创建一个模组

这边介绍的是全域注册的模组,区域俟深入 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 只能有一个根元素

如果在 componenttemplate 里有多个元素的话,就必须利用一个根元素将所有元素包裹起来,否则就会出错。

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 实例,也都拥有自己的 datacomputedwatchmethods 以及生命周期钩子等,不会互相干扰彼此的资料。

<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


<<:  Day 30 总结

>>:  [Day 最後一天]心得感想

鬼故事 - 天才小钓手

鬼故事 - 天才小钓手 credit: unknown 灵感来源: twitter - PyroBa...

Day 08:原则、设计模式、架构

前言 接下来要介绍的东西并不是学什麽工具, 而是怎麽把我们已经会的程序语言写得更有系统, 来达到高效...

Rust-所有权(二)

所有权与函式 将一个变数当作函式的参数传给其他函式,怎样安全的处理所有权 传递数值给函式这样的语义和...

Day 19 Flask Cookie

讲完前端之後,就一定要说到 Cookie 跟 Session 这两个东西了,这两个是什麽东西呢?又能...

学习 Hook( Day14 )

在截稿为止, React 最新的版本是 v17.0.2 ,而从 React 16.8.0 是第一个...