vue 輕鬆上手_2

[TOC]javascript

VUE中的組件(component)

組件的特色:vue

  • 可複用
  • 方便維護
  • 每個vue組件都是一個獨立的個體(獨立的vm實例):DATA是獨立的(不一樣組件的DATA應該互不干擾),有完整的生命週期,方法等也是獨立的;
  • 可以實現組件的嵌套:須要掌握組件之間的信息通訊

1.全局組件 & 組件的基本語法

無需單獨引用或配置,直接在大組件中調取全局組件便可java

語法:Vue.component(component.name,options)node

  • component.name 組件命名的規則
    • kebab-case: 橫線做爲分隔符 , 只能基於kebab調取
    • PasalCase: 單詞首字母大寫 , 也是基於kebab調取(若是在template模板中可使用Pasal方式調取)

調取組件的時候,會把因此組件的單詞渲染爲小寫字母**(咱們命名的時候除PasalCase模式外,咱們都要把組件名設置爲小寫,調取組件的時候能夠是大寫也能夠是小寫(最後都是按照小寫渲染 ))vuex

命名的時候儘可能不要出現其他的特殊字符數組

  • options可使用的有VM實例具備的一切(DATA,METHODS,生命週期函數)

1. 組件的調用

每調用一次組件都是建立一個單獨的VUE實例(VueComponent--->vue)瀏覽器

<body>
<div id="app"> <h3 v-text='title'></h3> // <my-button/> //單閉合:不符合w3c規範,調取完成後,後面的視圖不識別(避免使用) //雙閉合:能夠設置除組件規定內容外的其他內容(slot插槽) <my-button> 我加的其它內容(slot 插槽) //沒有效果,須要使用slot插槽 </my-button> </div> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> Vue.component('MyButton', { template: `<button>組件中的按鈕</button>` }); let vm = new Vue({ el: '#app', data: { title: '你們好哇~' } }); </script> </body>	
複製代碼

2. slot插槽

把調取組件時候,寫在組件中間部分的內容獲取到,放置到組件的某個位置(具體位置根據需求來),依託這種方式,可讓當前組件具有更強的擴展性閉包

/* * 必須設置template或者render函數:來規定當前組件的渲染視圖 * 1.只能有一個根元素節點 * 2.template的值能夠是字符串(包裹須要的結構),也能夠把結構單獨分離出來,放置到<template></template>標記中,而後和當前組件關聯 * DATA必須是一個函數:至關於造成一個閉包,讓返回的對象(須要的響應式數據)是當前實例的私有的 */

<body>
<div id="app"> <h3 v-text='msg'></h3> <!-- 調用組件 --> <my-app> <template v-slot:before><p>我是調取組件的時候,在組件模板外單獨寫的內容</p></template> <template #after><p>我是後面的</p></template> </my-app> </div> <!-- TMPLATE:建立TMPLATE標籤用來構建組件渲染的視圖 --> <template id="mybutton"> <div> <slot name='before'></slot> <button @click='handle'>我是template組件{{msg}}</button> <slot name='after'></slot> </div> </template> <script src="./node_modules/vue/dist/vue.js"></script> <script> Vue.component('MyApp', { template: '#mybutton', data() { return { msg: '你好哇~' } }, methods: { handle() { this.msg = '~hello world~' } } }) let vm = new Vue({ el: '#app', data: { msg: 'hello~' } }); </script> </body>
複製代碼

2.局部組件

  1. 建立組件:let componenName={...}app

  2. 基於components屬性聲明組件:想用哪一個組件須要先聲明函數

  3. 使用組件

<body>
    <div id="app"> <my-button></my-button> </div> <!-- 建立 template 標籤來構建組件渲染視圖--> <template id="MyButtonTemplate"> <div> <button>組件按鈕~{{msg}}</button> <p>哈哈哈</p> </div> </template> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 1. 建立局部組件 const MyButton = { template:'#MyButtonTemplate', data(){ return{ msg:'hello~' } } }; let vm = new Vue({ el: '#app', /2. 註冊當前視圖中須要使用的局部組件 components:{ MyButton } }) </script> </body>
複製代碼

1.組件信息通信之父傳子

  1. 父組件調用到的時候,給父組件設置自定義屬性,子組件經過props接收
<my-component title='哈哈哈' :data-index='0'></my-component> //傳遞的屬性值默認都是字符串格式,若是想要讓傳遞的值是數字、布爾、數組、對象等格式,咱們須要使用v-bind處理 複製代碼
  1. 子組件設置PROPS用來接收父組件基於屬性傳遞進來的信息
Vue.component('my-component',{
  props:['title','dataIndex'],
  ...
})
    
/* props中聲明的屬性和data同樣,是響應式數據,掛載到vm實例上,可控制視圖渲染 * 命名大小寫:父組件傳遞的是kebab-case格式,props中獲取的是camelCase駝峯命名|pasalCase * 基於屬性傳遞進來的值,只能獲取使用,不能在子組件中修改(修改後會有對應的效果,子組件會從新渲染,可是控制檯會報錯) */
複製代碼
  1. 註冊屬性的校驗(不符合校驗格式的,依然能夠在組件中使用,只不過控制檯會拋出異常信息)
/* 指定屬性的類型:props:{xxx:String,...} * 指定屬性的默認值:props:{xxx:{type:String,default:'xxx',required:true}} - type若是是一個數組,意爲指定的多類型皆能夠 - default能夠是一個函數,函數返回值是默認值 - validator自定義驗證規則函數:必須符合函數中指定的規則,返回true/false */

props: {
    //=>指定屬性的類型
    props: {
        title: String,
        dataIndex: [Number, Array]
	},
    //=>設置默認值 
	title: {
    	type: String,
        default: '我是設定的屬性默認值'
        },
     
     aaa: {
         //=>數據格式
         type: [Number, Array],
         //=>是否爲必傳 TRUE必須傳遞
         required: true
         //=>自定義驗證規則 val傳遞的屬性值 在函數中,根據本身的規則,返回TRUE和FALSE來驗證傳遞的值是否符合規則
     validator(val) {
         return val >= 0;
       }
    }
},
複製代碼

樣式和class自動合併問題

能夠把子組件當作一個標籤,咱們能夠設置ID/CLASS/STYLE等內置屬性值,這些屬性也會傳遞給子組件,VUE幫咱們處理好的,該合併的合併,該覆蓋的覆蓋,無需咱們在PROPS中註冊處理

2.vue的單向數據流

全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。

Vue 的父組件和子組件生命週期鉤子函數執行順序能夠歸類爲如下 4 部分:

  • 加載渲染過程:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

  • 子組件更新過程:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

  • 父組件更新過程:父 beforeUpdate -> 父 updated

  • 銷燬過程:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

3. VUE組件信息通訊:基於$emit實現子改父

每次父級組件發生更新時,子組件中全部的 prop 都將會刷新爲最新的值。這意味着你不該該在一個子組件內部改變 prop。若是你這樣作了,Vue 會在瀏覽器的控制檯中發出警告。

子組件想修改時,只能經過 $emit派發一個自定義事件,父組件接收到後,由父組件修改。有兩種常見的試圖改變一個 prop 的情形 :

這個 prop 用來傳遞一個初始值;這個子組件接下來但願將其做爲一個本地的 prop 數據來使用。 在這種狀況下,最好定義一個本地的 data 屬性並將這個 prop 用做其初始值

這個 prop 以一種原始的值傳入且須要進行轉換。 在這種狀況下,最好使用這個 prop 的值來定義一個計算屬性

訂閱自定義事件:調用組件的時候基於屬性傳遞一個方法 (父)

<my-component @func='xxx'></my-component> new Vue({ methods:{ xxx(value){ //=>value是this.$emit時候傳遞的第二個參數值 } } }); 複製代碼

通知自定義事件執行 (子)

{
  methods:{
    xxx(){
      this.$emit('func',10);
    }
  }
}
複製代碼

4.VUE組件信息通訊:基於this.$emit實現子改父

let eventBus = new Vue; //=>建立事件總線

//A組件 => 基於$on建立一個自定義事件:把指定方法放到任務隊列中(兄弟)
eventBus.$on('xxxA',this.func);

//B組件=> 通知自定義事件執行
eventBus.$emit('xxxA');
複製代碼

5.父子信息傳遞—this.$children

經過this.$children 控制子組件的顯示隱藏

<body>
	<div id="app"> <my-vote v-for='item in voteList' :title="item.title"></my-vote> </div> <!-- TEMPLATE --> <template id="MyVoteTemplate"> <div class="container"> <h3> <span v-text='title'></span><span v-text='num'></span><button type="button" class="btn btn-primary" @click='handle'>點着玩</button> </h3> <vote-button ref='button'></vote-button> </div> </template> <template id="VoteButtonTemplate"> <div class="footer" v-show='flag'> <button type="button" class="btn btn-primary" @click="handle('support')">支持</button> <button type="button" class="btn btn-danger" @click="handle('oppose')">反對</button> </div> </template> <!-- IMPORT JS --> <script src="./node_modules/vue/dist/vue.js"></script> <script> const VoteButton = { template: '#VoteButtonTemplate', methods: { handle(type) { // console.log(this.$parent); this.$parent.num++; } }, data() { return { flag: true } } }; const MyVote = { template: '#MyVoteTemplate', props: ["title"], data() { return { num: 0 } }, components: { VoteButton }, methods: { handle() { // console.log(this.$children); // this.$children[0].flag = !this.$children[0].flag; this.$refs.button.flag = !this.$refs.button.flag; } } }; let vm = new Vue({ el: '#app', data: { voteList: [{ id: 1, title: '哈哈哈' }, { id: 2, title: '呵呵呵' }] }, components: { MyVote } }); // vuex:公共狀態管理 </script> </body> 複製代碼

組件信息傳遞案例-計算器

<body>
    <div id="app">
        <my-vote v-for='item in voteList' :title="item.title"></my-vote>
    </div>
    <!-- TMPLATE:建立TMPLATE標籤用來構建組件渲染的視圖 -->
    <template id="myVoteTemplate">
        <div class="container">
            <h3><span v-text='title'></span>(<span v-text='num'></span>)</h3>
            <my-content :eventbus='eventBus'></my-content>
            <!-- 2.於自定義事件,把父組件的某個方法註冊到任務隊列當中 -->
            <my-button @changeparent='changeParent' :eventbus='eventBus'></my-button>
        </div>
    </template>

    <template id="myContentTemplate">
        <div class="content">
            <p>支持人數:<span v-text='supNum'></span></p>
            <p>反對人數:<span v-text='oppNum'></span></p>
            <p>支持率:<span v-text='ratio'></span></p>
        </div>
    </template>

    <template id="myButtonTemplate">
        <div class="footer">
            <button type="button" class="btn btn-success" @click="handle('support')">支持</button>
            <button type="button" class="btn btn-danger" @click="handle('oppose')">反對</button>
        </div>
    </template>
    <script src="./node_modules/vue/dist/vue.js"></script>
    <script>
        /* 1. 點擊子組件影響父組件的數據
        */

        // let eventBus = new Vue;

        const myContent = {
            template: '#myContentTemplate',
            props: ['eventbus'],
            data() {
                return {
                    supNum: 0,
                    oppNum: 0
                }
            },
            computed: {
                ratio() {
                    let total = this.supNum + this.oppNum;
                    if (total === 0) {
                        return '0%';
                    }
                    return (this.supNum / total * 100).toFixed(2) + '%'
                }
            },
            methods: {
                // 1. 建立一個方法(兄弟)
                changeNum(type) {
                    type === 'support' ? this.supNum++ : this.oppNum++;
                }
            },
            created() {
                // 2.基於$on建立一個自定義事件:把指定方法放到任務隊列中(兄弟)
                this.eventbus.$on('changesupport', this.changeNum)
            }
        }
        const myButton = {
            template: '#myButtonTemplate',
            props: ['eventbus'],
            data() {
                return {}
            },
            methods: {
                handle(type) {
                    // 3.通知任務隊列中changeParent這個事件執行  
                    // 事件類型,後面的參數都是通知方法執行的時候,給方法傳遞的參數
                    this.$emit('changeparent', type);
                    // 3.點擊執行handle時,通知自定義事件執行;
                    this.eventbus.$emit('changesupport', type);
                }
            }
        }
        const myVote = {
            template: '#myVoteTemplate',
            data() {
                return {
                    num: 0,
                    eventBus: new Vue
                }
            },
            props: ['title'],
            components: {
                myContent,
                myButton
            },
            //1. 自定義事件(子改父)
            methods: {
                changeParent(type) {
                    this.num++;
                }
            }
        }
        let vm = new Vue({
            el: '#app',
            data: {
                voteList: [{
                    id: 1,
                    title: '今每天氣很好~'
                },
                {
                    id: 2,
                    title: '今每天氣很差~'
                },
                {
                    id: 3,
                    title: '今每天氣還能夠~'
                }]
            },
            components: {
                myVote
            }
        })

    </script>
</body>
複製代碼
相關文章
相關標籤/搜索