Vue组件化开发

Vue组件化基本使用

(1)创建组件构造器对象,写上自定义组件的模板

 // 1.创建组件构造器对象
  const cpnContructor = Vue.extend({
    // 自定义组件模板
    template: `
    <div>
      <h2>我是组件模板</h2>
      <p>我是内容</p>
    </div>`
  })

(2)注册组件(参数1:注册组件的标签名,参数2:创建的组件构造器名

Vue.component('my-cpn' ,cpnContructor)

(3)使用组件

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

全局组件和局部组件

用上述注册方法注册的组件为全局组件。

注册局部组件的方法如下:
(1)创建组件构造器对象,写上自定义组件模板(同上)

 // 1.创建组件构造器
  const cpnC = Vue.extend({
    templete:`
    <div>
      <h2>我是局部组件</h2>
      <p>我是内容</p>  
    </div>
    `
  })

(2)局部组件要在Vue实例下注册

const vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    // 局部组件,在Vue实例下注册
    components: {
      // 标签名  构造器
      cpn: cpnC
    }
  });

(3)使用方法同上

父组件和子组件

(1)创建第一个组件cpnC1

const cpnC1 = Vue.extend({
    template:`
      <div>
        <h2>我是C1组件</h2>
        <p>我是C1组件内容</p>
      </div>
    `
  })

(2)创建第二个组件cpnC2(此组件中使用components注册了第一个组件cpnC1)

const cpnC2 = Vue.extend({
    template:`
      <div>
        <h2>我是C2组件</h2>
        <p>我是C2组件内容</p>
        <cpn1></cpn1>  
      </div>
    `,   
    //第二个组件构造器中包含components,注册了第一个组件
    components: {
      cpn1: cpnC1
    }
  })

(3)将第二个组件在vue实例下进行注册

// root组件
  const vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    // 注册了第二个组件
    components: {
      cpn2: cpnC2
    }
  });

(4)对组件进行使用

<div id="app">
  <cpn2></cpn2>
  <!--cpn1是无法在这里使用的 -->
</div>

注意:此处是无法直接使用cpn1组件的,因为cpn1注册在cpn2组件下,此时我们称cpn1是cpn2的子组件。而cpn2是cpn1的父组件.
结果:
在这里插入图片描述
先显示了cpnC2组件中的内容,又因此C2组件中注册了C1组件,因此同样显示了C1组件的内容,注意此处显示是有先后关系的。

注册组件的语法糖写法

(1)全局组件的语法糖写法:使用 Vue.component() 直接创建和注册组件。

Vue.component('my-button', { 
    template: `<button>点击我</button>` 
})

let app = new Vue({ 
    el: '#app' 
}) 

第一个参数是组件标签名称,第二个参数是一个选项对象,使用选对象的 template 属性定义组件模板。
(2)局部组件的语法糖写法:在选项对象 components 属性中注册局部组件的语法糖。

let app = new Vue({ 
    el: '#app',
    components: {
        'my-button': {
            template: `<button>点击我</button>` 
        }
    }
})

组件模板抽离的写法

即便有了注册组件的语法糖写法,但是看起来还是不够清晰,为了避免这种高耦合性,可以将组件的模板单独抽离出来
(1)注册一个组件

  // 1.注册一个全局组件
  Vue.component('cpn' , {
    template: '#cpn',
  })

(2)定义template标签并为他加上id属性

<template id="cpn">
  <div><h2>我是组件模板</h2></div>
</template>

组件data必须是函数

为什么组件中data必须是一个函数?

组件是需要被复用的,如果data中的数据并没有写成一个函数的话,它就不会有自己的作用域。写成函数后可以保证每一次调用这个组件中的数据,它都是新的数据,不会造成数据的混乱。

组件通信-父向子

父组件通过props向子组件传递数据 (Pass props)

<div id="app">
  <!-- 2 -->
  <!-- cmovies得到了movies的值,cmessage得到了message的值 -->
  <cpn :c-movies="movies" :cmessage="message"></cpn>
</div>

<!-- 模板 -->
<template id="cpn">
  <div>
    <ul>
      <!-- 3 -->
      <li v-for="items in cMovies">{{items}}</li>
    </ul>
  </div>
</template>

<script>
  const vm = new Vue({
    el: '#app',
    data: {
      // 父组件里的data,要传到下面的子组件cpn里
      message:'你好啊',
      movies:['1', '2', '3']
    },
    methods: {},
    components: {
      'cpn' :  {
      template : '#cpn',
      // 1.
      props: {
        // 为什么不写驼峰标识
        cMovies : Array,
        cmessage : String
      },
      data() {
        return{
        }
      }
    }
    }
  });

props有三种写法:

 	// 第一种
    // props:['cmovies', 'cmessage'],

    // 第二种写法
    // props: {
    //   cmovies: Array, //验证,数据必须是一个数组
    //   cmessage: String,

    // 第三种写法:提供一些默认值,以及必传值
    props: {
      cmessage: {
        type : String,
        // 显示默认值
        default: 'aaaaaaaa' ,
        // 必须要cmessage传值
        required: true
      },
      cmovies: {
        type : Array,
        default: [] 
      }
    },

子向父

子组件通过事件向父组件发送消息 ($emit Events)

 !-- 父组件模板 -->
<div id="app">
  <!--3.监听自定义事件(子组件发射出去的事件) -->
  <cpn v-on:itemclick="cpnClick"></cpn>
</div>

<!-- 子组件模板 -->
<template id="cpn">
  <div>
    <!-- 1.在子组件中获得用户所点击的对象 -->
    <button v-for="items in categories" 
            @click="btnClick(items)">  <!--点击之后得到所点击的对象-->
      {{items.name}}</button>
  </div>
</template>


<script>
  // 1.子组件:告诉父组件你点击了谁,父组件根据谁去请求对应的数据
  const cpn = {
    template : "#cpn",
    data(){
      return{
        categories:[
          {id: 'aaa', name: '热门推荐',},
          {id: 'bbb', name: '手机数码',},
          {id: 'ccc', name: '家电数码',},
          {id: 'aaa', name: '电脑办公',}
        ]
      }
    },
    // 定义btnClick方法,将这个自定义事件,发射给父组件
    methods:{
      btnClick(items){
        // 把item传给父组件
        // 发射
        this.$emit('itemclick' , items)  //发射事件名称为itemClick
      }
    }
  }

  // 2.父组件
  const vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    components: {
      cpn
    },
    methods: {
      // 得到发射来的点击目标
      cpnClick(items) {
        console.log('cpnClick' , items)
      }
    }
  });

父子组件通信案例

<!-- 子传父:监听子组件发射来的自定义事件 -->
<div id="app">
<cpn :cnum1="num1" 
     :cnum2="num2"
     @num1change="num1change"
     @num2change="num2change"/>
</div>


<!-- 模板 -->
<template id="cpn">
  <div>
    <h2>props:{{cnum1}}</h2>
    <h2>data:{{dnumber1}}</h2>
    <!-- v-model绑定到了props属性上,不要这样做 -->
    <!-- <input type="text" v-model="dnumber1"> -->
    <input type="text" v-bind:value="dnumber1" @input="num1Input">
    <h2>props:{{cnum2}}</h2>
    <h2>data:{{dnumber2}}</h2>
    <!-- 绑定要绑定到data函数里 -->
    <!-- <input type="text" v-model="dnumber2"> -->
    <!-- 监听 -->
    <input type="text" v-bind:value="dnumber2" @input="num2Input">
  </div>
</template>


<script>
  const vm = new Vue({
    el: '#app',
    data: {
      num1: 1,
      num2: 0
    },
    methods: {
      // 得到点击而来的value,默认传过来是string类型
      num1change(value) {
        this.num1 = parseFloat(value)
      },
      num2change(value) {
        this.num2 = parseFloat(value)
      }
    },
    // 注册子组件
    components :{
      cpn: {
        template: '#cpn',
        props : {
          cnum1 : {
            type: Number,
          },
          cnum2 : {
            type: Number
          }
        },
        data () {
          return {
            dnumber1 : this.cnum1,
            dnumber2 : this.cnum2
          }
        },
        methods: {
          num1Input (event) {
            // 1.将input中的value赋值到dnumber中
            this.dnumber1= event.target.value
            // 2.为了让父组件可以修改值,发出一个自定义事件
            this.$emit('num1change' , this.dnumber1)
            // 3.同时修改dnumber2的值
            this.dnumber2 = this.dnumber1 * 100
            this.$emit('num2change' , this.dnumber2)
          },
          num2Input (event) {
            this.dnumber2= event.target.value
            this.$emit('num2change' , this.dnumber2)

            // 3.同时修改dnumber1的值
            this.dnumber1 = this.dnumber2 / 100
            this.$emit('num1change' , this.dnumber1)
          }
        }
      } 
    },
  })
</script>

组件访问-父组件访问子组件children{refs}

父组件直接调用子组件里的方法

<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <!-- ref -->
  <cpn ref="aaa"></cpn>
  <button @click="btnClick">案例</button>
</div>

<!-- 模板 -->
<template id="cpn">
  <div>
    我是子组件
  </div>
</template>


<script>
  const vm = new Vue({
    el: '#app',
    data: {},
    methods: {
      btnClick() {
        // 1.$children
        // console.log(this.$children)
        // this.$children[0].showMessage

        // 2.$refs => 对象类型,默认是一个空的对象
        console.log(this.$refs.aaa.showMessage)
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        methods: {
          showMessage() {
            console.log('showMessage')
          }
        }
      }
    }
  });
</script>

组件访问-子访问父-parent-root

<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>
  const vm = 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.name)
               
              //  2.访问跟组件$root
              console.log(this.$root);
              console.log(this.$root,message);
          }
        },
          }
        }
      }
    }
  });
</script>

组件化开发高级—插槽的使用

  1.插槽的基本使用 <slot></slot>
  2.插槽的默认值 <slot>button</slot>
  3.如果有多个值,同时放入到组件进行替换时,一起作为替换元素

(1)插槽的基本使用

<div id="app">
  <cpn><button>按钮</button></cpn>
  <cpn><span>1</span></cpn>
  <cpn><i>2</i></cpn>
  <cpn></cpn>
</div>


<template id="cpn">
  <div>
    <h2>我是组件</h2>
    <p>我是组件,哈</p>
    <!-- 插槽 -->
    <!-- 设定默认值 -->
    <slot><button>按钮</button></slot>
  </div>
</template>

<script>
  const vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    components: {
      cpn : {
        template: '#cpn'
      }
    }
  });

(2)slot具名插槽的使用

<div id="app">
  <cpn><span slot="center">标题</span></cpn>
</div>

<template id="cpn">
  <div>
    <slot name="left"><span>左边</span></slot>
    <slot name="center"><span>中间</span></slot>
    <slot name="left"><span>右边</span></slot>
  </div>
</template>

<script>
  const vm = new Vue({
    el: '#app',
    data: {},
    methods: {},
    components: {
      cpn : {
        template: '#cpn'
      }
    }
  });
</script>

(2)作用域插槽的使用
作用域插槽的主要作用就是:可以换一种展示同种数据的方法。

<div id="app">
<cpn></cpn>
<!-- 换一种方法展示数据 -->
<cpn>
  <!-- 获取子组件中的pLanguages -->
  <template slot-scope="slot">
    <span v-for="items in slot.data">{{items}}--</span>
  </template>
</cpn>
</div>

<template id="cpn">
  <div>
    <!-- 插槽 -->
    <!-- 指向pLanguages -->
    <slot :data="pLanguages">
      <ul>
        <li v-for="items in pLanguages">{{items}}</li>
      </ul>
    </slot>

  </div>
</template>


<script>
  const vm = new Vue({
    el: '#app',
    data: {
    },
    methods: {},
    components: {
      cpn : {
        template: '#cpn',
        data() {
          return {
            pLanguages:['JavaScript','C++','Java','Python']
          }
        }
      }
    }
  });
</script>

结果如下:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值