第4章 深入理解Vue組件

4-1 使用組件細節(jié)點

1.is的使用
當我們寫循環(huán)組件的時候,經(jīng)常給
table中的tr
select中的option
ul中的li或者ol中的li
等等定義組件的時候,我們經(jīng)常用is來定義組件的名稱,為了讓瀏覽器成功的渲染正確的dom結構

<div id="root">
    <table>
        <tbody>
        <tr is="row"></tr>
        <tr is="row"></tr>
        <tr is="row"></tr>
        </tbody>
    </table>
    <select name="" id="">
        <option is="selectOption"></option>
        <option is="selectOption"></option>
        <option is="selectOption"></option>
    </select>
    <ul>
        <li is="ulLi"></li>
        <li is="ulLi"></li>
        <li is="ulLi"></li>
    </ul>
</div>
<script>
    Vue.component('row', {
        template: '<tr><td>this is a row</td></tr>'
    });
    Vue.component('selectOption',{
        template: '<option>this is option</option>'
    });
    Vue.component('ulLi',{
        template: '<li>this is li</li>'
    });
    var app = new Vue({
        el: '#root',
        data: {},
    })
</script>

2.在子組件定義data的時候,必須是一個函數(shù),而不能是一個對象,返回一個對象是為了每個子組件都能擁有一個獨立的數(shù)據(jù)存儲。這樣子組件之間的數(shù)據(jù)不會互相影響
而在根組件中,data可以是一個對象。

<div id="root">
    <table>
        <tbody>
        <tr is="row"></tr>
        <tr is="row"></tr>
        <tr is="row"></tr>
        </tbody>
    </table>
</div>
<script>
    Vue.component('row', {
        data: function () {//返回的是一個函數(shù)
            return {
                content: 'this is row'
            }
        },
        template: '<tr><td>{{content}}</td></tr>'
    });
    var app = new Vue({
        el: '#root',
        data: {}
    })
</script>

3.有時候我們在開發(fā)過程中,因為一些業(yè)務的需求,少不了對dom的操作,那么我們就可以借助ref來實現(xiàn)

//實例一
<div id="root">
    <div ref="hello" @click="handleClick">hello world</div>
</div>
<script>
    var app = new Vue({
        el: '#root',
        data: {},
        methods: {
            handleClick: function () {
                console.log(this.$refs.hello.innerHTML);//通過refs屬性 獲取當前節(jié)點的文本
            }
        }
    });
</script>


//案例二 counter求和
<div id="root">
    <counter ref="one" @change="handleChange"></counter>
    <counter ref="two" @change="handleChange"></counter>
    <div>{{total}}</div>
</div>
<script>
    Vue.component('counter', {
        data: function () {
            return {
                number: 0
            }
        },
        template: '<div @click="handleClick">{{number}}</div>',
        methods: {
            handleClick: function () {
                this.number++;
                this.$emit('change');//觸發(fā)一個監(jiān)聽器
            }
        }
    });
    var app = new Vue({
        el: '#root',
        data: {
            total: 0
        },
        methods: {
            handleChange: function () {
                this.total = this.$refs.one.number + this.$refs.two.number //通過refs 來回去組件的值
            }
        }
    });
</script>
4-2父子組件之間的數(shù)據(jù)傳遞

父組件向子組件傳值:是通過屬性的方式
子組件向父組件傳值:可以通過$emit來觸發(fā)一個事件

vue數(shù)據(jù)傳遞遵循的是單向數(shù)據(jù)流,
所以在下面的案例中我們并沒有對content數(shù)據(jù)直接進行數(shù)據(jù)的累加,而是把content數(shù)據(jù)賦值給了number,對number進行數(shù)據(jù)的累加操作。

<div id="root">
    <counter :content="1" @inc="handleInc"></counter><!--父組件通過屬性向子組件傳值-->
    <counter :content="3" @inc="handleInc"></counter>
    <div>{{total}}</div>
</div>
<script>
    Vue.component('counter', {
        props: ['content'],
        data: function () {
            return {
                number: this.content //遵循單向數(shù)據(jù)流
            }
        },
        template: '<div @click="handleClick">{{number}}</div>',
        methods: {
            handleClick: function () {
                this.number += 2;
                //子組件通過方法向父組件傳值
                this.$emit('inc', 2);
            }
        }
    });
    var app = new Vue({
        el: '#root',
        data: {
            total: 4
        },
        methods: {
            handleInc: function (step) {
                this.total += step
            }
        }
    })
</script>
4-3組件參數(shù)校驗和非props特性

1.組件的的參數(shù)校驗

<div id="root">
    <child content="hello"></child>
</div>
<script>
    Vue.component('child', {
        props: {
            content: {
                type: String,
                required: true,
                default: 'default Value',
                validator: function (value) {
                    return (value.length > 5)
                }
            }
        },
        template: '<div>{{content}}</div>'
    });
    var app = new Vue({
        el: '#root',
    })
</script>

2.props特性和非props特性的對比
props特性:
父組件傳遞屬性,子組件要接受該屬性
props屬性不會顯示在dom的標簽之中
非props特性:
父組件傳遞屬性,子組件沒有去接受,而是直接調用
props屬性會顯示在dom的標簽之中

4-4給組件綁定原生事件

通過.native屬性來綁定原生事件

<div id="root">
    <child @click.native="handleClick"></child>
</div>
<script>
    Vue.component('child', {
        template: '<div>child</div>'
    })
    var app = new Vue({
        el: '#root',
        methods: {
            handleClick: function () {
                console.log('click');
            }
        }
    })
</script>
4-5 非父子組件間的傳值
非父子組件間的傳值

1.通過vuex
2.通過發(fā)布訂閱模式(Bus/總線/發(fā)布訂閱模式/觀察者模式/)

<div id="root">
    <child content="sunny"></child>
    <child content="fan"></child>
</div>
<script>
    Vue.prototype.bus = new Vue();//定義bus
    Vue.component('child', {
        data: function () {
            return {
                newContent: this.content //保證單向數(shù)據(jù)流
            }
        },
        props: {
            content: String
        },
        template: '<div @click="handleClick">{{newContent}}</div>',
        methods: {
            handleClick: function () {
                this.bus.$emit('change', this.newContent); //在bus上發(fā)布一個事件,并且傳值
            }
        },
        mounted: function () {//通過這個鉤子,來監(jiān)聽change的變化,通過回調拿到相對應的的值
            var that = this;
            this.bus.$on('change', function (msg) {
                console.log(msg)
                that.newContent = msg//this 指向發(fā)生變更,所以上面要從新獲取一下this的指向
            })
        }
    });
    var app = new Vue({
        el: '#root'
    })

4-6 在vue中使用插槽

插槽只能有一個
而劇名插槽可以有多個

  <div id="root">
    <body-content>
      <p slot="header">this is header</p>
      <p slot="footer">this is footer</p>
    </body-content>
  </div>
  <script>
    Vue.component('body-content',{
      template:
      `<div>
        <slot name="header">default header</slot> //設置默認值
        <p>this is content</p>
        <slot name="footer"></slot>
      </div>`
    })
    var app = new Vue({
      el:'#root'
    })
  </script>
4-7作用域插槽

父組件調用子組件的時候,給子組件傳了一個插槽,這個插槽是一個作用域的插槽,這個插槽必須是一個<template slot-scope="props">{{props.item}}</template>
那什么時候使用作用插槽呢?
1.當子組件做循環(huán)
2.或者當子組件的dom結構由外部傳遞進來,或者有外部決定的時候

<div id="root">
    <child>
      <template slot-scope="props">
        <li>{{props.item}}</li>
      </template>
    </child>
  </div>
  <script>
    Vue.component('child', {
      data: function () {
        return {
          list: [1, 2, 3, 4]
        }
      },
      template: `<div>
        <ul>
          <slot v-for="item of list" :item=item></slot>
        </ul>
      </div>`
    })
    var app = new Vue({
      el: '#root'
    })
  </script>

4-8 動態(tài)組件和v-once 指令
<div id="root">
    <component :is="type"></component> <!--這就是動態(tài)組件-->
    <child-one v-if="type==='child-one'"></child-one>
    <child-two v-if="type==='child-two'"></child-two>
    <button @click="hanleBtnClick">change</button>
  </div>
  <script>
    Vue.component('child-one', {
      template: '<div v-once>child-one</div>'
    })

    Vue.component('child-two', {
      template: '<div v-once>child-two</div>'
    })

    var app = new Vue({
      el: '#root',
      data: {
        type: 'child-one'
      },
      methods: {
        hanleBtnClick: function () {
          this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
        }
      }
    })
  </script>

更多

上一篇:第3章 Vue 基礎精講
下一篇:第5章 Vue 表單
全篇文章:Vue學習總結
所有章節(jié)目錄:Vue學習目錄

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容