Vue.js,學(xué)習(xí)心得(十二)組件二

學(xué)習(xí)心得,
組件(二),

直接上代碼了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Prop</title>
    <script src="../js/vue.js"></script>
</head>
<body>
<div id="app-1">
    <div is="child1" message="HI~~Vue.js"></div>
</div>
<hr>

<div id="app-2">
    <!-- 在 HTML 中使用 kebab-case -->
    <div is="child2" my-message="Hello~~2"></div>
</div>
<hr>

<div id="app-3">
    <input v-model="parentMsg">
    <br>
    <div is="child3" v-bind:my-message="parentMsg" v-bind="todo"></div>

</div>
<hr>

<!--字面量語(yǔ)法 vs 動(dòng)態(tài)語(yǔ)法-->

<!--初學(xué)者常犯的一個(gè)錯(cuò)誤是使用字面量語(yǔ)法傳遞數(shù)值:-->
<!--&lt;!&ndash; 傳遞了一個(gè)字符串 "1" &ndash;&gt;-->
<!--<comp some-prop="1"></comp>-->
<!--因?yàn)樗且粋€(gè)字面量 prop,它的值是字符串 "1" 而不是一個(gè)數(shù)值。如果想傳遞一個(gè)真正的 JavaScript 數(shù)值,則需要使用 v-bind,從而讓它的值被當(dāng)作 JavaScript 表達(dá)式計(jì)算:-->
<!--&lt;!&ndash; 傳遞真正的數(shù)值 &ndash;&gt;-->
<!--<comp v-bind:some-prop="1"></comp>-->



<!--非 Prop 特性-->

<!--所謂非 prop 特性,就是指它可以直接傳入組件,而不需要定義相應(yīng)的 prop。-->
<!--盡管為組件定義明確的 prop 是推薦的傳參方式,組件的作者卻并不總能預(yù)見(jiàn)到組件被使用的場(chǎng)景。-->
<!--所以,組件可以接收任意傳入的特性,這些特性都會(huì)被添加到組件的根元素上。-->
<!--例如,假設(shè)我們使用了第三方組件 bs-date-input,它包含一個(gè) Bootstrap 插件,該插件需要在 input 上添加 data-3d-date-picker 這個(gè)特性。-->
<!--這時(shí)可以把特性直接添加到組件上 (不需要事先定義 prop):-->
<!--<bs-date-input data-3d-date-picker="true"></bs-date-input>-->
<!--添加屬性 data-3d-date-picker="true" 之后,它會(huì)被自動(dòng)添加到 bs-date-input 的根元素上。-->

<div id="app-4">
    <span is="bs-date-input" data-3d-date-picker="true" class="date-picker-theme-dark"></span>
</div>
<hr>

<div id="app-5">
    <p>{{totals}}</p>
    <button-counter v-on:increments="incrementTotals"></button-counter>
    <button-counter v-on:increments="incrementTotals"></button-counter>
</div>
<hr>


    <!--.sync 修飾符-->
    <!--<comp :foo.sync="bar"></comp>-->





<!--使用自定義事件的表單輸入組件-->

<!--自定義事件可以用來(lái)創(chuàng)建自定義的表單輸入組件,使用 v-model 來(lái)進(jìn)行數(shù)據(jù)雙向綁定。要牢記:-->

<!--<input v-model="something">-->

<!--這不過(guò)是以下示例的語(yǔ)法糖:-->
<!--<input-->
        <!--v-bind:value="something"-->
        <!--v-on:input="something = $event.target.value">-->
<!--所以在組件中使用時(shí),它相當(dāng)于下面的簡(jiǎn)寫:-->
<!--<custom-input-->
        <!--v-bind:value="something"-->
        <!--v-on:input="something = arguments[0]">-->
<!--</custom-input>-->



<div id="app-6">
    <currency-input v-model="price"></currency-input>
</div>
<hr>





<div id="app-7">
    <my-checkbox v-model="foo" value="some value"></my-checkbox>
</div>
<hr>




<script>
    //使用Prop傳遞數(shù)據(jù)
    //組件實(shí)例的作用域是孤立的。
    //這意味著不能 (也不應(yīng)該) 在子組件的模板內(nèi)直接引用父組件的數(shù)據(jù)。
    //父組件的數(shù)據(jù)需要通過(guò) prop 才能下發(fā)到子組件中。
    //子組件要顯式的用props選項(xiàng)聲明它預(yù)期的數(shù)據(jù):
    Vue.component('child1',{
        //聲明 props
        props:['message'],
        //就像data一樣,prop也可以用在模板中使用
        //同樣也可以在 vm 實(shí)例中通過(guò) this.message 來(lái)使用
        template:'<span>{{message}}</span>'
    });
    var app1 = new Vue({
        el:"#app-1"
    });

    //    camelCase vs. kebab-case
    //
    //    HTML 特性是不區(qū)分大小寫的。
    //    所以,當(dāng)使用的不是字符串模板時(shí),camelCase (駝峰式命名) 的 prop 需要轉(zhuǎn)換為相對(duì)應(yīng)的 kebab-case (短橫線分隔式命名):
    Vue.component('child2',{
        // 在 JavaScript 中使用 camelCase
        props:['myMessage'],
        template:'<span>{{myMessage}}</span>'
    });
    var app2 = new Vue({
        el:"#app-2"
    });

    //動(dòng)態(tài)Prop
    //與綁定到任何普通的 HTML 特性相類似,
    // 我們可以用 v-bind 來(lái)動(dòng)態(tài)地將 prop 綁定到父組件的數(shù)據(jù)。
    // 每當(dāng)父組件的數(shù)據(jù)變化時(shí),該變化也會(huì)傳導(dǎo)給子組件:

    //    如果你想把一個(gè)對(duì)象的所有屬性作為 prop 進(jìn)行傳遞,
    //    可以使用不帶任何參數(shù)的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。
    //    例如,已知一個(gè) todo 對(duì)象:

    var app3 = new Vue({
        el:"#app-3",
        data:{
            parentMsg:'',
            todo:{
                text:'Learn Vue',
                isComplete:false
            }
        },
        components:{
            child3:{
                props:['myMessage','text'],
                template:'<span>{{myMessage}},{{text}}</span>'
            }
        }
    });

    //單項(xiàng)數(shù)據(jù)流
    //    Prop 是單向綁定的:當(dāng)父組件的屬性變化時(shí),將傳導(dǎo)給子組件,但是反過(guò)來(lái)不會(huì)。
    //    這是為了防止子組件無(wú)意間修改了父組件的狀態(tài),來(lái)避免應(yīng)用的數(shù)據(jù)流變得難以理解。
    //另外,每次父組件更新時(shí),子組件的所有 prop 都會(huì)更新為最新值。
    //    這意味著你不應(yīng)該在子組件內(nèi)部改變 prop。如果你這么做了,Vue 會(huì)在控制臺(tái)給出警告。
    //在兩種情況下,我們很容易忍不住想去修改 prop 中數(shù)據(jù):
    //Prop 作為初始值傳入后,子組件想把它當(dāng)作局部數(shù)據(jù)來(lái)用;
    //Prop 作為原始數(shù)據(jù)傳入,由子組件處理成其它數(shù)據(jù)輸出。
    //對(duì)這兩種情況,正確的應(yīng)對(duì)方式是:
    //1.定義一個(gè)局部變量,并用 prop 的值初始化它:
    //    props: ['initialCounter'],
    //        data: function () {
    //        return { counter: this.initialCounter }
    //    }

    //    2.定義一個(gè)計(jì)算屬性,處理 prop 的值并返回:
    //props: ['size'],
    //    computed: {
    //        normalizedSize: function () {
    //            return this.size.trim().toLowerCase()
    //        }
    //    }
    //    注意在 JavaScript 中對(duì)象和數(shù)組是引用類型,指向同一個(gè)內(nèi)存空間,
    // 如果 prop 是一個(gè)對(duì)象或數(shù)組,在子組件內(nèi)部改變它會(huì)影響父組件的狀態(tài)。

    //Prop驗(yàn)證
    //我們可以為組件的 prop 指定驗(yàn)證規(guī)則。
    //如果傳入的數(shù)據(jù)不符合要求,Vue 會(huì)發(fā)出警告。
    //這對(duì)于開(kāi)發(fā)給他人使用的組件非常有用。
    //要指定驗(yàn)證規(guī)則,需要用對(duì)象的形式來(lái)定義 prop,而不能用字符串?dāng)?shù)組:


    Vue.component('child3',{
        props:{
            //基礎(chǔ)類型檢測(cè)('null',指允許任何類型)
            propA: Number,
            //可能是多種類型
            propB: [String, Number],
            //必傳且是字符串
            propC:{
                type:String,
                required:true
            },
            //數(shù)值且有默認(rèn)值
            propD:{
                type:'Number',
                default:100
            },
            //數(shù)組/對(duì)象的默認(rèn)值應(yīng)當(dāng)由一個(gè)工廠函數(shù)返回
            propE:{
                type:'Object',
                defalut:function(){
                    return {message:'hello'}
                }
            },
            //自定義驗(yàn)證函數(shù)
            propF:{
                validator:function(value){
                    return value > 10
                }
            }

        }
    });
    //    type 可以是下面原生構(gòu)造器:
    //    String
    //    Number
    //    Boolean
    //    Function
    //    Object
    //    Array
    //    Symbol
    //    type 也可以是一個(gè)自定義構(gòu)造器函數(shù),使用 instanceof 檢測(cè)。
    //    當(dāng) prop 驗(yàn)證失敗,Vue 會(huì)拋出警告 (如果使用的是開(kāi)發(fā)版本)。
    //    注意 prop 會(huì)在組件實(shí)例創(chuàng)建之前進(jìn)行校驗(yàn),
    //    所以在 default 或 validator 函數(shù)里,諸如 data、computed 或 methods 等實(shí)例屬性還無(wú)法使用。

    //非Prop特性

    //替換/合并現(xiàn)有的特性
    Vue.component('bs-date-input',{
        template:'<input type="date" class="form-control">'
    });
    var app4 = new Vue({
        el:"#app-4"
    });

    //自定義事件
    //    我們知道,父組件使用 prop 傳遞數(shù)據(jù)給子組件。但子組件怎么跟父組件通信呢?這個(gè)時(shí)候 Vue 的自定義事件系統(tǒng)就派得上用場(chǎng)了。
    //    使用 v-on 綁定自定義事件
    //
    //    每個(gè) Vue 實(shí)例都實(shí)現(xiàn)了事件接口,即:
    //    使用 $on(eventName) 監(jiān)聽(tīng)事件
    //    使用 $emit(eventName) 觸發(fā)事件
    //    Vue 的事件系統(tǒng)與瀏覽器的 EventTarget API 有所不同。
    //    盡管它們的運(yùn)行起來(lái)類似,但是 $on 和 $emit 并不是addEventListener 和 dispatchEvent 的別名。
    //
    //    另外,父組件可以在使用子組件的地方直接用 v-on 來(lái)監(jiān)聽(tīng)子組件觸發(fā)的事件。
    //    不能用 $on 偵聽(tīng)子組件釋放的事件,而必須在模板里直接用 v-on 綁定,參見(jiàn)下面的例子。

    //聲明是子組件,調(diào)用是父組件

    Vue.component('button-counter',{
        template:'<button v-on:click="incrementTotals">{{counter}}</button>',
        data:function(){
            return {
                counter:0
            }
        },
        methods:{
            incrementTotals:function () {
                this.counter += 1;
                this.$emit("increments");
            }
        }
    });

    var app5 = new Vue({
        el:"#app-5",
        data:{
            totals:0
        },
        methods:{
            incrementTotals:function () {
                this.totals +=1 ;
            }
        }
    });
    //    給組件綁定原生事件
    //
    //    有時(shí)候,你可能想在某個(gè)組件的根元素上監(jiān)聽(tīng)一個(gè)原生事件。
    // 可以使用 v-on 的修飾符 .native。例如:



    //所以要讓組件的 v-model 生效,它應(yīng)該 (從 2.2.0 起是可配置的):
    //接受一個(gè) value prop
    //    在有新的值時(shí)觸發(fā) input 事件并將新值作為參數(shù)
    //    我們來(lái)看一個(gè)非常簡(jiǎn)單的貨幣輸入的自定義控件:

    Vue.component('currency-input',{
        template:'<span>$' +
        '<input ref="inputr" v-bind:value="value" v-on:input="updateValue($event.target.value)">' +
        '</span>',
        props:['value'],
        methods:{
            //不是直接更新,而是使用此方法來(lái)對(duì)輸入值進(jìn)行改格式化和位數(shù)限制
            updateValue:function(value){
                var formattedValue = value
                //刪除兩側(cè)的空格符
                    .trim()
                //保留2位小數(shù)
                    .slice(
                        0,
                        value.indexOf('.') === -1
                        ? value.length
                            :value.indexOf('.') + 3
                    )
                //如果值上不合規(guī),則手動(dòng)覆蓋為合規(guī)的值
                if(formattedValue !== value){
                    this.$refs.inputr.value = formattedValue;
                }
                //通過(guò)input 事件帶出數(shù)值
                this.$emit('input', Number(formattedValue));

            }
        }
    });

    var app6 = new Vue({
        el:'#app-6',
        data:{
            price:''
        }
        //為什么price寫在這里,哪里用到了v-model="price" ??
    });



//    自定義組件的 v-model
//    默認(rèn)情況下,一個(gè)組件的 v-model 會(huì)使用 value prop 和 input 事件。
//    但是諸如單選框、復(fù)選框之類的輸入類型可能把 value 用作了別的目的。
//    model 選項(xiàng)可以避免這樣的沖突:


    Vue.component('my-checkbox',{
        template:'<input type="checkbox">',
        model:{
            prop:'checked',
            event:'checked'
        },
        props:{
            checked:Boolean,
            value:String
        }
    });


    var app7 = new Vue({
        el:'#app-7',
        data:{
            foo:''
        }
        //    沒(méi)調(diào)通,看不明白
    });


//    非父子組件的通信
//
//    有時(shí)候,非父子關(guān)系的兩個(gè)組件之間也需要通信。
    // 在簡(jiǎn)單的場(chǎng)景下,可以使用一個(gè)空的 Vue 實(shí)例作為事件總線:

    var bus = new Vue();

    //觸發(fā)組件A中的事件
    bus.$emit('id-selected',1);

    //在組件B創(chuàng)建的鉤子中監(jiān)聽(tīng)事件
    bus.$on('id-selected',function(id){
        //...
    })


//    使用插槽分發(fā)內(nèi)容




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

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

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