这是我参与「第四届青训营 」笔记创作活动的第7天
本文主要是对Vue中的一些进阶知识进行学习记录,对基础的概念不作详解。
组件注册
组件名称
一般采用两种方式
kebab-case:my-component-a
PascalCase:MyComponentA
组件注册
局部注册
var ComponentA = { /* ... */ }//创建一个组件对象
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
在模块系统中局部注册
//ComponentB.js
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'
export default {
components: {
ComponentA,
ComponentC
},
// ...
}
Prop
名称规范
在js 和vue 文件的模版(template)中,使用驼峰命名法,然而在HTML中需要使用短横线分隔 。这是因为HTML 对大小写不敏感。
类型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
传入所有对象
如果一个对象中属性很多,写起来会很复杂,可以使用语法
v-bind = "xxx",这样就可以一下子传入xxx 具有的所有参数。
单向数据流
与React中Prop 一样,父传给子的数据不允许被修改,这是利于维护的。要修改可以变为组件自身的data,这像是React 中的State
验证
可以在传入prop时进行验证,若不符合要求控制台会进行警告。
Vue.component('my-component', {
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: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].includes(value)
}
}
}
})
类型检查
type可能存在的值:
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
- 自定义函数
自定义函数例如:
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
非prop属性
指没有显示声明prop的属性。这种时候,属性会自动被添加到组件的根元素上。
自动合并
若原来已经存在class 和style属性,那么新添加的值会被自动合并,而不是覆盖。
禁用属性传承
不希望根元素继承属性,可以添加inheritAttrs:false
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})
上述例子中,若没有v-bind =$attrs 则传递的非prop属性会自动添加到label 标签。
边界情况
该节主要对Vue 中涉及到的一些小细节和规则进行说明。
访问元素/组件
在Vue中,我们一般不手动操作DOM元素,也不会干涉一个组件实例的内部,但是如果一定要这么做,也是可以的,接下来对几种可能的情况进行讨论:
访问根实例
在new Vue 实例的子组件中,要访问根实例,可以通过$root 属性进行访问,例如:
new Vue({
data: {
foo: 1
},
computed: {
bar: function () { /* ... */ }
},
methods: {
baz: function () { /* ... */ }
}
})
//使用方法
this.$root.foo //获取
this.$root.foo = 2 //写入
this.$root.bar //访问计算属性
this.$root.baz() //调用根组件方法
访问父级组件实例
$parent属性 ,用法与根组件一样。
用这种方式也可以替代使用prop父传子的数据传输方式。
访问子组件实例
使用ref 与子组件建联。
<base-input ref="usernameInput"></base-input>
定义了ref 之后,在base-input组件内,可以使用this.$ref.usernameInput 来访问该组件实例。
依赖注入
如果有多个组件存在嵌套,那么直接使用$parent 会不易维护,这种情况下推荐使用依赖注入,涉及到provide 和inject。
provide:允许我们指定想给后代组件提供的数据/方法。
provide:function(){
return {
getMap: this.getMap //将父组件中的getMap传出去
}
}
设定完后,可以在任何后代组件使用inject来接收。
inject: ['getMap'] //后代组件接收父组件中传来的getMap
//可以使用this.getMap来调用。
程序化事件监听
- 监听一个事件:
$on(事件名,事件处理函数) - 一次性监听一个事件:
$once(事件名,事件处理函数) - 停止监听一个事件:
$off(事件名,事件处理函数)
mounted: function () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
循环引用
循环引用的组件个人认为使用较少,也没有特别大的实用价值,因此暂时不作记录,日后再更。
控制更新
可以在根元素上使用v-once来创建低开销的静态组件。若一个组件内含有大量静态元素,那么可以使用这种方法,使得加载完成后被缓存起来,下次就不用再被加载了。可以提高速度。
Vue.component('my-component', {
template: `
<div v-once>
<h1>Terms of Service</h1>
... a lot of static content ...
</div>
`
})