深入 Vue.js 组件开发

关键字 :Vue.js

深入 Vue.js 组件开发

1. 前文回顾

在上一篇博文中介绍了 Vue.js 的计算属性组件化开发基础,让我们做一个简单的回顾。

1.1 计算属性

通过上一篇博文,我们知道了当我们要对一些变量进行逻辑处理时,我们就可以使用计算属性。同时,我们还比较了计算属性方法侦听属性的相同点和不同点。

1.2 组件化开发基础

紧接着,我们了解了组件的概念,知道了组件在实际开发中所占的重要地位,了解了组件化开发的基础内容,接下来让我们更加深入地了解组件化开发吧!

2. 深入组件化开发

2.1 组件的注册

2.1.1 组件名

在注册一个组件的时候,我们需要提供一个名字。比如在上一篇博文中我们注册了一个按钮组件:

Vue.component('button-counter', { /* ... */ });

Vue.component 第一个参数就是组件的名字。我们给予的名字一般依赖于我们拿它做什么,我们需要的注意的是组件名的大小写,定义组件一般有这两种方式:

使用 kabab-case
Vue.component('button-counter', { /* ... */ });

当我们使用 kabab-case(短横线分割命名)定义一个组件时,我们使用它的时候也必须使用短横线引用,如:

使用 PascalCase
Vue.component('ButtonCounter', { /* ... */ });

当我们使用 PascalCase(首字母大写命名)定义一个组件时,可以有两种方法,分别是:

2.1.2 全局注册

在上一篇博文中,我们尝试了用 Vue.component 的方式来创建组件,这是一种全局注册的方式:

Vue.component('button-counter', {
   // ...
});

这种方式注册的组件可以使用在任何 Vue 实例中。

2.1.3 局部注册

还有一种注册组件的方法便是局部注册,在实际 Vue-Cli 工程项目中,代码看起来是这个样子的:

import ComponentA from './ComponentA.vue'

export default {
   components: {
       ComponentA
  },
   // ...
}

在 ES2015+ 语法中,在对象中放一个类似 ComponentA 的变量名其实是 ComponentA: ComponentA 的缩写,即这个变量名同时是:

  • 用在模板中的自定义元素的名称

  • 包含了这个组件选项的变量名

2.2 Prop

2.2.1 camelCase vs kabab-case

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

Vue.component('blog-post', {
 // 在 JavaScript 中是 camelCase 的
 props: ['postTitle'],
 template: '...'
})

<blog-post post-title="hello!"></blog-post>

2.2.2 Prop 的类型

在上面的例子中,我们学会了以字符串的形式列出向子组件传递的 Prop:

props: ['title', 'content', 'page', 'callback', 'flag' ]

但是,通常我们需要指定 prop 的类型,因此我们可以以对象的形式列出 prop,属性的名称和值分别是 prop 各自的名称和类型:

prop: {
   title: String,
   content: Object,
   page: Number,
   callback: Function,
   flag: Boolean,
   // Array、Promise...
}

当 prop 的类型不正确时,游览器的控制台会将遇到的错误报告给用户。

2.2.3 传递动态的 Prop

上面我们知道了如何传递一个静态的 prop,而传递动态的 prop 可以通过 v-bind 动态赋值,如:


<blog-post v-bind:title="post.title"></blog-post>


<blog-post
 v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>

注意:上面的例子都是传递字符串,那么我们如何传入一个数字、布尔值、对象呢?



<blog-post v-bind:page="3"></blog-post>
<blog-post v-bind:page="post.page"></blog-post>

同理,传入一个布尔值、数组也是需要用 v-bind 告诉 Vue 这是表达式,否则 Vue 会理解为字符串。

当我们传入一个对象:
<blog-post
 v-bind:name="{
   lastName: 'James',
   firstName: 'Lebron'
 }"
></blog-post>


<blog-post v-bind:author="post.author"></blog-post>

传入一个对象的所有属性:

<blog-post v-bind="post"></blog-post>

其中 post 中的所有属性都会被传递。

2.3 自定义事件

2.3.1 事件名

和 Prop 不一样,事件名不会不会进行大小写的转换。比如:

this.$emit('addUser');

则监听 addUser 事件的 kabab-case 名字事件是没用的:

<add-user-button v-on:add-user="do"></add-user-button>

因为 HTML 对大小写是不敏感的,所以 v-on:addUser 将会转化成 v-on:adduser ,这就导致了 addUser 没有被监听到。

2.3.2 .native 修饰符

当我们想在一个组件的根元素上直接监听一个原生事件,这时,我们救需要使用 v-on.native 修饰符:

<base-input v-on:focus.native="onFocus"></base-input>

但是,如果这个 base-input 组件根元素不是 input 时,父组件的监听就失效了,并且不会产生任何报错,且 onFocus 处理函数不会被如期地被调用。

为了解决这个问题,Vue 提供了一个 $listeners 属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:

{
 focus: function (event) { /* ... */ }
 input: function (value) { /* ... */ },
}

2.3.3 .sync 修饰符

某些情况下,我们可能需要对一个 prop 进行“双向绑定”。但是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。

所以我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

this.$emit('update:title', newTitle)

然后父组件可以监听 update 事件并根据需要更新一个本地的数据属性。例如:
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

v-bind:title.sync="doc.title"

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 v-model

当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

  v-bind.sync="doc"

这样会把 doc 对象中的每一个属性 (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。

2.4 动态组件

什么是动态组件呢?比如我们页面中使用了一个多标签,并使用 is 来切换不同的组件:

 v-bind:is="currentTabComponent"

当我们在这些组件中切换的时候,新的组件是会重新渲染的,然而假如我们想保留这些组件的状态,避免重复渲染导致的性能问题,那么我们就需要用到“动态组件”了,我们可以用一个 keep-alive  元素将其动态组件包裹起来。

这样,标签在被切换之后会被缓存起来了,当我们再切换回来就不会重新渲染了。

注意这个 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是通过局部/全局注册的。

3. 结尾

通过本篇内容我们更深入地了解了 Vue.js 的组件化开发,组件化开发带来的便利以及其的作用远不止这些例子所展示的,我们需要在实际的开发过程中深入体会组件化开发。

在刚刚结束的 2.4 动态组件 中,我们提到了利用动态组件实现标签中组件的缓存,那么我们将在下一篇内容中手把手教大家如何结合 Element UI 库与 Vue.js 动态组件实现标签的缓存,请期待。

参考资料:Vue.js 官网

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论