vue生命周期和組件間傳值

生命周期

new Vue() 初始化一些事件和生命周期 例如:vm.$on, vm.$once, vm.$emit
beforeCreate 初始化之前,會先把一些數據方法放在實例中,還沒初始化完,不能操作數據,一般用不到
created 數據,方法初始化完成,可以操作數據,實現響應式綁定,此處一般ajax獲取數據
必須有el屬性(有編譯的元素),才能進行掛載,只能有一個根元素,如果有template屬性(內部html),app(外部html)中的內容就會被覆蓋掉,就沒有意義了
beforeMount 掛載之前,沒有什么實際意義,會用vm.$el替換el
mounted 掛載完成,數據和模板掛載好了,真實DOM渲染完了,可以操作DOM
beforeUpdate 更新之前,頁面依賴的數據有變化就會開始更新
updated 更新之后,一般用watch方法替代這兩個方法
beforeDestory 銷毀之前,開始移除一些定時器和事件綁定等操作,方法還沒銷毀,
destoryed 銷毀完成

this.$data:vm上的數據
this.$watch:監控
this.$el:當前el元素
this.$set:后添加的屬性實現響應式變化
this.$options:實例上的屬性,包括內置的還有自定義的
this.$refs:所有ref的集合,帶ref屬性的標簽,如果不是通過v-for循環出來的DOM元素,只能獲取一個
this.$nextTick():異步方法,等待渲染完成后獲取vm,數據變化后想獲取真實dom,需要等待頁面獲取完成后再去獲取,因此所有dom操作最好都放在this.$nextTick()

mounted(){
  // console.log(document.getElementsByTagName('p')[0].innerHTML);
  console.log(this.$refs.message);
  console.log(this.$refs.wrap);
  this.arr = [1,2,3,4,5]; // dom的渲染是異步的
  this.$nextTick(function () {
  // 數據變化后想獲取真實dom,需要等待頁面獲取完成后再去獲取
      console.log(this.$refs.wrap.children.length); // 5
   });
  console.log(this.$refs.wrap.children.length); // 3
}

組件化開發

組件化開發可以提高開發效率,方便重復利用,便與協同開發,更容易被管理和維護。一般根據功能可分為兩種:
1、頁面級組件,一個頁面是一個組件
2、基礎組件,將可復用的部分抽離出來
vue中,一個自定義標簽就會被看成一個組件
根據用法劃分:
全局組件:聲明一次可以在任何地方使用,寫插件的時候用的多
局部組件:必須要聲明這個組件屬于哪一部分
聲明組件的時候,標簽名不要大寫,多個單詞用- 組件名和定義的名字相同是可以的(首字母可以大寫)
html中用-,JS中轉駝峰也是可以的
組件中的data必須是函數類型的,返回一個實例作為組件中的數據

<body>
<!--分類 頁面級組件 一個頁面是一個組件-->
<!--將可復用的部分抽離出來  基礎組件-->

<div id="app">
<my-vue></my-vue>
</div>

<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    // 一個對象可以看成一個組件
    Vue.component('my-vue', {
        template: '<div>{{msg}}</div>',
        data(){
            return {msg: 'vue學習'}
        }
    });
</script>
</body>

局部組件
局部組件使用的三部曲
1、創建組件
2、注冊組件
3、引用組件
組件是相互獨立的,不能直接跨作用域,vm這個實例也是一個組件,組件中擁有生命周期函數,如果組件共用了數據會導致同時更新,因此要求data必須是函數類型的。
子組件不能直接使用父組件的數據(組件間數據傳遞),組件理論上可以無限嵌套

<body>
<div id="app">
    <component1></component1>
    <component2></component2>
</div>

<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    // 局部組件使用的三部曲
    // 1、創建組件
    // 2、注冊組件
    // 3、引用組件
    let component1 = {
        template: '<div>{{msg}}</div>',
        data(){
           return {msg: '組件2'}
        }
    };
    let component2 = {
        template: '<div>組件2</div>',
    };
    let vm = new Vue({
        el: '#app',
        components:{
            component1,
            component2
        },
        data: {}
    });
</script>

組件間的嵌套:
1、被調用的子組件必須先定義,否則就拿不到。
2、哪里要用當前組件,就在哪里通過components注冊,
3、需要在調用的組件中通過標簽的形式引入
理論上是無限嵌套的,單位了好維護,一般最多嵌套3層

<div id="app">
    <!--<div>parent-->
        <!--<div>child-->
            <!--<div>grandson</div>-->
        <!--</div>-->
    <!--</div>-->
    <parent>
        <child>
            <grandson></grandson>
        </child>
    </parent>
</div>

<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    let grandson = {
            template: `<div>grandson</div>`
        },
        child = {
            template: `<div>child<grandson></grandson></div>`,
            components:{
                grandson
            }
        },
        parent = {
        template: `<div>parent<child></child></div>`,
        components: {
            child
        }
    };
    let vm = new Vue({
        el: '#app',
        components:{
            parent,
        },
        data: {}
    });
</script>
</body>

父組件給子組件傳值:屬性傳遞,:money=""是傳值的,傳了一個空值,所以不會用到default,不在子組件定義這個屬性,這才算不傳值
required: true:表示該值必須傳遞,不穿就發警告,不能與默認值default同時出現。
校驗時不會阻斷代碼的執行,只會出現警告
還可以自己定義校驗信息,用validator方法,里面的參數就是當前傳遞的值,返回true表示通過反之不通過。(用的8多)

<body>
<div id="app">
    parent: {{money}}
    <!--m屬于子,屬性值屬于父-->
    <!--當前組件的屬性=父級的值-->
    <child :money="money"></child>
</div>

<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    // 父傳子
    let vm = new Vue({
        el: '#app',
        data: {
            money: 100,
            a: 400
        },
        components: {
            child: {
                // 會在當前子組件上聲明一個m屬性,值是父組件的
                // 數組的形式可以直接取值,但無法校驗
                // props: ['money'], // this.m = money變量 this->child
                // 對象的形式可以校驗
                props: {
                    // 子父組件中的屬性名不能重復,控制臺也會報錯
                    // 父組件的會覆蓋子組件的值
                    // 可以加個default值,不傳值的時候就用默認值
                    money: {
                        // 判斷傳遞值的類
                        // 如果不帶冒號:,得到的肯定是字符串類型
                        // 類型不對頁面上依舊會顯示,但控制臺會報類型錯誤
                        type: [Number],
                        // default: 0
                        required: true,
                        validator(val){ // 參數是當前傳遞的值,返回true表示通過
                            return val > 300;
                        }
                    }
                },
                template: '<div>child: {{money}}</div>'
            }
        }
    });
</script>
</body>

子組件給父組件傳值:通過發布訂閱的模式,父親綁定一些事件,兒子觸發這個事件,將參數傳遞過去,單向數據流 父組件數據刷新,子組件就刷新,不能子組件直接改父組件的值,要想這樣,就需要子組件先通知父組件要修改值,父組件再去修改
在本例子中,子組件通過點擊事件觸發($emit)自己的child-msg方法,而該方法又觸發了父組件的moreMoney方法執行,這樣一來就實現了子組件向父組件傳值

<body>
<div id="app">
    parent: {{money}} <button @click="lessMoney">少要點</button>
    <!--m屬于子,屬性值屬于父-->
    <!--當前組件的屬性=父級的值-->
    <!--剛剛那個事件是父級的,訂閱需要在子級做-->

    <child :money="money" @child-msg="moreMoney"></child>
</div>

<script src="../node_modules/vue/dist/vue.js"></script>
<script>
    let vm = new Vue({
        el: '#app',
        data: {
            money: 400,
        },
        methods: {
            moreMoney(val){
                this.money = val;
            },
            lessMoney(){
                this.money = 200;
            }
        },
        components: {
            child: {
                props: ['money'],
                template: '<div>child: {{money}} 
                 <button @click="getMoney">再來點</button></div>',
                methods: {
                    getMoney(){ // 觸發自己的自定義事件讓父組件的方法執行
                        this.$emit('child-msg', 800);
                    }
                }
            }
        }
    });
</script>
</body>

sync語法糖的用法

<child :money="money" @update:money="val=>this.money=val"></child>
same as
<child :money.sync="money"></child>

子父組件聲明周期
父組件需要等到子組件掛載完成(mounted)之后才會觸發掛載

mounted(){
    console.log(this.$refs.child.$el.innerHTML); 
    // 1 2 3
    // 因為存在DOM映射,所以頁面上的數據實時變化,
    // 但是DOM渲染是個異步的過程,這里還新的數據還沒有渲染完
    this.$nextTick(() => {
          console.log(this.$refs.child.$el.innerHTML); 
          // 4 5 6
    });
},

兄弟組件間相互通信
eventBus一般不用,了解,發布訂閱模式失敗的原因是因為在不同組件中的this是不一樣的,組件2觸發,組件1監聽,顯然是行不通的。發布訂閱的執行者應該是同一個才能成功,因此就需要有一個第三方實例eventBus來實現交互。

let brother1 = {
        template: '<div>{{color}} <button>變綠</button></div>',
        data() {
            return {color: '綠色', old: '綠色'}
        },
        created() {
            // 組件1監聽
            this.$on('changeRed', (val) => { // 頁面一加載,組件1長一個耳朵來監聽
                this.color = val;
            })
        }
    };
let brother2 = {
        template: '<div>{{color}} <button @click="change">變紅</button></div>',
        data() {
            return {color: '紅色', old: '紅色'}
        },
        methods: {
            change() {
                // 組件2發布
                this.$emit('changeRed', this.old);
            }
        }
};

eventBus使用,創建一個Vue實例,在兄弟組件中發布訂閱都用這個實例來操作即可,但是觸發的方法名不能重復,否則就亂套了

let eventBus = new Vue();
eventBus.$on('changeRed', (val) => { 
      this.color = val;
});
change() {
     eventBus.$emit('changeRed', this.old);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容

  • Vue 實例 在文檔中經常會使用 vm 這個變量名表示 Vue 實例,在實例化 Vue 時,需要傳入一個選項對象,...
    鄙人才疏學淺閱讀 592評論 0 1
  • 1.vue基本生命周期 vue源碼中最終執行生命周期函數都是調用callHook方法,callHook函數的邏輯很...
    WHU_GIS_LJ閱讀 19,643評論 0 13
  • 實例生命周期: beforeCreate:在實例初始化之后,數據觀測data observer(props、dat...
    隔壁老王z閱讀 36,994評論 0 29
  • 每個vue實例從創建到銷毀的過程都是一個生命周期,也會運行對應的鉤子函數,下圖為Vue生命周期示意圖: 1.bef...
    yun_154192閱讀 12,653評論 1 7
  • beforeCreate 1 .實例初始化之后2 .this指向創建的實例3 .數據觀測,event/watche...
    skoll閱讀 1,322評論 1 1