vue组件深入
组件注册
- 全局注册
- 局部注册
prop
prop的大小写
camelCase vs Kebab-case
kebab-case
prop类型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
传静态或动态prop
prop可以通过v-bind动态赋值
- 传入一个数字
- 传入一个布尔值
- 传入一个数组
- 传入一个对象
v-bind告诉JavaScript表达式是动态的而不是一个字符串
prop单向数据流
- 在组件中使用props来从父亲组件接受数据,在props中定义的属性,都可以在组件中直接使用
- props来自父级,而组件中的data return的数据就是组件自己的数据,两种情况作用域就是组件本身,可以直接在template,computed,methods中直接使用
- 使用v-bind动态绑定来自父组件的值。input
单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
两种常见的prop情形
一种是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域 下可以随意使用和修改。这种情况可以在组件 data 内再声明一个数据,引用父组件 的 prop
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props接收 步骤三:将传递进来的数据通过初始值保存起来
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
另一种情况就是 prop 作为需要被转变的原始值传入。这种情况用计算属性就可以了
步骤一:注册组件
步骤二:将父组件的数据传递进来,并在子组件中用props接收 步骤三:将传递进来的数据通过计算属性进行重新计算
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
自定义事件
v-model
一个组件上的v-model会利用名为value的prop和名为input的事件,但是像但是像单选框、复选框等类型的输入形控件可能会将value特性用于不同的目的
model选项可以用来避免这样的冲突
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
`
})
现在在这个组件上使用v-model的时候
这里的 lovingVue
的值将会传入这个名为 checked
的 prop。同时当 `` 触发一个 change
事件并附带一个新的值的时候,这个 lovingVue
的属性将会被更新。
.sync修饰符
对prop进行双向绑定,但真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,但在父组件和子组件都没有明显的改动来源
推荐updata:myPropName
的模式取而代之。
在一个包含title prop的假设组件中,我们可以用以下方法表达对其复新值的意图
this.$emit('updata:title',newTitle)
然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。
//doc.title = newTitle
1.当updata:title事件被触发时,将newTitle通过自定义的updata:title事件抛出
2. 在父组件上监听并绑定本地数据,实现双向绑定
为了方便起见,给这种模式提供一个缩写.sync修饰符
//子组件
this.$emit('updata:title',newTitle)
关于prop的双向绑定
举个例子就以title改变为例
父 ->子
父的本地数据 data下的doc.title ->
父组件v-bind:title="doc.title"->
子组件的props title:{type:String}
子组件使用props可写在子组件data中
子 -> 父
子组件 this.$emit('updata:title',newTitle) ->
父组件 v-on:update:title="doc.title = $event" ->
父组件 v-bind:title="doc.title" ->
父组件 data doc.title 改变
prop双向绑定相比v-model更灵活,总结父子组件上的v-bind时双向绑定的数据接口,父到子通过props ,子到父通过自定义事件。
关于在组件上使用v-model的双向绑定
因为原生的JavaScript的有value属性 所以为了父到子通信
举个例子
父->子
父自定义组件的data->
父的this.msg ->
父组件v-bind:value= 'msg' ->
子组件的props value:{type:String}改变 ->
子组件v-bind:value = value(来自子props)>
子的JavaScript
因为原生的JavaScript的有value属性 所以为了父到子通信 父和子都要动态绑定value属性。
子->父
子组件的JavaScript ->
子组件输入改变v-bind:value->
子组件v-on:input:$emit('input' , $event.target.value)
->
父组件v-on:input(msg = $event) ->
父的this.msg ->
父的data ->
父的{{msg}}
因为原生的JavaScript的有input事件,所以为了子到父通信,子组件触发input事件时采用自定义input事件,在父组件上监听input事件
插槽slot
一条规则
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
编译作用域
Clicking here will send you to: {{ url }}
后备内容
如果提供内容Submit就会被取而代之
具名插槽slot
新语法v-slot或#
v-slot:default
v-slot:name
作用域插槽slot
V-slot:name = "slotProps"
动态组件&异步组件
用is在多标签的界面来切换不同组件的时候,有时需要保持这些组件的状态,避免反复冲渲染导致的性能问题
让重新创建的动态组件能够在它们被第一次创建的时候缓存下来。为了解决这个问题,可以用个
元素将其动态组件包裹起来。
里面的组件一定要有自己的名字
处理边界情况
访问元素&组件
- 访问根实例$root: 对于小型的有少量的组件应用来说是很方便,大型项目使用vuex来管理应用的状态
- 访问父组件实例$parent:用与简单直接的父子组件,当需要向任意更深层的组件提供上下文信息使,使用依赖注入
- 访问子组件实例或子元素$refs:在组件渲染完成后生效。
依赖注入
provide inject
- provide选项,允许我们指定我们想要提供给后代组件的数据方法。
- inject选项,在后代组件里,使用inject选项来接受指定的想要添加在这个实例上的属性
可以;把依赖注入看作一部分"大范围有效的prop"一样
- 祖先组件不需要知道哪些后代组件使用它提供的属性
- 后代组件不需要知道被注入的属性来自哪里
程序化的事件侦听器
组件之间的循环应用
两个相互依赖的组件A、B ,需要给系统一个点,告诉系统A是需要B的,但我们不需要向解析B
- 在生命周期钩子beforeCreate时注册
- 在本地注册组件的时候,使用webpack的一步import