Vue组件化开发

上期回顾

  • 条件判断(v-if、v-show)的基本使用、开发时选择
  • 条件渲染案例(input添加key的区别)
  • 循环遍历(v-for)
  • 表单绑定(v-model)
  • lazy修饰符
  • number修饰符
  • trim修饰符
  • 拓展:数组的响应式方法

什么是组件化:

独立的,可复用的,整体化的一个功能模块

为什么要组件化:

1.实现功能模块的复用
2.开发单页面复杂应用
3.高效执行


组件化开发

注册组件

三大步骤
1.创建组件构造器( Vue.extend() )
2.注册组件( Vue.component() )
3.使用组件

  • 代码演练
  <div id="app">
    <!-- 第三步:使用组件 -->
    <my-cpn></my-cpn>
    <!-- 错误的使用方式 -->
    <myCpn></myCpn>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    //第一步:创建组件构造器
    let cpn = Vue.extend({
      template: `
      <div>
        <h2>我是组件</h2>
      </div>
      `
    })

    //第二步:注册组件
    Vue.component("myCpn", cpn)

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

      }
    })
  </script>
组件的使用

注意:
第三步不能使用小驼峰命名,大写字母变为小写字母,前面加 "-"

Vue.extend({template})
Vue.extend():返回一个组件构造器
template:代表自定义组件的html模板
Vue.vomponent("组件命名",组件构造器)
Vue.vomponent():注册组件


全局组件和局部组件

  • 代码演示
  <div id="app1">
    <!-- 全局 -->
    <global-cpn></global-cpn>
    <!-- 局部 -->
    <part-cpn></part-cpn>
  </div>
  <div id="app2">
    <!-- 全局 -->
    <global-cpn></global-cpn>
    <!-- 局部 -->
    <part-cpn></part-cpn>
  </div>

  <script src="./js/vue.js"></script>
  <script>
    //1.创建全局组件构造器
    let cpn1 = Vue.extend({
      template: `
          <div>
            <h2>我是全局组件</h2>  
          </div>
        `
    })
    //1.创建局部组件构造器
    let cpn2 = Vue.extend({
      template: `
          <div>
            <h2>我是局部组件</h2>  
          </div>
        `
    })

    //2.注册全局组件
    Vue.component("globalCpn", cpn1)
    const app1 = new Vue({
      el: "#app1",
      //第二步:注册局部组件
      components: {
        "partCpn": cpn2
      }
    })
    const app2 = new Vue({
      el: "#app2"
    })
  </script>
全局组件和局部组件

父组件和子组件

  • 代码演示
  <div id="app">
    <!-- 使用父组件 -->
    <father-cpn></father-cpn>
  </div>

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

    //1.创建子组件构造器
    let cpn2 = Vue.extend({
      template: `
          <div>
            <h2>我是子组件</h2>  
          </div>
        `
    })

    //1.创建父组件构造器
    let cpn1 = Vue.extend({
      template: `
          <div>
            <h2>我是父组件</h2>
            <!-- 使用子组件 -->
            <son-cpn></son-cpn>
          </div>
        `,
      //在父组件中挂载子组件
      components: {
        "sonCpn": cpn2
      }
    })

    const app1 = new Vue({
      el: "#app",
      //在全局组件中挂载父组件
      components: {
        "fatherCpn": cpn1
      }
    })
  </script>
父组件和子组件

组件的简写方式

  • 代码演示
  <div id="app">
    <!-- 使用全局组件 -->
    <global-cpn></global-cpn>
    <!-- 使用局部组件 -->
    <part-cpn></part-cpn>

  </div>

  <script src="./js/vue.js"></script>
  <script>
    // 创建全局组件
    Vue.component("globalCpn", {
      template: `
        <div>
          <h2>我是全局组件</h2>
        </div>
      `
    })

    const app1 = new Vue({
      el: "#app",
      // 创建局部组件
      components: {
        "partCpn": {
          template: `
            <div>
              <h2>我是局部组件</h2>
            </div>
          `
        }
      }
    })
  </script>
组件简写

省去了Vue.extend()的步骤,直接用一个对象代替


模板的两种分离写法

1.使用<script>标签

  • 代码演示
  <div id="app">
    <my-cpn></my-cpn>
  </div>
  <!-- 使用<script>标签,注意加上type属性和id属性 -->
  <script type="text/x-template" id="myCpn">
    <div>
      <h2>我是组件</h2>
    </div>
  </script>
  <script src="./js/vue.js"></script>
  <script>
    const app1 = new Vue({
      el: "#app",
      // 创建局部组件
      components: {
        "myCpn": {
          template: "#myCpn"
        }
      }
    })
  </script>
使用<script>标签

2.使用<template>标签(推荐)

  • 代码演示
  <div id="app">
    <my-cpn></my-cpn>
  </div>
  <!-- 使用<template>标签,注意加上id属性 -->
  <template id="myCpn">
    <div>
      <h2>我是组件</h2>
    </div>
  </template>
  <script src="./js/vue.js"></script>
  <script>
    const app1 = new Vue({
      el: "#app",
      // 创建局部组件
      components: {
        "myCpn": {
          template: "#myCpn"
        }
      }
    })
  </script>
使用<template>标签(推荐)

注意:
使用两种标签,主要是将template中的html模板抽离出去,所以,两种标签一定要加上id属性,用于template的绑定


组件数据的处理

  • 代码演示
  <div id="app">
    {{message1}} - {{message2}}
    <my-cpn></my-cpn>
  </div>
  <template id="myCpn">
    <div>
      <h2>{{message1}}</h2>
      <h2>{{message2}}</h2>
    </div>
  </template>
  <script src="./js/vue.js"></script>
  <script>
    cpn = {
      "myCpn": {
        template: "#myCpn",
        // 数据存放在组件内部,组件可以访问,全局不能
        data() {
          return {
            message2: "组件内的数据"
          }
        },
      }
    }

    const app1 = new Vue({
      el: "#app",
      components: cpn,
      // 数据存放在实例的data内,全局可以访问在组件中无法访问
      data() {
        return {
          message1: "实例内的数据"
        }
      },
    })
  </script>
组件数据的处理
注意:

组件中data必须是函数:这样可以保证组件每次使用的数据不会被别的组件更改,保证各组件间的数据互不干扰,data不是函数时,会报错!!!


组件间的数据传递(父传子)

props基本用法
  • 代码演示
  <div id="app">
    <!-- 1.通过v-bind绑定数据message -->
    <my-cpn :info="message"></my-cpn>
  </div>
  <template id="myCpn">
    <div>
      <!-- 3.展示组件内props的数据 info -->
      <h2>{{info}}</h2>
    </div>
  </template>
  <script src="./js/vue.js"></script>
  <script>
    cpn = {
      "myCpn": {
        template: "#myCpn",
        // 2.接收组件标签绑定的数据
        props: ["info"]
      }
    }

    const app1 = new Vue({
      el: "#app",
      components: cpn,
      data: {
        message: "hello Vue"
      }
    })
  </script>
props基本用法

注意数据传递过程:
1.通过v-bind绑定数据messag
2.接收组件标签绑定的数据
3.展示组件内props的数据 info

props数据验证
  • 代码演示
  <div id="app">
    <my-cpn :info="message" :addNum="add()" :num="num3"></my-cpn>
  </div>

  <template id="myCpn">
    <div>
      <h2>{{info}}</h2>
      <h2>{{addNum}}</h2>
      <h2>{{num}}</h2>
      <h2>{{str}}</h2>
    </div>
  </template>

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

    const app = new Vue({
      el: "#app",
      data: {
        message: "hello Vue",
        num1: 3,
        num2: 5,
        num3: 10,
        str: "test"
      },
      methods: {
        add() {
          console.log(this.num1 + this.num2)
        }
      },
      components: {
        "my-cpn": {
          template: "#myCpn",
          props: {
            // key:类型
            info: String,
            addNum: Function,
            num: {
              type: Number,
              // 设为必填值
              required: true,
            },
            str: {
              type: String,
              // 设置默认值
              default: "我是默认值"
            }
          }
        }
      }
    })
  </script>
props数据验证
  • props支持验证类型
    String
    Number
    Array
    Boolean
    Function
    Object
    Date
    Symbol

组件间的数据传递(子传父)

  • 代码演示
  <div id="app">
    <h2>{{num}}</h2>
    <!-- 第四步:  将子组件传出的函数转为自定义函数,并绑定自定义事件的实现函数-->
    <son-cpn :amount="num" @add="change" @cut="change"></son-cpn>
  </div>

  <template id="myCpn">
    <div>
      <!-- 第一步: 绑定事件 -->
      <button @click="add">加10</button>
      <button @click="cut">减10</button>
    </div>
  </template>

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

    const app = new Vue({
      el: "#app",
      data: {
        num: 1
      },
      methods: {
        // 第五步: 实现自定义事件的函数
        // count 是第三步传入的参数
        change(count) {
          this.num = count
        }
      },
      components: {
        "sonCpn": {
          template: "#myCpn",
          props: {
            amount: {
              type: Number,
              required: true,
            }
          },
          data() {
            return {
              count: this.amount
            }
          },
          methods: {
            // 第二步: 事件函数的实现
            add() {
              this.count += 10
              // this.amount += 10  避免直接改变属性,因为当父组件重新呈现时,该值将被覆盖。

              // 第三步: 使用 emit("函数名",参数) 通知父组件,并传递参数
              this.$emit("add", this.count)
            },
            cut() {
              this.count -= 10
              // this.amount += 10 避免直接改变属性,因为当父组件重新呈现时,该值将被覆盖。
              
              // 第三步: 使用 emit("函数名",参数) 通知父组件,并传递参数
              this.$emit("cut", this.count)
            }
          }
        }
      }
    })
组件间的数据传递(子传父)

注意一

注意二

数据传递(子传父)过程
1.在子组件中,通过$emit("事件名",参数)来触发事件。
2.在父组件中,通过v-on来监听子组件事件。

父组件直接访问子组件的数据($children、$refs)

  • 代码演示
  <div id="app">
    <f-cpn></f-cpn>
  </div>

  <!-- 子组件模板 -->
  <template id="zCpn">
    <div>
      <h2>我是子组件</h2>
      <h2>{{info}}</h2>
      <h2>调用方法:{{mult}}</h2>
    </div>
  </template>

  <!-- 父组件模板 -->
  <template id="fCpn">
    <div>
      <h2>我是父组件</h2>
      <!-- 通过ref给某一个子组件绑定一个特定的ID -->
      <z-cpn ref="child"></z-cpn>
      <button @click="access$children">通过$children访问子组件</button>
      <button @click="access$refs">通过$refs访问子组件</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>
    //子组件实例
    let zCpn = {
      template: "#zCpn",
      data() {
        return {
          info: "我是子组件数据",
          num: 2
        }
      },
      computed: {
        mult() {
          return this.num * 3
        }
      }
    }

    const app = new Vue({
      el: "#app",
      data: {
      },
      components: {
        // 注册父组件
        "f-cpn": {
          template: "#fCpn",
          components: {
            // 注册子组件
            "z-cpn": zCpn
          },
          methods: {
            access$children() {
              // 通过$children访问子组件
              console.log(this.$children)
              console.log(this.$children[0].info)
              console.log(this.$children[0].mult)
              // console.log(this.$children[0].mult())    ❌错误写法,mult是计算属性,不是函数
            },
            access$refs(){
              // 通过$refs访问子组件
              console.log(this.$refs)
              console.log(this.$refs.child)
              console.log(this.$refs.child.info)
              console.log(this.$refs.child.mult)
              // console.log(this.$refs.child.mult())       ❌错误写法,mult是计算属性,不是函数
            }
          }
        }
      }
    })
  </script>
$children的使用

$refs的使用

总结:

  • $children需要通过子组件的下标($children[index]),才能访问该子组件,易出错,
  • $refs是通过ref绑定的ID访问子组件($refs.ID),更加精确到位,推荐使用$refs

子组件直接访问父组件的数据($parent)

  • 代码演示
  <div id="app">
    <f-cpn></f-cpn>
  </div>

  <!-- 子组件模板 -->
  <template id="zCpn">
    <div>
      <h2>我是子组件</h2>
      <button @click="getFInfo">点击获取父组件的信息</button>
    </div>
  </template>

  <!-- 父组件模板 -->
  <template id="fCpn">
    <div>
      <h2>我是父组件</h2>
      <z-cpn></z-cpn>
    </div>
  </template>

  <script src="../js/vue.js"></script>
  <script>
    //子组件实例
    let zCpn = {
      template: "#zCpn",
      methods: {
        getFInfo() {
          console.log(this.$parent)
          console.log(this.$parent.info)
          this.$parent.show()
        }
      }
    }

    const app = new Vue({
      el: "#app",
      data: {
      },
      components: {
        // 注册父组件
        "f-cpn": {
          template: "#fCpn",
          components: {
            // 注册子组件
            "z-cpn": zCpn
          },
          data() {
            return {
              info: "我是父组件信息"
            }
          },
          methods: {
            show(){
              console.log("通过$parent访问父组件的方法")
            }
          }
        }
      }
    })
  </script>
$parent的使用

注意:
在开发中尽量避免子组件通过$parent直接访问父组件的数据,因为这样耦合度太高了。而且这样会使父组件中的状态将变得飘忽不定,很不利于我的调试和维护。

插槽(slot)的使用

插值基本用法
  • 代码演示
  <div id="app">
    <div>==========单个slot使用==========</div>
    <my-cpn1></my-cpn1>
    <my-cpn1>
      <!-- 填入内容替换插槽 -->
      <h2>hello vue</h2>
    </my-cpn1>
    <div>==========具名solt使用==========</div>
    <!-- 如果my-cpn2内部没有内容,具名插槽不会显示,不具名插槽会显示,如my-cpn1 -->
    <my-cpn2></my-cpn2>
    <!-- 如果my-cpn2内部所有的标签都绑定了具名插槽,则不具名的插槽不会显示 -->
    <my-cpn2>
      <div name="content1"><h2>替换文字1</h2></div>
      <div name="content2"><h2>替换文字2</h2></div>
      <div name="content3"><h2>替换文字3</h2></div>
    </my-cpn2>
  </div>
  <template id="mySlot1">
    <div>
      <!-- 设置一个插槽 -->
      <slot>默认内容</slot>
    </div>
  </template>
  <template id="mySlot2">
    <div>
      <!-- 设置一个插槽 -->
      <slot><h2>默认内容3</h2></slot>
      <!-- 设置三个具名插槽 -->
      <slot slot="content1"><h2>默认内容1</h2></slot>
      <slot slot="content2"><h2>默认内容2</h2></slot>
      <slot slot="content3"><h2>默认内容3</h2></slot>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>

    const app = new Vue({
      el: "#app",
      components: {
        myCpn1: {
          template: "#mySlot1"
        },
        myCpn2: {
          template: "#mySlot2"
        }
      }
    })
  </script>
插槽(slot)的使用
slot数据传递
  • 代码演示
  <div id="app">
    <my-cpn>
      <!-- 第二步: 接收数据 -->
      <template slot-scope="props">
        <ul>
          <!-- 第三步: 使用数据 -->
          <li v-for="(value,index) in props.info">{{index}} - {{value}}</li>
        </ul>
      </template>
    </my-cpn>
  </div>
  <template id="mySlot">
    <div>
      <!-- 第一步: 绑定数据 -->
      <slot :info="course"></slot>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>

    const cpn = {
      template: "#mySlot",
      data() {
        return {
          course: {
            1001: "Python入门",
            1002: "数据结构与算法",
            1003: "离散数学",
            1004: "概率论",
            1005: "形式与政策",
          }
        }
      }
    }

    const app = new Vue({
      el: "#app",
      components: {
        myCpn: cpn
      }
    })
  </script>
slot数据传递

注意:

注意

编译作用域(补充)

  • 代码演示
  <div id="app">
    <my-cpn v-if="isShow">
    </my-cpn>
  </div>
  <template id="mySlot">
    <div>
      <slot>默认数据</slot>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>

    const cpn = {
      template: "#mySlot",
      data() {
        return {
          isShow: false
        }
      }
    }

    const app = new Vue({
      el: "#app",
      components: {
        myCpn: cpn
      },
      data: {
        isShow: true
      }
    })
  </script>
编译作用域一

编译作用域二

注意:任意组件模板的所有东西都会在该模板作用域内编译,即变量会从该实例中寻找

END
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 组件化开发步骤:1.创建组件构造器 Vue.extend({})2.注册组件 Vue.component()3.使...
    似朝朝我心阅读 3,089评论 0 7
  • 一、什么是组件化开发 人面对复杂问题的处理方式:任何一个人处理信息的逻辑能力都是有限的所以,当面对一个非常复杂的问...
    c_gentle阅读 6,483评论 0 1
  • 认识组件化 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展...
    独调1997阅读 4,166评论 0 0
  • 组件化开发思想 现实中的组件化思想体现(1)标准(2)分治(3)重用(4)组合 编程中的组件化思想体现 组件化规范...
    辽A丶孙悟空阅读 5,878评论 1 19
  • 组件其实就是一个拥有样式、动画、js逻辑、HTML结构的综合块。前端组件化确实让大的前端团队更高效的开发前端项目。...
    IT老马阅读 4,179评论 0 1