1. 程式人生 > 其它 >Vue元件化開發 ->(個人學習記錄筆記)

Vue元件化開發 ->(個人學習記錄筆記)

@

目錄

Vue

1. 元件化開發

1.1 基本使用過程

  • 註冊元件的基本步驟:
    • 建立元件
    • 註冊元件
    • 使用元件

  • Vue.extend():
    • 呼叫Vue.extend()建立的是一個元件構造器。
    • 通常在建立元件構造器時,傳入template代表我們自定義元件的模板
    • 改模板就是在使用到元件的地方,要顯示的HTML程式碼
  • Vue.component():
    • 呼叫Vue.component()是將剛才的元件構造器註冊為一個元件,並且給它起一個元件的標籤名稱
    • 所以需要傳遞兩個引數:1、註冊元件的標籤名 2、元件構造器
  • 元件必須掛載在某個Vue例項下。否則他不會生效
<div id="app">
  <!-- 3.使用元件 -->
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
  //1.建立愛你元件構造器物件
  const cpnC = Vue.extend({
    template: `
        <div>
          <h2>我是標題</h2>
          <p>我是內容,哈哈哈</p>
          <p>我是內容,呵呵呵</p>
        </div>`
  })
  //2.註冊元件
  Vue.component('my-cpn', cpnC);
  
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    }
  })
</script>

1.2 全域性元件和區域性元件

  • 全域性元件:在Vue例項外註冊,可以在多個Vue的例項下使用
  • 區域性元件:在Vue例項內註冊,可以在其Vue的例項下使用
<div id="app2">
  <cpn></cpn>
</div>
<div id="app">
  <!-- 3.使用元件 -->
  <cpn></cpn>
  <cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
  //1.建立愛你元件構造器物件
  const cpnC = Vue.extend({
    template: `
        <div>
          <h2>我是標題</h2>
          <p>我是內容,哈哈哈</p>
        </div>`
  })
  //2.註冊元件(全域性元件,意味著可以在多個Vue的例項下使用)
  // Vue.component('cpn', cpnC);

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      //cpn 使用元件時的標籤名(區域性元件)
      cpn:cpnC
    }
  })
  const app2 = new Vue({
    el: '#app2'
  })
</script>

1.3 父元件和子元件

<div id="app">
  <cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
  //1. 建立第一個元件
  const cpnC1 = Vue.extend({
    template: `
      <div>
        <h2>我是標題1</h2>
        <p>我是內容1</p>
      </div>
    `
  })

  //2. 建立第二個元件
  const cpnC2 = Vue.extend({
    template: `
      <div>
        <h2>我是標題2</h2>
        <p>我是內容2</p>
        <cpn1></cpn1>
      </div>`,
    components:{
      cpn1:cpnC1
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      cpn2:cpnC2
    }
  })
</script>

1.4 註冊元件的語法糖寫法

  • 省去Vue.extend()
<div id="app">
  <cpn1></cpn1>
  <cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
  // 1. 全域性元件註冊的語法糖
  // 1. 建立元件構造器
  // const cpn1 = Vue.extend()
  // 2. 註冊元件
  //全域性元件
  Vue.component('cpn1',{
    template: `
      <div>
        <h2>我是標題1</h2>
        <p>我是內容1</p>
      </div>
    `
  });

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    //註冊區域性元件的語法糖
    components:{
      'cpn2':{
          template: `
            <div>
              <h2>我是標題2</h2>
              <p>我是內容2</p>
            </div>
          `
      }
    }
  })
</script>

1.5 元件模板抽離

  • script標籤
  • template標籤
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<!--1. script標籤,注意:型別必須是text/x-template-->
<script type="text/x-template" id="cpn">
  <div>
    <h2>我是標題2</h2>
    <p>我是內容2</p>
  </div>
</script>
<!--2.template標籤-->
<template id="cpn1">
  <div>
    <h2>我是標題2</h2>
    <p>我是內容2</p>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>

  //1.註冊一個元件
  Vue.component('cpn',{
    template: '#cpn1'
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    }
  })
</script>

1.6 元件中的data

<div id="app">
  <cpn></cpn>
</div>
<template id="cpn">
  <div>
    <h2>{{counter}}</h2>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  Vue.component('cpn',{
    template: '#cpn',
    data(){
      return{
        counter:0
      }
    },
    methods:{
      increment(){
        this.counter++;
      },
      decrement(){
        this.counter--;
      }
    }
  })
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    }
  })
</script>

1.7 父子元件通訊

父傳子

  • 方法
    • 通過props向子元件傳遞資料
    • 通過事件向父元件傳送訊息
  • Vue例項和子元件的通訊 和 父元件和子元件的通訊過程是一樣的
props
  • 不要用駝峰標識 v-bind無法識別,如必須使用:c-info="info" 元件內用駝峰cInfo
  • 在元件中,使用選項props來宣告需要從父級接收到的資料。
  • props的值有兩種方式:
    • 方式一:字串陣列,陣列中的字串就是傳遞時的名稱
    • 方式二:物件,物件可以設定傳遞時的型別,也可以設定預設值等

props資料驗證

  • 支援的型別
    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol
<div id="app">
  <cpn :cmovies="movies" :cmessage="message"></cpn>
</div>
<template id="cpn">
  <div>
    <ul>
      <li v-for="item in cmovies">{{item}}</li>
    </ul>
    <h2>{{cmessage}}</h2>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  //父傳子 props
  const cpn = {
    template: '#cpn',
    // props: ['cmovies','cmessage'],
    props:{
      //1.型別限制
      // cmovies: Array,
      // cmessage: String,

      //2.提供一些預設值
      cmessage: {
        type: String, //型別
        default:'aaaaa',  //預設值
        required: true
      },
      //型別是物件或者陣列時,預設值必須是一個函式
      cmovies: {
        type:Array,
        default() {
          return []
        }
      }
    },
    data(){
      return{}
    },
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!',
      movies:['海王','海賊王','海爾兄弟']
    },
    components:{
      cpn,
    }
  })
</script>

子傳父

自定義事件

  • $emit
<!--父元件模板-->
<div id="app">
  <cpn @item-click="cpnClick"></cpn>
</div>

<!--子元件模板-->
<template id="cpn">
  <div>
    <button v-for="item in categories" @click="itemClick(item)">
      {{item.name}}
    </button>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  //子元件
  const cpn = {
    template: '#cpn',
    data() {
      return {
        categories: [
          {id: 'aaa', name: '熱門推薦'},
          {id: 'bbb', name: '手機數碼'},
          {id: 'ccc', name: '家用家電'},
          {id: 'ddd', name: '電腦辦公'},
        ]
      }
    },
    methods: {
      itemClick(item) {
        this.$emit('item-click',item)
        // console.log(item);
      }
    }
  }

  //父元件
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!',
      movies: ['海王', '海賊王', '海爾兄弟']
    },
    components: {
      cpn,
    },
    methods: {
      cpnClick(item){
        console.log('aaaaa',item);
      }
    }
  })
</script>

父子元件通訊案例

<div id="app">
  <cpn :number1="num1"
       :number2="num2"
       @num1change="num1change"
       @num2change="num2change"></cpn>
</div>

<template id="cpn">
  <div>
    <h2>props:{{number1}}</h2>
    <h2>data:{{dnumber1}}</h2>
<!--    <input type="text" v-model="dnumber1">-->
    <input type="text" :value="dnumber1" @input="num1Input">
    <h2>props:{{number2}}</h2>
    <h2>data:{{dnumber2}}</h2>
<!--    <input type="text" v-model="dnumber2">-->
    <input type="text" :value="dnumber2" @input="num2Input">
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!',
      num1:1,
      num2:0
    },
    methods: {
      num1change(value){
        this.num1=parseInt(value);
      },
      num2change(value){
        this.num2=parseInt(value);
      }
    },
    components:{
      cpn:{
        template:'#cpn',
        props:{
          number1:Number,
          number2:Number
        },
        data(){
          return {
            dnumber1:this.number1,
            dnumber2:this.number2,
          }
        },
        methods:{
          num1Input(event){
            this.dnumber1=event.target.value;
            this.$emit('num1change', this.dnumber1);

            this.dnumber2 = this.dnumber1*100;
            this.$emit('num2change',this.dnumber2);
          },
          num2Input(event){
            this.dnumber2=event.target.value;
            this.$emit('num2change', this.dnumber2);

            this.dnumber1 = this.dnumber2/100;
            this.$emit('num1change',this.dnumber1)
          },
        }
      }
    },

  })
</script>

watch監聽改變

 watch:{
          dnumber1(newValue){
            this.dnumber2 =  newValue*100;
            this.$emit('num1change', newValue);
          },
          dnumber2(newValue){
            this.dnumber1 =  newValue*100;
            this.$emit('num2change', newValue);
          }
        },

父子元件的訪問方式: $children

  • 父元件訪問子元件:使用$children$refs(引用)
  • 子元件訪問父元件:使用$parent
父訪問子
<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <cpn ref="aaa"></cpn>
  <button @click="btnClick">按鈕</button>
</div>
<template id="cpn">
  <div>我是子元件</div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    methods: {
      btnClick(){
        //1.關於$children
        // console.log(this.$children);
        // for(let c of this.$children){
        //   console.log(c.name);
        //   c.showMessage();
        // }

        //2.$refs
        console.log(this.$refs);

      }
    },
    components:{
      cpn:{
        template:'#cpn',
        data() {
          return{
            name: '我是子元件的name'
          }
        },
        methods:{
          showMessage(){
            console.log('showMessage');
          }
        }
      }
    }
  })
</script>
子訪問父
<div id="app">
  <cpn></cpn>
</div>
<template id="cpn">
  <div>
    <h2>我是cpn元件</h2>
    <ccpn></ccpn>
  </div>
</template>
<template id="ccpn">
  <div>
    <h2>我是子元件</h2>
    <button @click="btnClick">按鈕</button>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      cpn:{
        template:'#cpn',
        data(){
          return{
            name:'我的cpn元件的name'
          }
        },
        components: {
          ccpn:{
            template:'#ccpn',
            methods:{
              btnClick(){
                //1.訪問父元件
                console.log(this.$parent);
                console.log(this.$parent.name);

                //2.訪問根元件$root
                console.log(this.$root);
                console.log(this.$root.message);
              }
            },
          }
        }
      }
    }
  })
</script>

2. 元件化高階

2.1 slot 插槽

2.1.1 基本使用

  1. 插槽的基本使用<slot></slot>
  2. 插槽的預設值<slot>button</slot>
  3. 多個值同時放入到元件中,則一起組我誒替換元素
<!--1. 插槽的基本使用<slot></slot>-->
<!--2. 插槽的預設值<slot>button</slot>-->
<!--3. 多個值同時放入到元件中,則一起組我誒替換元素-->
<div id="app">
  <cpn>
    <button>案例</button>
  </cpn>
  <cpn>
    <span>哈哈哈</span>
  </cpn>
  <cpn>
    <i>哈哈哈</i>
    <div>我是div元素</div>
    <p>我是p元素</p></cpn>
  <cpn>
    <button>新按鈕</button>
  </cpn>
  <cpn></cpn>
</div>
<template id="cpn">
  <div>
    <h2>我是元件</h2>
    <p>我是元件,哈哈哈</p>
    <!--設定預設值-->
    <slot>
      <button>預設按鈕</button>
    </slot>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components: {
      cpn: {
        template: '#cpn',
      }
    }
  })
</script>

2.1.2 具名插槽

  • 多個插槽,區分通過新增name
<div id="app">
  <cpn>
    <button slot="left">返回</button>
    <span slot="center">標題</span>
  </cpn>
</div>
<template id="cpn">
  <div>
    <slot name="left"><span>左邊</span></slot>
    <slot name="center"><span>中間</span></slot>
    <slot name="right"><span>右邊</span></slot>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      cpn:{
        template:'#cpn'
      }
    }
  })
</script>

2.2 編譯作用域

<div id="app">
  <cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
  <div>
    <h2>我是子元件</h2>
    <p>我是內容,哈哈哈</p>
    <button v-show="isShow">按鈕</button>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!',
      isShow:true
    },
    components:{
      cpn:{
        template:'#cpn',
        data(){
          return{
            isShow: true
          }
        }
      }
    }
  })
</script>

2.3 作用域插槽

<div id="app">
  <cpn></cpn>
  <cpn>
    <!--<span v-for="item in pLanguages"></span>-->
    <template slot-scope="slot">
<!--      <span v-for="item in slot.data"> {{item}}- </span>-->
      <span>{{slot.data.join(' - ')}}</span>
    </template>
  </cpn>

  <cpn>
    <!--<span v-for="item in pLanguages"></span>-->
    <template slot-scope="slot">
<!--      <span v-for="item in slot.data"> {{item}}* </span>-->
      <span>{{slot.data.join(' * ')}}</span>
    </template>
  </cpn>
</div>
<template id="cpn">
  <div>
    <slot :data="pLanguages">
      <ul>
        <li v-for="item in pLanguages">{{item}}</li>
      </ul>
    </slot>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊!'
    },
    components:{
      cpn:{
        template:"#cpn",
        data(){
          return{
            pLanguages:['JavaScript','C++','Java','C#','Python','Go','Swift']
          }
        }
      }
    }
  })
</script>