组件
全局注册
-
要注册一个全局组件,可以使用
Vue.component(tagName,options)
Vue.component('my-component', { // 选项 })
-
组件注册之后,便可以作为自定义元素`
html
<div id="example">
<my-component></my-component>
</div>
js
// 注册
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
// 创建根实例
new Vue({
el: '#example'
})
渲染为html
<div id="example">
<div>A custom component!</div>
</div>
局部注册
- 不必把每个组件都注册全局,可以通过某个vue实例/组件的实例选项
components
注册仅在其作用域中可用的组件
js
var Child = {
template: '<div>A custom component!</div>'
}
new Vue({
// ...
components: {
// <my-component> 将只在父组件模板中可用
'my-component': Child
}
})
组件组合
- 在vue中,父子组件的关系可以总结为prop向下传递,事件向上传递。父组件通过prop给子组件下发数据,子组件通过事件给父组件发送消息
prop
字面量语法vs动态语法
hhtml
<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>
- 因为它是一个字面量 prop,它的值是字符串 "1" 而不是一个数值。如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算:
html
<!-- 传递真正的数值 -->
<comp v-bind:some-prop="1"></comp>
prop验证
- 要指定验证规则,需要用对象的形式来定义prop,而不能用字符串数组:
js
Vue.component('example', {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})
type 可以是下面原生构造器:
- String
- Number
- Boolean
- Function
- Object
- Array
- Symbol(ES6新增了一种数据类型:Symbol,Symbol是用来定义对象的唯一属性名的不二之选;)
type也可以是一个自定义构造函数,使用instanceof检测
- 当 prop 验证失败,Vue 会抛出警告 (如果使用的是开发版本)。注意 prop 会在组件实例创建之前进行校验,所以在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还无法使用。
自定义事件
- 我们知道,父组件使用 prop 传递数据给子组件。但子组件怎么跟父组件通信呢?这个时候 Vue 的自定义事件系统就派得上用场了。
使用v-on绑定自定义事件
每个vue实例都实现了事件接口即:
- 使用
$on(eventName)
监听事件 - 使用
$emit(eventName,optionalPayload)
触发事件
给组件绑定原生事件
-
想在某个组件的根元素上监听一个原生事件,可以使用v-on的修饰符.native。
<my-component v-on:click.native="doTheThing"></my-component>
动态组件
-
通过使用保留的
元素,并对其 is 特性进行动态绑定,你可以在同一个挂载点动态切换多个组件:
js
var vm = new Vue({ el: '#example', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
html
<component v-bind:is="currentView">
<!-- 组件在 vm.currentview 变化时改变! -->
</component>
-
也可以直接绑定到组件对象上:
var Home = { template: '<p>Welcome home!</p>' } var vm = new Vue({ el: '#example', data: { currentView: Home } })
编写可复用组件
vue组件的API来自三部分---prop,事件和插槽:
- Prop允许外部环境传递数据给组件
- 事件允许从组件内触发外部环境的副作用
- 插槽允许外部环境将额外的内容组合在组件中
子组件引用
- 尽管有 prop 和事件,但是有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 ref 为子组件指定一个引用 ID。例如:
html
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
js
var parent = new Vue({ el: '#parent' })
// 访问子组件实例
var child = parent.$refs.profile
- $refs 只在组件渲染完成后才填充,并且它是非响应式的。它仅仅是一个直接操作子组件的应急方案——应当避免在模板或计算属性中使用 $refs。
高级异步组件
-
自 2.3.0 起,异步组件的工厂函数也可以返回一个如下的对象:
const AsyncComp = () => ({ // 需要加载的组件。应当是一个 Promise component: import('./MyComp.vue'), // 加载中应当渲染的组件 loading: LoadingComp, // 出错时渲染的组件 error: ErrorComp, // 渲染加载中组件前的等待时间。默认:200ms。 delay: 200, // 最长等待时间。超出此时间则渲染错误组件。默认:Infinity timeout: 3000 })
组件命名约定
-
当注册组件 (或者 prop) 时,可以使用 kebab-case (短横线分隔命名)、camelCase (驼峰式命名) 或 PascalCase (单词首字母大写命名)。
// 在组件定义中 components: { // 使用 kebab-case 注册 'kebab-cased-component': { /* ... */ }, // 使用 camelCase 注册 'camelCasedComponent': { /* ... */ }, // 使用 PascalCase 注册 'PascalCasedComponent': { /* ... */ } }
内联模板
- 如果子组件有inline-template特性,组件将把它的内容当作它的模板,而不是把它当作分发内容。这让模板编写起来更灵活
html
<my-component inline-template>
<div>
<p>这些将作为组件自身的模板。</p>
<p>而非父组件透传进来的内容。</p>
</div>
</my-component>
X-Template
- 另一种定义模板的方式是在JavaScript标签中使用text/x-template类型,并且指定一个id。
html
<script type="text/x-template" id="hello-world-template">
<p>Hello hello hello</p>
</script>
js
Vue.component('hello-world', {
template: '#hello-world-template'
})
对滴开销的静态组件使用v-once
-
尽管在 Vue 中渲染 HTML 很快,不过当组件中包含大量静态内容时,可以考虑使用 v-once 将渲染结果缓存起来,就像这样:
Vue.component('terms-of-service', { template: '\ <div v-once>\ <h1>Terms of Service</h1>\ ...很多静态内容...\ </div>\ ' })