Vue:深入理解组件

目录

1. 组件注册

2. Prop

3. 插槽

4. 动态组件 & 异步组件

(一)组件注册

两种组件的注册类型:全局注册局部注册

1. 全局注册

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

// 定义一个名为 button-counter
//当直接在 DOM 中使用一个组件 (而不是在字符串模板或单文件组件) 的时候,强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会避免和当前以及未来的 HTML 元素相冲突。
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

2. 局部注册

//模块系统中局部注册
import ComponentA from './ComponentA.vue'
export default {
  components: {
    ComponentA
  },
  // ...
}

(二)Prop

1. Prop的大小写

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!--HTML 中是 kebab-case-->
<blog-post post-title="hello!"></blog-post>

重申一次,如果你使用字符串模板,那么这个限制就不存在了。

2. Prop验证

不推荐使用数组的方式,对系统后续维护不利。

props:['name', 'type', 'list', 'isVisible']

推荐以下写法:定制 prop 的验证方式。

 props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    propF: {
        type:Array,
//对象或数组默认值必须从一个工厂函数获取
            default: () => []
    },
    propG: {
        type:Function,
        default: () => {}
    } 
    // 自定义验证函数
    propH: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    },
    propI: {
        type:Boolean,
         default:false
    },
  }

3. 传递Prop

<!-- 1. 传递静态Prop -->
<blog-post title="My journey with Vue"></blog-post> 
<!-- (1)传入一个数字 -->
<blog-post v-bind:likes="42"></blog-post>
<!-- (2)传入布尔值 -->
<blog-post v-bind:is-published="false"></blog-post>
<!-- (3)传入数组 -->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- (4)传入对象 -->
<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>

<!-- 2. 传递动态Prop -->  
<!-- (1)动态赋予一个变量的值 -->
<blog-post v-bind:likes="post.likes"></blog-post>
<blog-post v-bind:author="post.author"></blog-post>
<!-- (2)动态赋予一个复杂表达式的值 -->
<blog-post v-bind:title="post.title + ' by ' + post.author.name"></blog-post>
<!-- (3)传入对象的所有属性 -->
<blog-post v-bind="post"></blog-post>
<!--
post: {
  id: 1,
  title: 'My Journey with Vue'
}
等效于下面代码:
-->
<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

(三)插槽

1. 基本使用

<!-- 在 <navigation-link> 的模板中写为 -->
<a
  v-bind:href="url"
  class="nav-link"
>
  <slot></slot>
</a>

<!-- 在使用<navigation-link>模板时: -->
<navigation-link url="/profile">Your Profile</navigation-link>

<navigation-link url="/profile">
  <span class="fa fa-user"></span>
  Your Profile
</navigation-link
    
<navigation-link url="/profile">
  <font-awesome-icon name="user"></font-awesome-icon>
  Your Profile
</navigation-link>

如果 <navigation-link> 没有包含一个 <slot> 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

2. 后备内容

为一个插槽设置具体的后备 (也就是默认的) 内容,它只会在没有提供内容的时候被渲染。而如果我们提供内容,则这个提供的内容将会被渲染从而取代后备内容。

<!-- 在 <submit-button> 的模板中写为 -->
<button type="submit">
  <slot>Submit</slot>
</button>

<!-- 在使用<submit-button>模板时: -->
<submit-button></submit-button>
<!-- 将被渲染为: -->
<button type="submit">
  Submit
</button>

3. 具名插槽

使用场景:需要多个插槽。

对于这样的情况,<slot> 元素有一个特殊的 attribute:name。这个 attribute 可以用来定义额外的插槽。一个不带 name<slot> 出口会带有隐含的名字“default”。

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。

<!-- 在 <base-layout> 的模板中写为 -->
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

<!-- 在使用<base-layout>模板时: -->
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>
<!-- 上面两行代码等效为:  
  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>
 -->   
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

具名插槽缩写

<base-layout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>

3. 作用域插槽

编译作用域

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

我们在父级模板里使用带有插槽的子组件。当想在一个插槽中使用数据时,该插槽跟父级模板的其它地方一样可以访问父级的实例属性 (也就是相同的“作用域”),而不能访问子组件的作用域。

而当我们想让插槽内容能够访问子组件中才有的数据时,可以使用作用域插槽。 <slot> 元素上的 attribute 被称为插槽 prop

<!-- 在<current-user>的模板中写为: -->
<!-- 为了让 user 在父级的插槽内容中可用,我们可以将 user 作为 <slot> 元素的一个 attribute 绑定上去 -->
<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

<!-- 在使用<current-user>模板时: -->
<!-- 可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字 -->
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

(四)动态组件 & 异步组件

1. 动态组件

通过 Vue 的 <component> 元素加一个特殊的 is attribute 来实现:

<!-- 组件会在 `currentTabComponent` 改变时改变 -->
<component v-bind:is="currentTabComponent"></component>

在上述示例中,currentTabComponent 可以包括

  • 已注册组件的名字,或
  • 一个组件的选项对象

例子

<template>
  <p id="app">
   <component :is="currentView"></component>
   <button @click="changeView('A')">切换到A</button>
   <button @click="changeView('B')">切换到B</button>
   <button @click="changeView('C')">切换到C</button>
  </p>
</template>

<script>
var app = new Vue({
 el: '#app',
 data: {
  currentView: 'comA'
 },
 methods: {
  changeView: function(data){
   this.currentView = 'com'+ data  //动态地改变currentView的值就可以动态挂载组件了。
  }
 },
 components: {
  comA: {
   template: '<p>组件A</p>'
  },
  comB: {
   template: '<p>组件B</p>'
  },
  comC: {
   template: '<p>组件C</p>'
  }
 }
});
</script>

2. 在动态组件上使用 keep-alive

<keep-alive>包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

当组件在<keep-alive> 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。 主要用于保留组件状态或避免重新渲染。

详细见

利用Vue中keep-alive,快速实现页面缓存

Vue keep-alive详解

3. 异步组件

vue项目实现按需加载的3种方式:vue异步组件、es提案的import()、webpack的require.ensure()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章