VUE從入門到入坑—05.自定義局部|全局組件 / 自定義事件$emit


上篇:VUE從入門到入坑—04.v-model指令 / 事件綁定指令 / 修飾符 / 深度響應式

一、什么是組件

組件就是零件,將零件組裝成想要的工具(頁面),組件是vue.js最強大的功能之一,它可以擴展html元素,封裝可重用的代碼,通過傳入對象的不同,實現(xiàn)組件的復用。

1.定義全局組件
全局組件:使用Vue.component來創(chuàng)建全局組件,可以用在創(chuàng)建的 Vue 根實例 (new Vue) 的模板中,任何方式,任何地點都可以使用的標簽組件。

Vue.component('mx-box', {
       template:`
       <div>
           <h1>標題</h1>
       </div>
       `,
       props:{ },
       data() {
           return { }
       }           
})
new Vue({ el: '#app' })
<div id="app">
     <mx-box> </mx-box>
</div>

2.定義局部組件

只能在定義它的el中使用,不能在其他位置,否則就會失效。

new Vue({
  el: '#app',
  components: {
       // 自定義組件名
       'mx-box': {
         template:`
         <div>
             <p> hello </p>
         </div>
         `,
         props:{ },
         data() {
             return { }
         }       
       }
  }
})
<div id="app">
     <mx-box> </mx-box>
</div>

(1)components選項中定義局部組件。每個組件就是一個小型的Vue實例,它里面除了不能設置el選項,其他選項它都有。
(2)組件名稱:自定義,可以使用駝峰命名方式或者短橫線的命名方式,但是需要注意的是如果應用到DOM中,就只能用短橫線命名的方式,否則就會報錯。注意組件的名稱不要跟原生html元素重名。
(3)template選項:定義組件的模板。模板中必須包含一個根標簽。
(4)props選項:定義組件標簽上的屬性。駝峰命名法的 prop 名(postTitle)需要使用其等價的短橫線分隔命名法(post-title)命名。注意:props是只讀的,不能修改(解決辦法:在data中對props接收到的數(shù)據(jù)進行中轉)。
(5)props的值可以是一個字符串數(shù)組,里面定義每一個標簽屬性名稱,這是簡單用法,不能對屬性做嚴格的驗證。例如:props:["count"]。
(6)props的值可以是一個對象,里面定義每個標簽屬性名稱,以及對應的類型。例如:props:{ count:Number }。
(7)props的值可以是一個對象,里面定義的每個標簽屬性名稱也可以是一個對象,在這個對象里面定義該屬性的完整信息。type 定義類型,required 非空,default 默認值。例如:props: {count: { type: Number, required: true, default: 1 } }
(8)data:定義組件的數(shù)據(jù)。注意:Vue實例的data選項可以是一個對象,也可以是一個方法,由該方法返回一個對象。 但是在組件中,data選項必須是一個方法,由該方法返回一個對象。因為組件可能會使用很多次,如果data選項是對象的話,會導致多個組件使用了同一份數(shù)據(jù)。

二、全局組件和局部組件的區(qū)別

全局:可以再頁面中任何位置使用。
局部:只能在定義它的el中使用,不能在其他位置,否則就會失效。
定義方法
全局:可以使用Vue.component(tagName,options)定義。
局部:可以通過Vue實例中component屬性定義局部組件。
是否掛載:全局組件在擴展元素用于封裝復用代碼時不需要掛載,但是不常見,因為會影響瀏覽器的性能 局部組件必須手動掛載,否則會失效。
其他 局部組件中代碼的編寫是”components“,而全局組件中是”component“ 。

三、$emit()自定義事件

Vue為每個組件對象提供了一個內(nèi)置方法:$emit,作用:子組件向父組件傳值,觸發(fā)自定義事件,注意:事件名稱中不能采用大寫字母。

// 觸發(fā)一個自定義事件,事件名稱是synccount,將val作為事件對象傳出去
this.$emit('synccount',val)
<mx-box @synccount="synccount(doSomething)"> </mx-box>

四、練習,counter組件

    <div id="app">
        <ul class="list">
            <li v-for="(item,index) in list" :key="index">{{item.label}}--{{item.count}}</li>
        </ul>
        <b-counter v-for="(item,index) in list" :key="index" :label="item.label" :count="item.count"
            @synccount="synccount(index,$event)"></b-counter>
    </div>
        new Vue({
            el: '#app',
            // 定義數(shù)據(jù)
            data: {
                list: [
                    {  label: '衣服',count: 5  },
                    {  label: '褲子',count: 8  },
                    {  label: '鞋子',count: 3  },
                    {  label: '襪子',count: 10  }
                ]
            },
            methods: {
                synccount(index, e) {
                    // 同步更新商品的數(shù)量
                    this.list[index].count = e
                }
            },
            // 注冊組件
            components: {
                'b-counter': {
                    template: `
                    <div class="counter">
                        <div class="label">{{label}}</div>
                        <div class="btns">
                            <button @click="myCount--" :disabled="myCount===minCount">-</button>
                            <input readonly class="text" type="text" :value="myCount">
                            <button @click="myCount++" :disabled="myCount===maxCount">+</button>
                        </div>
                    </div>
                    `,
                    //props選項
                    props: {
                        // 文本
                        label: {
                            type: String,
                            // 允許為空
                            required: false,
                        },
                        // 數(shù)量
                        count: {
                            type: Number,
                            // 非空
                            required: true
                        },
                        // 最大值
                        maxCount: {
                            type: Number,
                            default: 999
                        },
                        // 最小值
                        minCount: {
                            type: Number,
                            default: 1
                        }
                    },
                    //定義數(shù)據(jù)
                    data() {
                        return {
                            // 將props接收到的count,中轉給myCount
                            myCount: this.count
                        }
                    },
                    // 監(jiān)聽器
                    watch: {
                        // 偵聽myCount是否發(fā)生變化
                        myCount(val) {
                            // 觸發(fā)一個自定義事件synccount,將count的最新值作為事件對象傳出去
                            this.$emit('synccount', val)
                        }
                    }
                }
            }
        })

效果:

五、練習,評分組件

    <div id="app">
        <ul class="list">
            <li v-for="(item,index) in list" :key="index">{{item.title}}--{{item.value}}</li>
        </ul>
        <b-star v-for="(item,index) in list" :key="index" 
        :title="item.title" :value="item.value" @syncvalue="syncvalue(index,$event)"></b-star>
    </div>
        // 注冊全局組件
        Vue.component('b-star', {
            //模板
            template:`
            <div class="star">
                <div class="title">{{title}}</div>
                <div>
                    <i v-for="item in 10" :key="item" class="iconfont" 
                    :class="item<=myValue?'icon-xingxing':'icon-star'"
                    @mouseenter="enter(item)" @mouseleave="leave(item)" @click="okValue=item"></i>
                </div>
            </div>
            `,
            // 定義組件的標簽屬性
            props:{
                title:{
                    type:String,
                    required:false
                },
                value:{
                    type:Number,
                    default:0
                }
            },
            // 數(shù)據(jù)
            data() {
                return {
                    // 中轉props傳進來的value值
                    myValue:this.value,
                    // 定義一個確定值
                    okValue:this.value
                }
            },
            // 方法
            methods: {
               // 鼠標進入時,調(diào)用的方法
                enter(val){
                    this.myValue = val
                },
               // 鼠標離開時,調(diào)用的方法
                leave(val){
                    this.myValue = this.okValue
                }
            },
            // 監(jiān)聽器
            watch:{
                // 偵聽okValue的變化
                okValue(val){
                    // 觸發(fā)自定義事件
                    this.$emit('syncvalue',val)
                }
            }
        })
        new Vue({
            el:'#app',
            data:{
                list:[
                    {
                        title:'產(chǎn)品質量',
                        value:5
                    },
                    {
                        title:'物流速度',
                        value:7
                    },
                    {
                        title:'客服態(tài)度',
                        value:2
                    }
                ]
            },
            methods: {
                // 同步評分
                syncvalue(index,e){
                    this.list[index].value = e
                }
            },
        })

效果:

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

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容