Vue 组件化开发

Vue 组件化介绍

  • 组件化是 Vue 的精髓, Vue 就是由一个一个的组件构成的

  • 组件化思想是笔者认为世界上最美丽的思想, 此时不学, 更待何时!!!

    • (别再跟我说面向对象思想了, 我没有对象~~)

创建组件构造器对象

  • 调用Vue.extend()创建的是一个组件构造器

  • 通常在创建组件构造器时, 传入 template 代表我们自定义组件的模板

  • 该模板就是在使用到组件的地方, 要显示的 HTML 代码

  • 事实上, 这种写法在 Vue2.x 的文档中几乎看不到了, 因为"语法糖"的存在

Vue.extend({
  template: "html 模板代码",

  components: {
    // 注册子组件
  },

  data() {
    return Object;
  },

  methods: {
    // 方法
  },

  props: [] || {} // 获得组件的属性值 数组 | 对象
});

注册组件

  • Vue.component("组件标签名", 构造器对象)

  • 调用Vue.component()是将组件构造器注册为一个组件, 并且给它起了一个组件的标签名称

  • 所以需要传递两个参数:

    1. 注册组件的标签名(在 HTML 中使用该组件的标签名称)
    2. 组件构造器对象

模板代码注意事项

  • 模板代码必须有且只有一个根标签(template 不算根标签)

全局组件

  • 通过 Vue.component 注册的组件即为全局组件

  • 在所有 Vue 实例和所有组件中都可以使用该组件

局部组件

  • 通过 Vue 实例在 options 中的 components 属性中注册的组件

  • 只能在该实例中使用该组件

父子组件

  • 在父构造器中使用 components 属性注册子组件

  • Vue 实例对象也可以看成一个组件, 即根结点 root

  • 子组件只能在直接父组件内使用

    • 若要在 A 组件下使用某个子组件(非 A 注册, 但被其他组件注册过的子组件), 需在 A 组件上注册该子组件
  • 即组件树中, 父结点只能访问直接子结点

    • 若要访问孙子结点, 需要在将孙子结点变成父结点的子结点, 或将孙子结点注册为全局组件

组件语法糖 (!!!推荐写法!!!)

注册全局组件

Vue.component("cpn", {
  template: `
hello world
` });

组册局部组件

  • 该写法是将 template模板 代码直接写入 components(不推荐, 容易造成代码阅读困难)

  • 后面我们将介绍模板分离写法(最主流写法, 也使代码更容易阅读)

components: {
   "cpn": {
    template: `
hello world
` } }

即省略构造器, 直接在构造器参数上填写构造器对象, 内部还是调用了 Vue.extend({...})

模版分离写法

script 标签写法

  • 在 body 中使用 script 标签写模板代码, 且用 id 进行绑定

注册全局组件

Vue.component("cpn", { template: "#cpn" });

注册局部组件

components: {
  "cpn": { template: "#cpn" }
}

template 标签写法

  • 该写法为最常用, 且最实用, 创建 .vue 来抽离组件将更有利于代码阅读和维护

  • 方案一: 在 body 中使用 template 标签写模版代码, 且用 id 进行绑定


  • 方案二(推荐写法): 你也可以创建 .vue 文件

    • 在该文件中写入 template 模版代码
    • 以及组件 JS 逻辑代码
    • CSS 样式代码
  • 且不需要绑定 id, 在注册时引入文件即可

  • 注意:

    • 在父组件中使用子组件时必须将驼峰式转换成用 - 链接的形式

以下为 HelloWorld.vue 文件的 template 实例代码




以下为父组件 template 中使用子组件


  

注册全局组件

Vue.component("cpn", { template: "#cpn" });

注册局部组件

components: {
  "cpn": { template: "#cpn" }
}

组件的 data 数据

  • 组件不可以直接访问 Vue 实例或其他组件中的数据
    • 因为:
      • 组件是一个单独的功能模块的封装, 这个模块有属于自己的 HTML 模板, 也应该有属于自己的数据 data

组件内部属性 data

data() {
  return {
    message: "hello world"
  };
}
  • 注意:
    • 组件中的 data实例中的 data 有区别
    • 组件中的 data 必须是一个函数, 且函数返回一个对象, 变量声明在对象中
    • 因为:
      • 对象是引用类型, 组件可能会被多个实例同时引用
      • 如果 data 值为对象, 将导致多个实例共享一个对象, 其中一个组件改变 data 属性值, 其它实例也会受到影响
    • 上面解释了 data 不能为对象的原因, 这里我们简单说下data为函数的原因
      • data 为函数, 通过 return 返回对象的拷贝, 致使每个实例都有自己独立的对象, 实例之间可以互不影响的改变 data 属性值

组件 data 是函数, 且返回对象的原理

  • 在使用组件时, 因为 data 函数每次调用时会返回一个新的对象

  • 即每个组件的实例得到的 data 都是独立的, 所以组件在使用时的变量就没有连锁反应了

父子组件的通信

下传数据 (父组件传递数据给子组件)

props

  • props 在组件中, 使用选项 props 来声明需要从父级接收到的数据

  • 在父组件模版中, 如果有多个子组件模板, 那么父组件传递给子组件的属性只作用与该子组件的对应模板

    • 即父组件传递给子组件 A 模板, 那么就只有 A 组件有该属性, 子组件的其他模板并没有该属性
  • 注意:

    • Vue 的 v-bind 不支持小驼峰式(即传递失败), 所以一般使用 - 来作为单词分割符
  • 如果 props 属性要写小驼峰式, 那么 v-bind 必须要用 - 来链接单词从而转换成对应的小驼峰属性, 且使用变量时必须是 props 中定义的小驼峰式属性

  • 子组件不能修改 props 属性的值, 应该要让父组件来对 props 的值进行修改

    • 如果需要实现通过下传得到的数据来与子组件进行双向绑定(v-model), 需要使用 data 或 computed 来实现双向绑定
    • 详情参见 "父子组件案例"

props 字符串数组

以下代码为父组件向子组件传递数据




以下代码为子组件接收并使用父组件传递的数据





  • 字符串数组, 数组中的字符串就是传递时的名称, 通过 v-bind 获得父组件的数据

  • 为子组件添加属性, 属性值为父组件的变量值

props 对象

  • 对象可以设置传递时的类型, 也可以设置默认值

  • 类型:

    • String
    • Number
    • Boolean
    • Array
    • Object
    • Date
    • Function
    • Symbol
    • null(匹配任何类型)
props: {
  // 1、类型限制
  cMovies: Arraym,
  cMessage: String

  // 2、提供默认值, 以及使用组件时属性是否为必传值
  cMessage: {
    type: String,
    default: "hello world",
    required: true
  },

  // 3、类型是Array | Object时, 默认值必须是一个函数
  cMovies: {
    type: Array,
    default() {
      return [];
    }
  },

  // 4、多个可能的类型
  cMessage: [String, Number],

  // 5、自定义验证函数
  cMessage: {
    validator(value) {
      // 这个值必须匹配下列字符串中的一个
      return ["success", "warning", "danger"].indexOf(value) !== -1;
    }
  }

  /* 6、自定义类型
     function Zjh() {
       name: "Sunny",
       age: 20
     }
  */
  cMessage: Zjh
}

上传数据 (子组件传递数据给父组件)

自定义事件 Vue.$emit 和 v-on:

  • 同 v-bind 一样不能写驼峰(如果使用Vue脚手架可以写驼峰式)

  • 流程:

    • 子组件的浏览器默认事件触发后
    • 通过 this.$emit("自定义对象名称", 数据)发送事件
      • 自定义事件, 将该自定义事件发送到父组件上

以下代码为子组件模板代码




  • 在父组件中, 通过 v-on 来监听子组件的自定义事件

  • 此时的 cpnClick 省略括号, 则 Vue 会自动把数据传入该事件方法中

    • 因为不是浏览器默认事件, 所以没有 event 对象
  • 此时在父组件的 methods 中实现监听该事件的方法即可获得子传父的数据

以下代码为父组件模板代码




父子组件案例

父组件下传数据, 子组件与自身表单进行双向绑定, 且同时与父组件双向绑定

父组件模板代码




子组件模板代码




父子组件的访问方式

父组件访问子组件

$children

  • 在父组件中使用this.$children即可获得一个数组
    • 该数组中包含了父组件下所有子组件对象 VueComponent

$refs (!!!推荐使用!!!)

  • 在父组件中使用this.$refs获得一个空对象

  • 为这个对象添加子组件即可获得第一个子组件对象




子组件访问父组件

$parent (不推荐使用, 耦合度太高)

  • 在子组件中使用this.$parent即可获得父组件对象
    • 如果是 Vue 实例下的子组件, 则获得 Vue 实例对象Vue
    • 如果不是 Vue 实例下的子组件, 则获得父组件对象VueComponent

访问根组件

$root

  • 在 Vue 实例下, 任意组件通过this.$root即可获得 Vue 的实例对象(Vue)

  • Vue 实例的 root 是自己本身

你可能感兴趣的:(Vue 组件化开发)