组件传值,数据双向绑定

一、组件传值
组件间的传值方式
父子传值:props、emit、$parent、$chidren、ref
兄弟之间传值:事件总线(on、emit)、Vuex
传值实例
(1)父组件传到子组件(props)一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
// 父组件
<template>
<div>
<ceshi @test="test"></ceshi>
</div>
</template>
<script>
export default {
data() {
test: '测试'
}
}
</script>
// 子组件接收 ceshi
<template>
<div>
{{test}}
</div>
</template>
<script>
export default {
props: {
test: String
}
data() {
}
}
</script>
(2)子组件传到父组件(emit)子组件通过emit触发事件给父组件,父组件通过on去监听数据的变化。
// 父组件
<template>
<div>
<ceshi :test="test" @change="change"></ceshi>
</div>
</template>
<script>
export default {
data() {
test: '测试'
},
methods: {
change(val){
console.log(val)
}
}
}
</script>
// 子组件接收 ceshi
<template>
<div>
{{test}}
<button @click="getTitle"></button>
</div>
</template>
<script>
export default {
`props: {
test: String
}`
data() {
title: '子组件'
},
methods: {
getTitle(){
this.$emit('change', this.title) // 将值绑定到change上传递过去
}
}
}
</script>
二、prop
prop类型
以字符串形式列出:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
通常我们都需要每个 prop 都有指定的值类型,因此通过对象的形式列出、分别标明prop的名称和类型以及默认值
props: {
test: String,
likes: {
type: Number,
default: () => []
},
isPublished: {
type: Boolean,
default: false
}
}
传递静态或动态 Prop
// 静态传值
<blog-post title="My journey with Vue"></blog-post>
// 动态赋予一个变量的值
<blog-post v-bind:title="post.title"></blog-post>
// 动态赋予一个复杂表达式的值
<blog-post
v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定
:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
需要改变prop时,可以通过
(1)子组件内需要将prop作为本地数据进行使用,可以在data中将这个prop作为初始值
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
(2)这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
三、自定义事件(v-model)
双向绑定v-model
一个组件上的 v-model 默认会利用名为 value 的 prop
和名为 input
的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:
// 子组件
<template>
<div>
<el-input v-model="price" @input="updateVal"></el-input>
</div>
</template>
<script>
export default {
// model用于改变v-model绑定的属性和抛出事件(实时监听)
model: {
prop: 'price',
event: 'change'
},
props: {
price: Number
},
methods: {
updateVal(val){
this.$emit('change', val) // 监听price值变化,传递给父组件
}
}
}
</script>
在父组件使用v-model,通过该语句实现price变量与输入值双向绑定
<ceshi @change="change" v-model="price"></ceshi>
// 等同于
<ceshi @change="change" :value="price" @input="price=$event.target.value"></ceshi>
执行流程:1、子组件通过通过 prop 接收父组件的数据price2、当input进行输入时,会触发input事件3、通过 $emit 提交事件,将值传递给父组件4、父组件的input事件被触发,将会更新变量price的值5、父组件在通过props传值给子组件
v-bind 实现单向绑定
v-model 实现双向绑定
.sync修饰符
真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。因此推荐update:myPropName
的模式触发事件
vue事件名可以updata:prop去定义,用于处理prop传递的新值组件内部将通过$emit('update:dtitle', val)触发事件,修改title的值
// 子组件
<el-input v-model="title" @input="updateVal"></el-input>
props: ['title'],
updateVal(val) {
this.$emit('update:dtitle', val)
}
// 父组件
<ceshi @update:dtitle="title = $event" :title.sync="title"></ceshi>
注意事项:1、 .sync 修饰符的 v-bind 不能和表达式一起使用 2、组件内部需要$emit触发的事件名,格式为update:prop
同时在使用sync的时候,简化了绑定prop
和绑定update:prop
事件
四、动态组件&异步组件
动态组件
通过 is
来控制不同组件的切换
<component v-bind:is="currentTabComponent"></component>
但是有时候切换组件的时候,组件都会重新渲染为了避免反复重新渲染这个问题,可以通过keep-alive来实现
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
注意这个 <keep-alive> 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。
异步组件
全局或局部引入组件时,一般通过import引入,然后在components注入。
import Header from './pages/header'
components: {
Header
}
1、使用异步组件可以减少打包的结果,会将异步组件分开打包,会采用异步的方式加载组件。2、异步组件的核心可以给组件定义变成一个函数
components: {
myComponent(resolve){
// 这个特殊的 `require` 语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require(['./my-component'], resolve)
}
}
components: {
'my-component': () => import('./my-component')
}
结语
流云秋风金黄 月落舟窗
,一句我特别喜欢的句子,也希望这篇文章给到大家帮助,编写不易,也希望帮忙点个赞。