Skip to content

组件 #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Twlig opened this issue Mar 12, 2022 · 1 comment
Open

组件 #34

Twlig opened this issue Mar 12, 2022 · 1 comment
Labels

Comments

@Twlig
Copy link
Owner

Twlig commented Mar 12, 2022

组件是可复用的 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 Twlig added the Vue label Mar 12, 2022
@Twlig
Copy link
Owner Author

Twlig commented Mar 27, 2022

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant