組件

1.使用組件

//組件命名規(guī)則:全小寫-分隔(kebab-case)
//注冊一個全局組件
Vue.component('my-component', {});
//注冊一個局部組件
new Vue({
    components:{
        'my-component':{}
    }
});
<table>
    <!-- ul,ol,table,select標簽限制了被包裹元素的類型,如果使用自定義組件會有問題 -->
    <!-- my-row></my-row -->
    <!-- 變通方案使用is屬性 -->
    <tr is="my-row"></tr>
</table>

為什么component的data被設計為一個函數(shù)?
嘻嘻...你猜...

2.父子組件通信

父組件通過props向下傳遞數(shù)據(jù)給子組件,子組件通過events給父組件發(fā)送消息

組件實例作用域是孤立的,不應該在子組件內(nèi)部直接引用父組件數(shù)據(jù),應該通過props選項訪問

<!-- myMessage屬性camelCase在html中要寫成kebab-case -->
<!-- my-message綁定靜態(tài)字符串 -->
<my-component my-message="hello"></my-component>
<!-- :my-message動態(tài)綁定父組件變量,當父組件數(shù)據(jù)變化,會傳導給子組件 -->
<my-component :my-message="message"></my-component>
Vue.component('my-component', {
    props:['myMessage'],
    template:'<span>{{myMessage}}</span>'
});

var app = new Vue({
    el: "#app",
    data:{
        message:"from parent"
    }
});

props是單向綁定,父組件屬性變化會傳到給子組件,但不會反過來,不應該在子組件內(nèi)部直接改變prop值

<my-component :init="init" :size="size"></my-component>
Vue.component('my-component', {
    props: ['init', 'size'],
    template: '<span>{{myInit}}{{mySize}}</span>',
    //組件內(nèi)部改變prop的2種方案:
    //1.prop作為值初始值傳入,賦值給組件局部變量
    data: function () {
        return {myInit: this.init}
    },
    //2.prop作為初始值傳入,由組件處理為其他數(shù)據(jù)輸出
    computed: {
        mySize: function () {
            return this.size.toLowerCase();
        }
    }
});

var app = new Vue({
    el: "#app",
    data: {
        init: 0,
        size: "six"
    }
});

props如果是引用類型,在子組件內(nèi)部改變其屬性會影響父組件

可為組件props指定驗證規(guī)則

<my-component :pro-a="proA" :pro-b="proB" :pro-c="proC" :pro-d="proD"></my-component>
Vue.component('my-component', {
    props: {
        //String,Number,Boolean,Function,Object,Array,Symbol,null(任意類型)
        proA: Number,
        //多種類型
        proB: [String, Number],
        proC: {
            type: String,
            //設置默認值
            default: "66",
            //設置必填驗證
            required: true
        },
        proD: {
            type: Number,
            //自定義默認值
            default: function () {
                return 6;
            },
            //自定義驗證規(guī)則
            validator: function (value) {
                return value >= 6;
            }
        }
    },
    template: '<span></span>'
});

var app = new Vue({
    el: "#app",
    data: {
        //報錯
        proA: "6",
        //報錯
        proB: [],
        //報錯
        proC: null,
        //報錯
        proD: 5
    }
});

3.自定義事件

子組件通過自定義事件系統(tǒng)于父組件通信

  • $on(eventName)監(jiān)聽事件
  • $emit(eventName)觸發(fā)事件
<!-- 父組件可直接使用v-on監(jiān)聽子組件觸發(fā)的自定義事件 -->
<my-button @myevent="addTotal"></my-button>
<!-- 父組件監(jiān)聽子組件根元素上的原生事件,使用.native修飾符 -->
<my-button @click.native="addTotal"></my-button>
Vue.component('my-button', {
    template: '<button @click="addCount">{{count}}</button>',
    data: function () {
        return {
            count: 0
        }
    },
    methods: {
        addCount: function () {
            this.count++;
            //觸發(fā)自定義事件
            this.$emit('myevent');
        }
    }
});

var app = new Vue({
    el: "#app",
    data: {
        total: 0
    },
    methods: {
        addTotal: function () {
            this.total++;
        }
    }
});

v-model語法糖實際會轉(zhuǎn)化為::value="value" @input="value=$event.target.value",因此,自定義事件可以用來創(chuàng)建自定義表單輸入組件,使用v-model實現(xiàn)數(shù)據(jù)雙向綁定

{{currency}}
<!--my-currency :value="currency" @input="currency = $event.target.value"></my-currency-->
<my-currency v-model="currency"></my-currency>
Vue.component('my-currency', {
    props: ["value"],
    template: '<div><input ref="myInput" :value="value" @input="updateValue"/></div>',
    methods: {
        updateValue: function (event) {
            var currency = "$" + event.target.value.replace(/\$/g, "");
            this.$refs.myInput.value = currency;
            //觸發(fā)input事件
            this.$emit('input', currency);
        }
    }
});

var app = new Vue({
    el: "#app",
    data: {
        currency: "0"
    }
});

可定制組件的v-model的prop和event,避免沖突

{{currency}}
<!--my-currency :myvalue="currency" @myinput="currency = $event.target.value"></my-currency-->
<my-currency v-model="currency" value="hello"></my-currency>
Vue.component('my-currency', {
    //可定制v-model
    model: {
        prop: 'myvalue',
        event: 'myinput'
    },
    //釋放value屬性
    props: ['myvalue', 'value'],
    template: '<div><input ref="myInput" :value="myvalue" @input="updateValue"/></div>',
    methods: {
        updateValue: function (event) {
            var currency = "$" + event.target.value.replace(/\$/g, "");
            this.$refs.myInput.value = currency;
            //觸發(fā)myinput事件
            this.$emit('myinput', currency);
        }
    }
});

var app = new Vue({
    el: "#app",
    data: {
        currency: "0"
    }
});

非父子組件通信,簡單場景使用一個空Vue實例做事件中轉(zhuǎn),復雜情況請考慮狀態(tài)管理模式

var bus = new Vue();
bus.$emit('my-event', 6);
bus.$on('my-event', function(arg){});

4.使用Slots分發(fā)內(nèi)容

slots標簽讓組件內(nèi)容可以混合嵌套,類似Angular的transclusion

<!-- 最終生成html -->
<!--div>
    <h1>child</h1>
    <div>parent content</div>
</div-->
<my-component>
    <div>parent content</div>
</my-component>
Vue.component('my-component', {
    template: '<div><h1>child</h1><slot></slot></div>'
});

為slot指定name來配置如何分發(fā)內(nèi)容

<!-- 最終生成html -->
<!--div>
    <h1>header</h1>
    <p>footer</p>
</div-->
<my-layout>
    <h1 slot="header">header</h1>
    <p slot="footer">footer</p>
</my-layout>
Vue.component('my-layout', {
    template: '<div><slot name="header"></slot><slot name="footer"></slot></div>'
});

作用域插槽,暴露數(shù)據(jù),允許父組件自定義渲染

<my-list :items="items">
    <!-- template表示作用域插槽模板,scope為一臨時變量,來至子組件 -->
    <template slot="listItem" scope="props">
        <!-- 自定義渲染 -->
        <li>{{props.text}}</li>
    </template>
</my-list>
Vue.component('my-list', {
    props: ['items'],
    template: '<ul><slot name="listItem" v-for="item in items" :text="item"></slot></ul>'
});

var app = new Vue({
    el: "#app",
    data: {
        items: ["1", "2"]
    }
});

5.動態(tài)組件

通過<component>元素,動態(tài)綁定is特性,可使用同一個掛載點,動態(tài)切換組件

<component :is="currentView"></component>
<!-- keep-alive保留切換出去的組件在內(nèi)存,避免重新渲染 -->
<keep-alive>
    <component :is="currentView"></component>
</keep-alive>
<button @click="change">change</button>
var myHeader = {
    template: '<h1>Header</h1>'
};

var myFooter = {
    template: '<div>Footer</div>'
};

var myText = {
    template: '<input type="text"/>'
};

var app = new Vue({
    el: "#app",
    data: {
        //currentView: myHeader
        currentView: 'myFooter'
    },
    components: {
        myFooter: myFooter,
        myText: myText
    },
    methods: {
        change: function () {
            this.currentView = (this.currentView == 'myText' ? 'myFooter' : 'myText');
        }
    }
});

6.雜項

組件分3部分:

  • props允許外部傳遞數(shù)據(jù)給組件
  • events允許外部和組件內(nèi)部通信
  • slots允許外部自定義內(nèi)容渲染到組件中

子組件索引

<!-- ref為子組件指定索引,用來在javascript中直接訪問子組件 -->
<my-component ref="my"></my-component>
Vue.component('my-component', {
    data: function () {
        return {name: "66"};
    },
    template: '<div>66</div>'
});

var app = new Vue({
    el: "#app"
});

//通過實例屬性$refs訪問子組件
app.$refs.my.name;

異步組件
將應用拆分多個小模塊,按需從服務器下載,Vue允許將組件定義為一個工廠函數(shù),動態(tài)解析,建議配合Webpack異步加載功能食用

<async-component></async-component>
Vue.component('async-component', function (resolve, reject) {
    //模擬異步網(wǎng)絡請求
    setTimeout(function () {
        //調(diào)用porime模式resolve方法表示成功返回異步組件
        resolve({template: '<div>async</div>'});
    }, 1000);
});

var app = new Vue({
    el: "#app"
});

組件命名約定
注冊組件(或props)使用kebab-case,camelCase,PascalCase,HTML模板中只能使用kebab-case

遞歸組件
設置了name選項,組件才可以遞歸調(diào)用自己

<my-component :tree="tree"></my-component>
Vue.component('my-component', {
    props: ['tree'],
    name: 'component',
    template: '<div>' +
    '<div v-if="tree instanceof Array">' +
    '<component :tree="item" v-for="item in tree"></component>' +
    '</div>' +
    '<div v-else>{{tree}}</div>' +
    '</div>'
});

var app = new Vue({
    el: "#app",
    data: {
        tree: [[1, 2], 3]
    }
});

要保證遞歸調(diào)用有終止條件(如v-if最終返回false),否則可能出現(xiàn)死循環(huán)

組件循環(huán)引用
A引用B,B中也引用A,使用Vue.component注冊的全局組件,框架會自動解決依賴組件的矛盾

X-Templates

<my-component></my-component>

<script type="text/x-template" id="my-component">
    <div>hello</div>
</script>
Vue.component('my-component', {
    template: '#my-component'
});

低開銷靜態(tài)組件使用v-once,緩存渲染結(jié)果

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

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

  • 此文基于官方文檔,里面部分例子有改動,加上了一些自己的理解 什么是組件? 組件(Component)是 Vue.j...
    陸志均閱讀 3,949評論 5 14
  • Vue.js 是一套構(gòu)建用戶界面的漸進式框架。我們可以使用簡單的 API 來實現(xiàn)響應式的數(shù)據(jù)綁定和組合的視圖組件。...
    前端小透明閱讀 8,489評論 10 54
  • 9.1 什么是組件? 組件(Component)是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,...
    白水螺絲閱讀 888評論 0 2
  • 序 今年大前端的概念一而再再而三的被提及,那么大前端時代究竟是什么呢?大前端這個詞最早是因為在阿里內(nèi)部有很多前端開...
    一縷殤流化隱半邊冰霜閱讀 11,374評論 19 92
  • 什么是組件 組件(Component)是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝可重用...
    angelwgh閱讀 819評論 0 0

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