最近一直在加班,都没时间学习vue的知识,今天还是花点时间总结点东西吧。
1. 父组件向子组件传值
Prop
是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。
还是老样子,先举例子:
<template>
<!-- 父组件 -->
<div class="app-container">
<child :name="name" :information="information" test-name="父组件"></child>
</div>
</template>
<script>
import Child from './Child'
export default {
components: {
Child
},
data() {
return {
name: 'rodchen',
information: {
'age': 25,
'phone': 18700000000
}
}
},
watch: {},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<!-- 子组件 -->
<div class="childer-container">子组件</div>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true,
default: {},
validator: function(value) {
return true;
}
},
information: {
type: Object,
required: true,
default: {},
validator: function(value) {
return true;
}
},
testName: {
}
},
created() {
this.name = 34
this.information = {}
},
data() {
return {};
},
methods: {
}
};
</script>
<style lang="scss" scoped>
</style>
(1) props的接受方式说明
上面使用的方式是最复杂的,也是官方风格提出最好的方式。
a. props: ['name', 'information', 'testName'] //官方不推荐使用
b. props: {
name: String,
information: Object,
testName: String
}
c. props: {
name: {
type: String,
required: true,
default: {},
validator: function(value) {
return true;
}
},
information: {
type: Object,
required: true,
default: {},
validator: function(value) {
return true;
}
},
testName: {
}
}
type说明:可以是下列原生构造函数中的一个,(也可以是自己构造的类型)
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
(2) prop命名问题
相信大家发现上面testName里没有值,因为这里只是为了说明一个问题,父组件在子组件绑定其属性‘test-name’,子组件需要通过驼峰命名法来接受testName
(3) prop的初始化处理
上面的子组件的生命周期函数代码
created() {
this.name = 34
this.information = {}
}
子组件将prop的值进行了赋值操作,这种做法其实是错误的
上面控制台报错原因,应该避免直接对prop进行修改。
不需要修改prop的情况下
data() {
return {
// 接受prop
tempName: '',
tempInformation: {},
tempTestName: ''
};
}
子组件创建temp属性用于处理prop。
需要修改prop的情况下(出错情况说明)
<template>
<!-- 子组件 -->
<div class="childer-container">子组件</div>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true,
default: {},
validator: function(value) {
return true;
}
},
information: {
type: Object,
required: true,
default: {},
validator: function(value) {
return true;
}
},
testName: {
}
},
created() {
// this.name = 34
// this.information = {}
this.initData()
},
data() {
return {
// 接受prop
tempName: '',
tempInformation: {},
tempTestName: ''
};
},
methods: {
// prop数据初始化处理
initData () {
this.tempName = this.name
this.tempInformation = this.information
this.tempTestName = this.testName
this.tempName = 34
this.tempInformation.address = '子组件修改'
}
}
};
</script>
<style lang="scss" scoped>
</style>
上面的代码,子组件创建temp属性用于处理prop,然后子组件修改了父组件的information的address的值,会发生什么呢?
父组件代码创建create函数,控制台输出information
created () {
console.info('++++++++++++父组件创建生命周期函数++++++++++++++')
console.info(this.information)
}
如图可以看到当前information.address已经被修改了,这样说明:
- JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
- 父组件当前输出表明,父组件的创建完成在子组件之后。
需要修改prop的情况下(仅包含一级属性)
information: {
'age': 25,
'phone': 18700000000,
'address': {
'homeAddress': '安徽'
}
}
information中属性划分
- 一级属性为:age, phone, address
- 二级属性为:homeAddress
修改上面子组件代码
<template>
<!-- 子组件 -->
<div class="childer-container">子组件</div>
</template>
<script>
export default {
props: {
name: {
type: String,
required: true,
default: {},
validator: function(value) {
return true;
}
},
information: {
type: Object,
required: true,
default: {},
validator: function(value) {
return true;
}
},
testName: {
}
},
created() {
// this.name = 34
// this.information = {}
this.initData()
},
data() {
return {
// 接受prop
tempName: '',
tempInformation: {},
tempTestName: ''
};
},
methods: {
// prop数据初始化处理
initData () {
this.tempInformation = Object.assign({}, this.information)
this.tempInformation.age = 100
this.tempInformation.address.homeAddress = '子组件修改'
}
}
};
</script>
<style lang="scss" scoped>
</style>
这里得到的结论为:如果prop属性只包含一级属性,可以通过Object.assign{}的方式进行深复制,但是二级及以上属性就不行了。
需要修改prop的情况下(包含一级及以上属性)
需要使用下面方式进行对象的深复制。
this.tempInformation = JSON.parse(JSON.stringify(this.information))
Prop 传值内容
- 属性
- 方法
- 父组件自己
<template>
<!-- 父组件 -->
<div class="app-container">
<child :property="name" @click="testFunction" :parentOwn="this"></child>
</div>
</template>
<script>
import Child from './Child'
export default {
components: {
Child
},
created () {
},
data() {
return {
name: 'rodchen'
}
},
watch: {},
methods: {
testFunction () {
console.info('父组件方法')
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<!-- 子组件 -->
<div class="childer-container">
<h3>子组件</h3>
<button @click="testFunctionTemp">测试父组件方法</button>
</div>
</template>
<script>
export default {
props: {
property: {
property: String,
required: true,
default: {},
validator: function(value) {
return true;
}
},
parentOwn: {
type: Object,
required: true,
default: {},
validator: function(value) {
return true;
}
}
},
created() {
this.initData()
},
data() {
return {
// 接受prop
tempProperty: ''
};
},
methods: {
// prop数据初始化处理
initData () {
this.tempProperty = this.property
console.info(this.$parent.name)
},
// 测试父组件方法
testFunctionTemp () {
this.$emit('click')
}
}
};
</script>
<style lang="scss" scoped>
</style>
父/子组件主动获取子/父组件
对于这个就不做举例子。
父组件主动获取子组件
<child ref="children" :name="name" :information="information" test-name="父组件"></child>
this.$refs.children
子组件主动获取父组件
this.$parent.name
自定义事件
<child @customerEvent="click"></child>
this.$emit('customerEvent')
非父子组件通信
复杂的情况下,使用vuex。
需求:父组件下包含子组件和header组件,子组件内的输入框实时修改header组件的内容。
<template>
<!-- 父组件 -->
<div class="app-container">
<header-component></header-component>
<child></child>
</div>
</template>
<script>
import Child from "./Child";
import HeaderComponent from "./Header";
export default {
components: {
Child,
HeaderComponent
},
mounted() {},
data() {
return {};
}
};
</script>
<style lang="scss" scoped>
</style>
<template>
<!-- 子组件 -->
<div class="childer-container">
<h4>子组件</h4>
<input type="text" v-model="headerTitle" @input="input">
</div>
</template>
<script>
import VueService from "./service";
export default {
created() {
this.$emit("customerEvent");
},
data() {
return {
headerTitle: ""
};
},
methods: {
input(e) {
VueService.$emit("change-header", e.target.value);
}
}
};
</script>
<style lang="scss" scoped>
</style>
<template>
<!-- header组件 -->
<div class="childer-container">
<h1>Header组件</h1>
<h2>{{title}}</h2>
</div>
</template>
<script>
import VueService from './service'
export default {
created() {},
mounted() {
var self = this
VueService.$on('change-header', function (value) {
self.title = value
})
},
destroyed () {
VueService.off('change-header')
},
data() {
return {
title: "Headercontent"
};
},
methods: {
}
};
</script>
<style lang="scss" scoped>
</style>
// service
import Vue from 'vue'
var VueService = new Vue();
export default VueService
说明:
- 需要创建公共文件(service)注册/注销/广播事件
- 注册组件内如果需要直接修改本自己的属性,需要self处理
组件插槽
简单用法
<template>
<!-- 父组件 -->
<div class="app-container">
<child>
父组件内容
</child>
</div>
</template>
<template>
<!-- 子组件 -->
<div class="childer-container">
<h4>子组件</h4>
<slot></slot>
</div>
</template>
具名插槽
<template>
<!-- 父组件 -->
<div class="app-container">
<child>
<template slot="header">
<h1>header</h1>
</template>
<p>content</p>
<template slot="footer">
<p>footer</p>
</template>
</child>
</div>
</template>
<template>
<!-- 子组件 -->
<div class="childer-container">
<h4>子组件</h4>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>