美文网首页
组件化开发

组件化开发

作者: 想吃热干面了 | 来源:发表于2020-09-16 08:43 被阅读0次

    一、全局组件和局部组件

    全局组件:即可以在多个Vue实例中使用

    Vue实例1
    <div id="app">
    <cpn></cpn>
    </div>
    Vue实例2
    <div id="app2">
    <cpn></cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
    // 1.创建组件构造器
    const cpnC = Vue.extend({
      template: `
          <div>
            <h2>我是标题</h2>
            <p>我是内容</p>
          </div>`
    })
    //2.注册组件
    Vue.component('cpn',cpnC)
    
    const app = new Vue({
      el: "#app",
      data: {
        message: "你好啊!"
      }
    })
    
    const app2 = new Vue({
      el: "#app2"
    })
    </script>
    

    局部组件:只能在当前Vue实例中使用

    使用:在Vue实例中使用components属性引用
    const app = new Vue({
      el: "#app",
      data: {
        message: "你好啊!"
      },
      components:{
        cpn: cpnC
      }
    })
    

    二、父组件和子组件

    在一个组件中注册另一个组件,这个组件就可以称为另一个组件的父组件,注Vue实例可以看成一个root组件

    <div id="app">
      <cpn2></cpn2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
    //1.创建第一个组件(子组件)
    const cpnC1 = Vue.extend({
      template: `
        <div>
          <h2>我是组件1</h2>
          <p>哈哈哈</p>
        </div>`
    })
    
    //1.创建第二个组件(父组件)
    const cpnC2 = Vue.extend({
      template: `
        <div>
          <h2>我是组件2</h2>
          <p>呵呵呵</p>
          <cpn1></cpn1>
        </div>`,
      components: {
        cpn1: cpnC1
      }
    })
    
    //可以看成root组件
    const app = new Vue({
      el: "#app",
      data: {
        message: "你好啊!"
      },
      components: {
        cpn2: cpnC2
      }
    })
    </script>
    

    三、注册组件的语法糖写法

    全局组件语法糖写法:

    Vue.component('cpn1',{
      template: `
      <div>
        <h2>我是组件1</h2>
        <p>哈哈哈</p>
      </div>`
    })
    

    局部组件语法糖写法:

    const app = new Vue({
      el: "#app",
      data: {
        message: "你好啊!"
      },
      components: {
        'cpn2': {
           template: `
             <div>
              <h2>我是组件2</h2>
              <p>呵呵呵</p>
             </div>`
        }
      }
    })
    

    四、组件模版抽离的写法

    使用script标签或者template标签

    1.script标签 text/x-template类型
    <script type="text/x-template" id="cpn1">
    <div>
      <h2>我是标题1</h2>
      <p>我是内容,哈哈哈</p>
    </div>
    </script>
    
    2.template标签
    <template id="cpn2">
    <div>
      <h2>我是标题2</h2>
      <p>我是内容,呵呵呵</p>
    </div>
    </template>
    
    
    <script src="../js/vue.js"></script>
    <script>
    //1.注册一个全局组件
    Vue.component('cpn',{
      template: '#cpn2'
    })
    

    五、组件中的数据存放问题

    1.组件中不能访问Vue实例中的data数据。但是在注册组件时,组件内可以使用data函数来定义数据

    <div id="app">
      <cpn></cpn>
    </div>
    <template id="cpn">
      <div>
        <h2>{{title}}</h2>
        <p>我是内容 哈哈哈</p>
      </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
      Vue.component('cpn',{
        template: '#cpn',
        data() {
          return {
            title: 'abc'
          }
        }
      })
      const app = new Vue({
        el: "#app",
        data: {
          message: "你好啊!",
          title: "我是标题"
        }
      })
    </script>
    

    2.组件中的data为什么必须是函数

    下面是一个简单的计数器的例子,我们创建3个组件实例,data是函数使得这三个实例间的数据不会相互干扰,即改变其中一个并不会影响到其余组件实例
    <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <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>
    //1.注册组件
    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.通过props向子组件传递数据 父传子
    • 2.通过事件向父组件发送消息 子传父


      父子.png

    (一)props基本用法 父传子

    <div id="app">
      <cpn :cmovies="movies" :cmessage="message"></cpn>
    </div>
    
    <template id="cpn">
    <div>
      <ul>
        <li v-for="item in cmovies">{{item}}</li>
      </ul>
      {{cmessage}}
    </div>
    </template>
    
    <script src="../js/vue.js"></script>
    <script>
    const cpn = {
      template: '#cpn',
      !!!注意:此处未用驼峰写法 下面会有解释
      props: ['cmovies','cmessage'],
      data() {
        return {}
      },
      methods: {
    
      }
    }
    
    const app = new Vue({
      el: "#app",
      data: {
        message: "你好啊!",
        movies: ['海王','海贼王','海尔兄弟']
      },
      components: {
        cpn
      }
    })
    </script>
    
    props除了数组外,还可以用对象
      props: {
        //1.类型限制
        cmovies: Array,
        cmessage: String,
    
        //2.提供一些默认值,以及必传值
        cmessage: {
          type: String,
          default: 'aaaaaa',
          required: true
        },
        //类型是对象或者数组时,默认值必须是一个函数
        cmovies: {
          type: Array,
          default() {
            return []
          }
        }
      },
    

    注意:目前版本v-bind不支持驼峰标识

    例如一下代码 当props中使用驼峰标识
        props: {
          cInfo: {
            type: Object,
            default() {
              return {}
            }
          },
          childMyMessage: ''
        }
    
    如果在绑定时v-bind中也使用驼峰,并不会识别
    <div id="app">
      <cpn :cInfo="info" :childMyMessage="message"></cpn>
    </div>
    
    这时需要做如下转换,就可以正常显示了
    <div id="app">
      <cpn :c-info="info" :child-my-message="message"></cpn>
    </div>
    

    (二)自定义事件 子传父

    1.子组件自定义事件,然后发射给父组件:$emit()
    <template id="cpn">
     <div>
        <button v-for="item in categories"
              @click="btnClick(item)">
          {{item.name}}
        </button>
     </div>
    </template>
    ......
     methods: {
       btnClick(item) {
         // console.log(item);
         //子组件向父组件发射事件:自定义事件
         this.$emit('item-click',item)
       }
     }
    
    2.父组件模版中监听自定义事件
    <!--父组件模版-->
    <div id="app">
    <!--父组件监听子组件发射的事件,并处理 此处不支持驼峰-->
      <cpn @item-click="cpnClick"></cpn>
    </div>
    
    3.父组件中处理
     methods: {
       cpnClick(item) {
         console.log('btnClick',item);
       }
     }
    
    实际上就是使用v-on监听自定义事件
    <!--父组件模版-->
    <div id="app">
      <!--父组件监听子组件发射的事件,并处理 此处不支持驼峰-->
      <cpn @item-click="cpnClick"></cpn>
    </div>
    <!--子组件模版-->
    <template id="cpn">
     <div>
        <button v-for="item in categories"
                @click="btnClick(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: {
         btnClick(item) {
           // console.log(item);
           //子组件向父组件发射事件:自定义事件
           this.$emit('item-click',item)
         }
       }
     }
     //父组件
     const app = new Vue({
       el: "#app",
       data: {
         message: "你好啊!"
      },
       components: {
         cpn
       },
       methods: {
         cpnClick(item) {
           console.log('btnClick',item);
         }
       }
     })
    </script>.
    
    真实项目中,组件会封装在vue文件中,解析成render函数

    (三)父子组件的访问方式

    有时我们需要父组件直接访问子组件,或者子组件直接访问父组件,或者子组件访问跟组件,这是我们可以通过对象方式直接访问
    • 父组件访问子组件:使用children或refs
    • 子组件访问父组件:使用$parent
    1.$children
    一个父组件可能有多个子组件,所以获取的是个数组
    <div id="app">
      <cpn></cpn>
      <cpn></cpn>
      <cpn></cpn>
      <button @click="btnClick">按钮</button>
    </div>
    <template id="cpn">
      <div>
        <h2>我是子组件</h2>
      </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
        },
        methods: {
          btnClick() {
            console.log(this.$children);
            // this.$children[0].showMessage()
            for (let c of this.$children){
              console.log(c.name);
              c.showMessage()
            }
          }
        },
        components: {
          cpn: {
            template: '#cpn',
            data() {
              return {
                name: '我是子组件的name'
              }
            },
            methods: {
              showMessage() {
                console.log('showMessage');
              }
            }
          }
        }
      })
    </script>
    
    2.$refs——对象类型,默认是空对象
    在开发中,并不推荐使用children,当需求取指定第三个子组件时它是通过数组索引去取到,但是如果前面添加了一个新的子组件,我们还需要修改索引值。因此推荐使用$refs
       我们只需要先给要取到的子组件加一个ref属性
    <div id="app">
      <cpn></cpn>
      <cpn></cpn>
      <cpn ref="aaa"></cpn>
      <button @click="btnClick">按钮</button>
    </div>
      然后就可以根据属性名称找到对应的子组件
    methods: {
      btnClick() {
        console.log(this.$refs.aaa.name);
      }
    },
    就是键值对的形式
    
    3.$parent:不推荐使用,会使子组件复用性变差,耦合度提高
    4.$root:访问跟组件,即vue实例
    <div id="app">
      <cpn></cpn>
    </div>
    
    <tempalte id="cpn">
      <div>
        <h2>我是cpn组件</h2>
        <ccpn></ccpn>
      </div>
    </tempalte>
    
    <tempalte id="ccpn">
      <div>
        <h2>我是ccpn组件</h2>
        <button @click="btnClick">按钮</button>
      </div>
    </tempalte>
    
    <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() {
                    console.log(this.$parent);
                    console.log(this.$parent.name);
                    console.log(this.$root.message);
                  }
                }
              }
            }
          }
        }
      })
    </script>
    

    七、watch属性

    watch来监测Vue实例上的数据变动
    <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">
        <h2>props:{{number2}}</h2>
        <h2>data:{{dnumber2}}</h2>
        <input type="text" v-model="dnumber2">
      </div>
    </template>
    
    <script src="../js/vue.js"></script>
    <script>
    const app = new Vue({
      el: "#app",
      data: {
        num1: 1,
        num2: 0,
      },
      methods: {
        num1change(value) {
          this.num1 = parseFloat(value)
        },
        num2change(value) {
          this.num2 = parseFloat(value)
        }
      },
      components: {
        cpn: {
          template: '#cpn',
          props: {
            number1: Number,
            number2: Number,
          },
          data() {
            return {
              dnumber1: this.number1,
              dnumber2: this.number2,
            }
          },
          //使用watch监视dNumber值的改变
          watch: {
            dnumber1(newValue) {
              this.dnumber2 = newValue * 100;
              this.$emit('num1change',newValue);
            },
            dnumber2(newValue) {
              this.dnumber1 = newValue / 100;
              this.$emit('num2change',newValue);
            }
          }
        }
      }
    })
    </script>

    相关文章

      网友评论

          本文标题:组件化开发

          本文链接:https://www.haomeiwen.com/subject/dvigdktx.html