Vue组件化梳理

一、组件化

(1):全局组件与局部组件的定义

组件定义的步骤:
1:组件注册
2:组件的模板定义与绑定
3:组件的使用
注意点:
/*全局组件
01:全局组件:Vue.component(name,options)
name:为组件名称
options:为组件的配置参数(是个对象)
template:只能是有一个根节点

  组件用途:
    复用---(每一次返回一个对象)为了达到复用的时候,每一个为独立的数据

  三段论:
    大前提:Vue有着以下配置参数(data,directives,methods等)
    小前提:组件是一个Vue实例
    结论:组件具有与Vue实例一样的配置参数 但是没有el,其中data必须为函数(返回一个对象)
 */
 <div id="app">
    <!-- 3:使用组件 -->
    <cpm></cpm>

  </div>
  <!-- 2-1定义模板 -->
  <template id="cpm">
    <div>
      <!--02: 使用局部组件 -->
      <my-header></my-header>
      my name is {{name}},我今年{{age}}。
      <my-footer></my-footer>
    </div>
  </template>

  //1:定义一个全局组件
    Vue.component('cpm', {
      data() {
        return {
          name: 'liang',
          age: 22,
          sex: 'nan'
        }
      },
      //2-2:利用选择器绑定模板
      template: "#cpm",
      //01:定义局部组件
      components: { //全局组件里面可以定义局部组件
        myHeader: { //header为局部组件名称,{}为配置参数
          template: `<header>cpm组件的头部</header>`
        },
        myFooter: {
          template: `<footer>cpm组件的尾部</footer>`
        }
      },
      methods: {

      }
    })
    //这是根组件
    const vm = new Vue({
      el: "#app",
      data: {

      },
      methods: {

      },
      directives: {

      },
      componets: {

      }
    })

二、父子组件的通讯

//父子组件的通讯
// 一般而言,一些数据都是在大组件发送请求数据,然后向下层传递数据
// 父子间的通讯有两种方式
//1:通过props属性向子组件传递数据
//2:通过事件向父组件发送消息

  2:props属性名命名规则
    01:如果props中使用驼峰命名法,模板中(html)则需要使用-来划分(buttonContent :button-content)
    02:字符串形式的模板则没有这个限制
  3:props属性值类型
    01:字符串-String  02:数值-number
    03:布尔值-boolean  04:数组-Array 05:对象-Object---常用
// 注意点:首先是父组件的数据(本身定义一个局部组件),然后通过属性绑定的方式, ,然后在子组件里面通过props属性接受

(1): 父组件向子组件传值

步骤:
1:定义父组件—里面定义行数据
2:再父组件内部定义一个局部组件(子组件用于接收父组件传递值)
注意点:在里面使用了 对象的字面量增强写法 本来是cpm:cpm
3:对子组件的抽离出去的进行定义–
01:模板的定义和绑定
02:数据的传递与接收 传递是在Vue实例中(cpm例如属性的绑定来传递的),props接收传递的值
03:其中prop可以输数组,对象,字符串等 可以提高默认值
04:最后在模板中使用数据

 <div id="app">
    <!-- 2:使用父组件来传递值  通过属性的绑定,子组件绑定承接父组件的数据-->
    <cpm :cmovies="movies" :cmsg="msg"></cpm>
  </div>
  <!--02: 子组件的模板 -->
  <template id="cpm">
    <div>
      <!-- 03:最后引用数据 -->
      <ul>
        <li v-for="item in cmovies">{{cmsg +'-'+ item}}</li>
      </ul>
    </div>
  </template>

  //01-2:子组件的定义(抽离出来)
    const cpm = {
      template: '#cpm',
      // props: ['cmovies', 'cmsg'],//数组类型
      props: { //其中prop可以输数组,对象,字符串等  可以提高默认值
        cmovies: {
          type: Array,
          defalute() { //类型为数组或者对象的时候,默认值是一个函数,有返回值(数组或者对象)
            return []
          },
          required: true, //必须传递这个属性
        },
        cmsg: {
          type: String
        }
      }
    }
    //1:定义父组件
    const vm = new Vue({
      el: "#app",
      data: {
        msg: '你好啊',
        movies: ['火影', '蓝色', '佳佳']
      },
      // 01-1:定义子组件
      components: {
        // 'cpm': {
        //   //假如是 'cpm':cpm的话,则是被抽离到外部,需要在外面定义组件 const cpm  
        // },
        cpm //或者直接简写 cpm(则是被抽离到外部,需要在外面定义组件 const cpm  ) 
        // 对象的字面量增强写法 本来是cpm:cpm
      }
    });

(2): 父组件向子组件传值(驼峰写法)


<body>
  <div id="app">
    <!--3 组件定义的属性为驼峰的时候,在html这边,需要以-来拆分, -->
    <cpm :c-info="info" :c-msg="msg"></cpm>
  </div>
  <!-- 02:子组件模板 -->
  <template id="cpm">
    <div>
      <h2>{{cInfo}}</h2>
      <p>{{cMsg}}</p>
    </div>

  </template>
  <script src="../js/vue.js"></script>
  <script>
    //父传子-props驼峰标识
    //01:子组件
    const cpm = ('cpm', {
      data() {
        return {}
      },
      //03:接受模板和接受数据
      template: '#cpm',
      props: {
        cInfo: {
          type: Object,
          defalute() {
            return {}
          }
        },
        cMsg: {
          type: String,
          defalute: 'aaaa',
        }
      }
    })
    //1-父组件
    const vm = new Vue({
      el: "#app",
      data: {
        msg: '你好啊',
        info: {
          uname: 'why',
          sex: '男',
          age: 18
        }
      },
      //2:定义一个局部组件
      components: {
        cpm
      }
    });
  </script>
</body>

(3): 子组件向父组件传值

/*
子组件向父组件发送数据的步骤:
01:定义子组件
02:子组件模板 并且子子组件进行绑定(id)
03:对子组件内的数据进行定义并且在模板渲染
04-子组件向父组件发送点击事件
  注意点:1:子组件发射事件1-定义btnclick事件(并且发生参数)
         2:子组件发射事件2-btnclick事件 发射事件itemclick(自定义一个事件)
         3:子组件发射事件3,在父组件(引用了cpm组件)监听该事件,并且化为cpmclick事件再父组件处理
         4:在父组件的方法里面,做输出等
*/
   <!-- 父组件模板 -->
  <div id="app">
    <!-- 子组件发射事件,在父组件监听该事件,并且化为cpmclick事件再父组件处理 -->
    <cpm @itemclick="cpmclick"></cpm>
  </div>
  <!-- 子组件模板 -->
  <template id="cpm">
    <div>
      <ul>
        <!-- 子组件发射事件1-定义btnclick事件 -->
        <li v-for="(item,index) in catagories" @click="btnclick(item)">{{item.name}}</li>
      </ul>
    </div>
  </template>
  
//01-2:定义一个子组件模板和内容
    const cpm = {
      data() {
        return {
          catagories: [{
              id: 1,
              name: '胡奥'
            },
            {
              id: 2,
              name: '电器'
            }, {
              id: 3,
              name: '号码'
            }
          ]
        }
      },
      template: '#cpm',
      methods: {
        // 子组件发射事件2-btnclick事件 发射事件itemclick
        btnclick(item) {
          this.$emit('itemclick', item);
        }
      }
    }

    //1:定义父组件
    const vm = new Vue({
      el: "#app",
      data: {},
      //01-1:定义一个子组件
      components: {
        cpm
      },
      methods: {
        cpmclick(item) {
          console.log(item);
        }
      }
    })

三、组件访问

(1):父访问子

 <!-- 父组件 -->
  <div id="app">
    <cpm></cpm>
    <cpm></cpm>
    <cpm ref="aaa"></cpm>
    <button @click="btnclick">点击</button>
  </div>
  <!-- 02-1:子组件模板 并且子子组件进行绑定(id) -->
  <template id="cpm">
    <div>
      我是子组件的
    </div>
  </template>

 //01:定义一个父组件
    const vm = new Vue({
      el: "#app",
      data: {},
      methods: {

      },
      methods: {
        btnclick() {
          //1:利用$children来访问子组件的内容
          // console.log(this.$children);
          // this.$children[0].showMsg();
          // for (let i of this.$children) {
          //   console.log(i.name);
          // }
          //2:使用$refs来访问子组件的内容---常用 
          //2-1:首先需要定义ref属性(html中,并且有一个属性值,证明你需要取得的某个组件)例如:ref="aaa"
          this.$refs;
          console.log(this.$refs.aaa.name);
        }
      },
      //02:定义局部组件 组件{模板-数据-方法}
      components: {
        cpm: {
          template: '#cpm',
          data() {
            return {
              name: '我是子组件的name'
            }
          },
          methods: {
            showMsg() {
              console.log('showMsg');
            }
          }
        },
      }
    });

(1):子访问父

 <div id="app">
    <cpm></cpm>
  </div>
  <template id="cpm">
    <div>
      <h2>我是子组件</h2>
      <button @click="btnClick">点击</button>
    </div>
  </template>

//点击子组件的按钮,访问父组件的数据
    const vm = new Vue({
      el: "#app",
      data: {},
      components: {
        cpm: {
          template: '#cpm',
          methods: {
            btnClick() {
              //1:访问父组件---通过$parent
              console.log(this.$parent);
              //2:访问根组件
              console.log(this.$root);
            }
          }
        }
      }
    });

四、插槽

(1):插槽的基本使用

slot插槽
目的:是的原来的设备具有更多的扩展性(slot标签:就是给组件留下预留空间)

1:就是在组件内部定义一个<slot></slot>标签
2:插槽里面的默认值:<slot><button>按钮</button></slot> 
	假如cpm组件里面,在父组件使用的时候,里面没有任何标签,那么会加入button默认值
3:插槽的替换:<slot><button>按钮</button></slot> 
	假如cpm组件里面,在父组件使用的时候,里面没有有标签,那么会其他的标签作为整体把button替换了

  <div id="app">
    <!-- 在组件内部,添加button,替代带那个slot标签 -->
    <cpm><button>按钮</button></cpm>
    <cpm><span>我啊</span></cpm>
    <cpm>
      <i>我</i>
      <div>123</div>
    </cpm>
  </div>
    <template id="cpm">
    <div>
      <h2>我是组件插槽的基本使用</h2>
      <p>WPS组件</p>
      <slot><button>默认按钮</button></slot>
    </div>
  </template>

    const vm = new Vue({
      el: "#app",
      data: {},
      components: {
        cpm: {
          template: "#cpm"
        }
      }
    });

(2):具名插槽的使用

具名插槽:
1:就是给标签起一个名字 比如 左边
2:使用的时候,需要替换那个插槽,就再父组件使用组件的时候,把插槽内的标签添加slot=“要修改的标签”
比如: 标题

  <div id="app">
    <!-- 在组件内部,添加button,替代带那个slot标签 -->
    <cpm><span slot="center">标题</span></cpm>
    <cpm><button slot="center">按钮</button></cpm>
  </div>
  <template id="cpm">
    <div>
      <slot name="left"><span>左边</span></slot>
      <slot name="center"><span>中间</span></slot>
      <slot name="right"><span>右边</span></slot>
      <!-- <slot>11</slot> -->
    </div>

   const vm = new Vue({
      el: "#app",
      data: {},
      components: {
        cpm: {
          template: "#cpm"
        }
      }
    });

(3):作用域

 <!-- 父组件 作用域在父组件内 -->
  <div id="app">
    <cpm v-show="isShow"></cpm>
  </div>
  <!-- 子组件 作用域在子组件内,所以这个isShow为false -->
  <template id="cpm">
    <div>
      <h2>我是子组件</h2>
      <p>我是内容</p>
      <button v-show="isShow">阿牛</button>
    </div>
  </template>

  const vm = new Vue({
      el: "#app",
      data: {
        msg: "你好啊",
        isShow: true
      },
      components: {
        cpm: {
          template: "#cpm",
          data() {
            return {
              isShow: false
            }
          }
        }
      }
    })

(4):作用域插槽的使用

/*作用域插槽:
  父组件替换插槽标签,但是内容由子组件来提供

  案例:子组件有着以下数据:  pLanguages:['JS','PY','C',"C++"]
    1:需要在某些界面以水平方向一一展示
    2:某些界面是以列表形式展示
    3:某些界面直接展示一个数组
  内容在子组件,希望父组件怎么展示? --- 利用slot作用域插槽就可以了
*/
    /*
    步骤:
      1:在子组件内部使用一个插槽作用域,由于是获取数据,定义为data
      2:在父组件内部使用子组件的时候,在子组件内部,定义一个template标签,并且通过slot-scope="slot" 来引用插槽的数据
      3:由于数据存在了slot.data,使用它即可
    */
  <div id="app">
    <cpm></cpm>
    <cpm>
      <!-- 目的:就是获取子组件的pLanguages  使用template标签里面定义slot-scope="slot" 来引用插槽的数据 -->
      <template slot-scope="slot">
        <!-- <span v-for="item in slot.data">{{item + ' '}}</span> -->
        <span>{{slot.data.join('-')}}</span>
      </template>
    </cpm>
        <cpm>
      <template slot-scope="slot">
        <ul>
          <li>{{slot.data}}</li>
        </ul>
      </template>
    </cpm>
  </div>
  <template id="cpm">
    <div>
      <slot :data="pLanguages">
        <ul>
          <li v-for="item in pLanguages">{{item}}</li>
        </ul>
      </slot>
    </div>
  </template>

  const vm = new Vue({
      el: "#app",
      data: {

      },
      components: {
        cpm: {
          template: "#cpm",
          data() {
            return {
              pLanguages: ['JS', 'PY', 'C', "C++"]
            }
          }
        }
      }
    })
发布了12 篇原创文章 · 获赞 2 · 访问量 299

猜你喜欢

转载自blog.csdn.net/weixin_43845137/article/details/105152146