Twlig / issuesBlog

MIT License
3 stars 0 forks source link

组件 #34

Open Twlig opened 2 years ago

Twlig commented 2 years ago

组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。只是没el 这样根实例特有的选项。

组件名

  1. kebab-case(短横线分隔命名)

    • 定义组件
    Vue.component('my-component-name', { /* ... */ })
    • 引用组件
    <div id="app">
     <my-component-name></my-component-name>
    </div>
  2. PascalCase(首字母大写命名)

    • 定义组件
    Vue.component('MyComponentName', { /* ... */ })
    • 引用这个自定义元素时两种命名法都可以使用。
     <my-component-name></my-component-name>
     <MyComponentName></MyComponentName>

    注意:直接在 DOM (即非字符串的模板)如:在单个组件的<template></template>中 或者 index.html中直接CDN引入vue.js的<div id="app"></div>中,使用时只有 kebab-case 是有效的。

建议:定义时两种方式都可以,引用使用kebab-case。不过为了统一还是建议定义和引用都用kebab-case

组件注册

组件注册有全局注册和局部注册两种。

  1. 全局注册

    全局注册的组件注册之后可以用在任何新建的Vue根实例的模板中。因为component相当于直接挂载在Vue属性上。所有Vue实例都可以共享该属性。

    //全局注册
    Vue.component('my-component-name', {
     // ... 选项 ...
    })
    new Vue({ el: '#app' })
    <!--使用-->
    <div id="app">
     <my-component-name></my-component-name>
    </div>
  2. 局部注册

    全局注册所有的组件意味着即便已经不再使用一个组件了,它仍然会被包含在最终的构建结果中。这造成了用户下载的 JavaScript 的无谓增加。

    因此可以局部注册:

    同文件局部注册

    定义组件和注册组件在一个文件内

    1. 定义组件
      var ComponentA = { /* ... */ }
    2. 局部注册组件

      所谓局部注册就是在Vue实例上注册,只有该实例可以使用,其他Vue实例需要自己注册才能使用。

      new Vue({
      el: '#app',
      components: {
        'component-a': ComponentA
      }
      })
    不同文件局部注册

    定义组件和注册组件在不同文件

    1. 定义组件

      假设在ComponentA.vue文件中定义了一个组件。

      export default {
        name: 'ComponentA',
        /* ... */
      }
    2. 局部注册组件

      在另一个组件ComponentB.vue中注册A组件。

      import ComponentA from './ComponentA'  //1. 导入A组件
      export default {
      components: {
        ComponentA  //2. 注册A组件
      },
      // ...
      }

组件注意事项

  1. data必须是一个函数

    在Vue基础指令中曾经说过,data有两种写法:

    • 对象写法

      data: {
      count: 0
      }
    • 函数写法

      data: function () {
      return {
       count: 0
      }
      }

    注意:但是在组件中只能用函数写法。因为组件是要被复用的,也就是说组件可能有很多个实例。当采用对象写法,则每一个组件实例都会指向相同的data对象。而函数写法新建组件实例后,调用data会执行一遍data函数,返回新的对象。每个实例都能有独立的数据。

  2. 单根元素

    <h3>{{ title }}</h3>
    <div v-html="content"></div>

    在模板中采用上面的写法,Vue会报错,显示every component must have a single root element (每个组件必须只有一个根元素)。可以修改成下面的写法:

    <div class="blog-post">
     <h3>{{ title }}</h3>
     <div v-html="content"></div>
    </div>

    原因:因为一个组件的一般只有一个Vue实例,Vue实例要挂载DOM元素才能实现响应式更新。而如果组件内部有多个最外层的并列DOM元素。那挂载在哪一个上面都无法覆盖整个DOM节点。因此要采用一个单根元素去包裹全部DOM节点,实现整体响应式更新DOM。

父子组件间的通信

1.通过 Prop 父组件向子组件传递数据

假设有一个blog-post子组件:

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的, 使用时需要用kebab-case
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})

父组件如下:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'My journey with Vue' },
      { id: 2, title: 'Blogging with Vue' },
      { id: 3, title: 'Why Vue is so fun' }
    ]
  }
})
 <!--HTML中属性用kebab-case形式-->
<blog-post 
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post-title="post.title"
></blog-post>

通过在子组件中定义需要的props属性,父组件可以通过v-bind动态属性把父组件的值传入子组件。这样每一篇博客的title就在子组件上显示了。

2. 通过 $emit 子组件向父组件传递数据

假设在子组件上存在一个按钮,通过点击子组件上的按钮,能放大字体。

  1. 父组件监听enlarge-text事件

    父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件。

    <blog-post
     ...
     v-on:enlarge-text="postFontSize += 0.1"
    ></blog-post>
  2. 子组件通过点击触发enlarge-text事件

    子组件通过$emit触发enlarge-text事件。

    • 当按钮被点击的时候先会触发click事件
    • 接着进入$emit('enlarge-text')事件处理程序
    • 最后$emit触发enlarge-text事件
    <button v-on:click="$emit('enlarge-text')"> 
     Enlarge text
    </button>
  3. 父组件监听到enlarge-text事件发生

    父组件监听到enlarge-text事件发生,进入(postFontSize += 0.1,也可以写成一个函数)事件处理程序。更新 postFontSize 的值,字体就变大了。

  4. 使用事件抛出一个值

    上面写法中,字体每次放大的数值是父组件决定的。但是如果要让子组件自己决定呢?我们该如何向父组件传递子组件的信息。

    • 可以使用 $emit 的第二个参数来提供这个值:
    <button v-on:click="$emit('enlarge-text', 0.1)">
     Enlarge text
    </button>
    • 当在父级组件监听这个事件的时候,我们可以通过 $event 访问到被抛出的这个值:
    <blog-post
     ...
     v-on:enlarge-text="postFontSize += $event"
    ></blog-post>
    • 或者,把事件处理程序绑定一个方法:
    <blog-post
     ...
     v-on:enlarge-text="onEnlargeText"
    ></blog-post>

    这个值会做为第一个参数传递过去:

    methods: {
     onEnlargeText: function (enlargeAmount) {
       this.postFontSize += enlargeAmount
     }
    }
Twlig commented 2 years ago

Vue组件六种通信方式的优缺点及应用场景

https://blog.csdn.net/weixin_47111901/article/details/116033575