Vue系统学习:4、组件化开发

1、组件文档链接:https://www.jianshu.com/p/29c514ef3462

1、全局组件和局部组件:

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

  </div>

  <script src="../js/vue.js"></script>

  <script>
    // 1、全局组件
    // Vue.component(组件名称,{
    //   data: 组件数据,
    //   template: 组件模板内容
    // })

    Vue.component('my-cpn', {
      data: () => {
        return { count: 0 }
      },
      template: `<button @click='handle'>点击了{{count}}次</button>`,
      methods: {
        handle() {
          this.count += 2;
        }
      }
    })

    const app = new Vue({
      el: '#app',
      // 2、局部组件
      components: {
        'my-cpn2': {
          template: `<h2>Hello Word</h2>`,
        }
      }
    })
  </script>

  

1.1、HTML代码抽离方法:

  <template id="my-cpn">
    <div>
      <button>点我</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>

  <script>
    Vue.component('my-cpn', {
      template: '#my-cpn',
    })

  

父组件和子组件及其类型,差别只在于子组件没有el挂载点,

取而代之的是 template属性,其余方法几乎是一样的。

  <div id="app">  // 父组件绑定 app

  </div>

  <template id="cpn">  // 子组件绑定cpn
    <div>

    </div>
  </template>

  <script src="../js/vue.js"></script>

  <script>
    const cpn = {         // 父子组件里面结构几乎一样
      template: '#cpn',
      data() {
        return {

        }
      },
      methods: {

      },
    }

    const app = new Vue({
      el: '#app',
      data: {},
      methods: {

      },
      components: { cpn }
    })
  </script>

  

 

父组件和子组件:

①、父组件必须注册子组件。

②、父子组件模板之间只能使用自己组件的数据,不能直接互相使用。

③、父组件和子组件及其类型,差别只在于子组件没有el挂载点,取而代之的是 template属性,其余方法几乎是一样的。


  <!--父组件模板-->
  <div id="app">
    <ul>
      <li v-for='its in city'>{{its}}</li>
    </ul>
    <cpn></cpn>

    <!-- 父组件不能直接使用子组件数据 -->
    <!-- <ul>
      <li v-for='item in movies'>{{item}}</li>
    </ul> -->
  </div>

  <!--子组件模板-->
  <template id="cpn">
    <div>
      <ul>
        <li v-for='item in movies'>{{item}}</li>
      </ul>

      <!-- 子组件也不能直接使用父组件数据 -->
      <!-- <ul>
        <li v-for='items in city'>{{items}}</li>
      </ul> -->
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>
    // 1、这是子组件
    const cpn = {
      template: '#cpn',
      // data中不管有无数据都要return出去
      data() {
        return {
          movies: ['海王', '海贼王', '海尔兄弟']
        }
      },
    }
 
    // 2、这是父组件,里面注册了子组件
    new Vue({
      el: '#app',
      data: {
        city: ['北京', '上海', '广州']
      },
      components: { cpn }
    })
  </script>

  

 

2、父子组件之间的通信:父--->子:props

①、在子组件中使用props接收父组件data数据:子组件定义一个新变量接收数据。

②、字父组件模板中绑定父组件data数据:新变量绑定父组件data里面的变量。

③、在子组件模板中直接使用父组件模板中绑定的数据:子模板中使用绑定了父组件内容的新变量。

  <div id="app">
    <!--v-bind绑定子组件props属性,值=父组件的数据-->
    <cpn v-bind:sonmovies='movies' :soncity='city'></cpn>
  </div>

  <template id="cpn">
    <div>
      <ul>
        <li v-for='item in sonmovies'>{{item}}</li>
      </ul>
      <ul>
        <li v-for='it in soncity'>{{it}}</li>
      </ul>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>
    const cpn = {
      template: '#cpn',
      // props可以是多种数据类型。里面存要引用的变量名(自己定义)
      // props: ['sonmovies', 'soncity'],   数组类型
      props: {     // 对象类型:里面可以定义数据类型以及默认值等等
        sonmovies: {
          type: String,
          default: '我是默认值'
        },
        // 如果数据类型是对象/数组,默认值必须是一个函数
        soncity: {
          type: Array,
          default() {
            return []
          }
        }
      },
      // data中不管有无数据都要return出去
      data() {
        return {}
      },
    }

    new Vue({
      el: '#app',
      data: {
        movies: '海王',
        city: ['北京', '上海', '广州']
      },
      components: { cpn }
    })
  </script>

  

2、父子组件的通信:子--->父:$emit():

  ①、子组件通过$emit('事件名称', 事件参数),将事件发送出去:

this.$emit('sonclick', item)

  ②、父组件模板监听子组件发送出来的事件:

<cpn @sonclick='fatherclick'></cpn>
③、去父组件中定义这个方法

总的来说:首先:子组件用$emit方法将事件传递出去,而父组件则在父组件模板里面监听这个发送的事件,然后在父组件里面定义这个事件。

<!--父模板-->
<div id="app">
  <!--接收子组件发送的事件-->
  <cpn @sonclick='fatherclick'></cpn>
</div>

<!-- // 子模板 -->
<template id="cpn">
  <div>
    <button v-for='item in cate' @click='btnclick(item)'>{{item.name}}</button>
  </div>
</template>

<body>
  <script src="../js/vue.js"></script>

  <script>
    // 1、子组件:在子组件中通过$emit()来触发事件
    const cpn = {
      template: '#cpn',
      data() {
        return {
          cate: [
            { id: '1', name: '热门推荐' },
            { id: '2', name: '手机数码' },
            { id: '3', name: '家用家电' },
            { id: '4', name: '电脑办公' },
          ]
        }
      },
      methods: {
        btnclick(item) {
          // emit发射事件:自定义事件(事件名称,事件参数)
          this.$emit('sonclick', item)
        }
      }
    }

    // 2、父组件
    new Vue({
      el: '#app',
      components: { cpn },
      methods: {
        fatherclick(item) {
          console.log('hello', item);
        }
      },
    })
  </script>

  

③、父子组件相互传递:

  <div id="app">
    <cpn :sonnum='fathernum'></cpn>
  </div>

  <template id="cpn">
    <div>
      <ul>
        <li v-for='item in sonnum'>{{item}}</li>
      </ul>
      <button v-for='(it,index) in city'>{{city[index]}}</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>

  <script>
// 父组件 new Vue({ el: '#app', data: { fathernum: [12, 22, 32, 42] }, methods: { fatherclick(it) { console.log(it); } },
// 子组件 components: { cpn: { template: '#cpn', props: { sonnum: { type: Array } }, data() { return { city: ['北京', '上海', '广州', '深圳'] } }, methods: { btnclick(item) { this.$emit('sonclick', item) } }, } } }) </script>

  

 1、父组件访问子组件:ref

  <div id="app">
    <cpn ref="reference"></cpn>
    <button @click='refclick'>点我</button>

  </div>

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

  <script src="../js/vue.js"></script>

  <script>
    new Vue({
      el: '#app',
      data: {
      },
      methods: {
        refclick() {
      // $refs是一个对象类型,默认是一个空对象,只有传了一个变量之后才会拿到子组件内容 console.log(this.$refs.reference.name); } }, components: { cpn: { template: '#cpn', data() { return { name: '我是子组件的name' } }, methods: { btnclick(item) { this.$emit('sonclick', item) } }, } } }) </script>

  

二、组件插槽:slot

①、定义:为了让封装的组件更加具有扩展性。
②、就是在组件模板中预留一个空间,让使用者决定组件内部的一些内容到底展示什么。

 

1、具名插槽:给插槽起一个名字

  <div id="app">
    <cpn>
      <span slot="left">替换左按钮</span>
      <!-- <i>我是i</i>
      <em>我是em</em> -->
    </cpn>
    <!-- <cpn><i slot="right">替换右按钮</i></cpn> -->
  </div>

  <template id="cpn">
    <div>
      <slot name='left'><button>左按钮</button></slot>
      <slot name='middle'><button>中间按钮</button></slot>
      <slot name='right'><button>右按钮</button></slot>
    </div>

  </template>
  <script src="../js/vue.js"></script>

  <script>
    new Vue({
      el: '#app',
      components: {
        cpn: {
          template: '#cpn'
        }
      }
    })
  </script>

  

2、作用域插槽:父组件替换插槽的标签,但是内容是由子组件来提供。

①、什么是组件作用域:说白了就是父组件模板不可以使用子组件数据;子组件模板不可以使用父组件数据。

a、父组件模板的所有东西都会在父级作用域(父组件)内编译;

b、子组件模板所有东西都会在子级作用域(子组件)内编译。

②、那么如何解决这个插槽不能相互使用的问题呢?

  <div id="app">
    <cpn></cpn>
    <cpn>
      <!-- // 目的是获取子组件中的plaguanges数据 -->
      <template v-slot:slot>
        <div>
          <span>{{slot.data}}-</span>
        </div>
      </template>
    </cpn>

    <cpn>
      <template v-slot:slot>
        <div>
          <span v-for="item in slot.data">{{item}} *</span>
        </div>
      </template>
    </cpn>
  </div>

  <template id="cpn">
    <div>
      <!-- data这个名字是自己定义的 -->
      <slot :data='planguanges'>
        <ul>
          <li v-for='item in planguanges'>{{item}}</li>
        </ul>
      </slot>
    </div>
  </template>

  <script src="../js/vue.js"></script>

  <script>
    new Vue({
      el: '#app',
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              planguanges: ['js', 'java', 'node', 'c++', 'c#']
            }
          },
        }
      }
    })
  </script>

  

 

posted @ 2021-06-06 16:41  Y字仇杀队  阅读(53)  评论(0编辑  收藏  举报