VUE系列-Vue中組件的應用(三)

大家好,我是前端嵐楓,一枚二線城市的程序媛,上篇主要跟分享了《VUE系列-Vue核心應用(二)》,今天主要跟大家分享我整理的vue的組件相關的,主要包括組件聲明、組件種類、組件間的幾種數據通信方式及一些常用的面試題,vue面試題相關的答案我後期會專門整理分享。

Vue中的組件是開發中非常重要的一部分,組件化的好處:方便維護、方便複用 、 減少不必要的渲染

一.組件的聲明

1.1 全局組件

<my-button></my-button>  
Vue.component('my-button',{
  template:'<button>點我啊</button>'
})
let vm = new Vue({
  el:'#app'
})

1.2 局部組件

<my-button></my-button>
let vm = new Vue({
  el:'#app',
  components:{
      'MyButton':{
          template:'<button>按鈕</button>'
      }
  }
});

HTML不支持自閉合的自定義元素,在DOM模板裏永遠不要使用自閉合組件,在HTML中也不支持MyButton的寫法,所以組件調用全部使用短橫線連接的方式!

二.組件的數據

在組件中的數據必須是函數的形式,目的爲了保證每個組件間的數據數據相互獨立

'MyButton':{
    data(){
        return {content:'按鈕'}
    },
    template:'<button>{{content}}</button>'
}

三.組件的屬性應用及校驗

  • 屬性應用
<my-button button-content="按鈕"></my-button>
components:{
    'MyButton':{
        props:['buttonContent'],
        template:'<button>{{buttonContent}}</button>'
    }
}

屬性在組件標籤上需要使用短橫線命名法,在組件中聲明需要採用駝峯命名法

  • 屬性校驗
<my-button button-content="按鈕" :number="'1'"></my-button>
components:{
    'MyButton':{
        props:{
            buttonContent:String,
            arr:{
                type:Array,
                default:()=>([])
            },
            number:{
                type:Number,
                validator:(value)=>{
                    return typeof value == 'number'
                }
            },

        },
        template:'<button>{{buttonContent}} {{arr}} {{number}}</button>'
    }
}

四.Vue組件間的通信

快速原型開發: 可以快速識別.vue文件封裝組件插件等功能,也是基於Vue-Cli

sudo npm install @vue/cli -g
sudo npm install -g @vue/cli-service-global
vue serve App.vue

4.1 Props傳遞數據

components
   ├── Grandson1.vue // 孫子1
   ├── Grandson2.vue // 孫子2
   ├── Parent.vue   // 父親
   ├── Son1.vue     // 兒子1
   └── Son2.vue     // 兒子2

在父組件中使用兒子組件

<template>
 <div>
  父組件:{{mny}}
  <Son1 :mny="mny"></Son1>
 </div>
</template>
<script>
import Son1 from "./Son1";
export default {
 components: {
  Son1
 },
 data() {
  return { mny: 100 };
 }
};
</script>

子組件接受父組件的屬性

<template>
 <div>子組件1: {{mny}}</div>
</template>
<script>
export default {
 props: {
  mny: {
   type: Number
  }
 }
};
</script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <!-- 將父組件的數據 通過兒子的屬性傳入 -->
        {a:1,b:2,c:3}
        <my a=1 b=2 c=3></my>
    </div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
        // 單向數據流 父組件將數據傳遞給兒子
        //  每個組件都應該有三部分 1) html  2) js 3) 樣式
        let component = {
            template:`<div>兒子 {{mny}} <button @click="change">更改</button></div>`,
            // props:['mny'], // this.mny = 100
            props:{ // 表示 我要對屬性進行校驗
                mny:{
                    // 普通類型直接寫 默認值即可 如果是對象或者是數組 必須寫成函數返回值的效果
                    type:Object, // 類型校驗
                    default:()=>({a:1})// 默認值校驗
                    // required:true //必填校驗
                }
            },  
            methods:{
                change(){
                    this.mny = 200; // 不靠譜,不應該兒子去更改父親數據
                }
            },
            data(){
                return {m:1}
            },
            beforeCreate(){ // 這裏可以描述 父子關係 
                console.log(this.$parent.$children[0] === this);
            },
        }
        // Vue.component('my',component)
        let vm = new Vue({
            el:'#app',
            beforeCreate(){
                console.log(this.$children);
                debugger;
            },
            data:{
                arr:[1,2,3],
                mny:'100'
            },
            components:{ // 在實例上註冊組件
                my:component
            }
        });
        // 組件的使用 三部 1)導入一個組件 2) 註冊 3) 使用 在當前組件定義的模板中使用
    </script>
</body>
</html>

4.2 $emit使用

子組件觸發父組件方法,通過回調的方式將修改的內容傳遞給父組件

<template>
 <div>
  父組件:{{mny}}
  <Son1 :mny="mny" @input="change"></Son1>
 </div>
</template>
<script>
import Son1 from "./Son1";
export default {
 methods: {
  change(mny) {
   this.mny = mny;
  }
 },
 components: {
  Son1
 },
 data() {
  return { mny: 100 };
 }
};
</script>

子組件觸發綁定自己身上的方法

<template>
 <div>
  子組件1: {{mny}}
  <button @click="$emit('input',200)">更改</button>
 </div>
</template>
<script>
export default {
 props: {
  mny: {
   type: Number
  }
 }
};
</script>

這裏的主要目的就是同步父子組件的數據,->語法糖的寫法

.sync

<Son1 :mny.sync="mny"></Son1>
<!-- 觸發的事件名 update:(綁定.sync屬性的名字) -->
<button @click="$emit('update:mny',200)">更改</button>

v-model

<Son1 v-model="mny"></Son1>
<template>
 <div>
  子組件1: {{value}} // 觸發的事件只能是input
  <button @click="$emit('input',200)">更改</button>
 </div>
</template>
<script>
export default {
 props: {
  value: { // 接收到的屬性名只能叫value
   type: Number
  }
 }
};
</script>

4.3 parent 、children

繼續將屬性傳遞

<Grandson1 :value="value"></Grandson1>
<template>
 <div>
  孫子:{{value}}
  <!-- 調用父組件的input事件 -->
  <button @click="$parent.$emit('input',200)">更改</button>
 </div>
</template>
<script>
export default {
 props: {
  value: {
   type: Number
  }
 }
};
</script>

如果層級很深那麼就會出現parent.parent.....我們可以封裝一個$dispatch方法向上進行派發

$dispatch

Vue.prototype.$dispatch = function $dispatch(eventName, data) {
  let parent = this.$parent;
  while (parent) {
    parent.$emit(eventName, data);
    parent = parent.$parent;
  }
};

既然能向上派發那同樣可以向下進行派發

$broadcast

Vue.prototype.$broadcast = function $broadcast(eventName, data) {
  const broadcast = function () {
    this.$children.forEach((child) => {
      child.$emit(eventName, data);
      if (child.$children) {
        $broadcast.call(child, eventName, data);
      }
    });
  };
  broadcast.call(this, eventName, data);
};

4.4 attrs、listeners

$attrs

批量向下傳入屬性

<Son2 name="小珠峯" age="10"></Son2>

<!-- 可以在son2組件中使用$attrs屬性,可以將屬性繼續向下傳遞 -->
<div>
  兒子2: {{$attrs.name}}
  <Grandson2 v-bind="$attrs"></Grandson2>
</div>


<template>
 <div>孫子:{{$attrs}}</div>
</template>

$listeners

批量向下傳入方法

<Son2 name="小珠峯" age="10" @click="()=>{this.mny = 500}"></Son2>
<!-- 可以在son2組件中使用listeners屬性,可以將方法繼續向下傳遞 -->
<Grandson2 v-bind="$attrs" v-on="$listeners"></Grandson2>

<button @click="$listeners.click()">更改</button>

4.5 Provide & Inject

Provide

在父級中注入數據

provide() {
  return { parentMsg: "父親" };
},

Inject

在任意子組件中可以注入父級數據

inject: ["parentMsg"] // 會將數據掛載在當前實例上

provide inject 和 context (可以在父組件中聲明一個公共數據),在子組件中可以注入原理 (比較混亂,名稱問題 他不會在業務代碼中使用) 組件庫 多級通信爲了方便你可以使用provide

4.6 Ref使用

獲取組件實例
ref 獲取真實dom元素,如果放到組件上 代表的是 當前組件的實例 ,父組件中可以直接獲取子組件的方法或者數據

<Grandson2 v-bind="$attrs" v-on="$listeners" ref="grand2"></Grandson2>
mounted() { // 獲取組件定義的屬性
  console.log(this.$refs.grand2.name);
}

4.7 EventBus

用於跨組件通知(不復雜的項目可以使用這種方式)

Vue.prototype.$bus = new Vue();

eventbus (parent,children) 綁定on 只能通過綁定on的那個組件來觸發 (混亂)

Son2組件和Grandson1相互通信

 mounted() {
  this.$bus.$on("my", data => {
   console.log(data);
  });
 },
mounted() {
  this.$nextTick(() => {
   this.$bus.$emit("my", "我是Grandson1");
  });
 },

五.面試題環節

  • 組件間通信方式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章