深入了解Vue组件 — Prop(下)
1.4 单向数据流
所有的prop都是从父组件传递到子组件中,反过来则不行。
每次父组件发生更新时,子组件中的所有prop都将会刷新为最新的值。
我们不应该在子组件内部改变prop。
两种常见的试图改变prop的情形:
① 这个prop用来传递一个初始值;这个子组件将其作为一个本地的prop数据来使用。
② 传入的这个prop需要进行转换。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<my-component v-bind:initial-counter="counter"></my-component>
<button @click="addOne">加1</button>
<p>{{ counter }}</p>
</div>
<script>
Vue.component('my-component', {
props: ['initialCounter'],
data: function(){
return {
counter: this.initialCounter
}
},
template: '<div><p>{{ counter }}</p><p>{{ initialCounter }}</p></div>'
})
new Vue({
el: '#app',
data: {
counter: 42
},
methods: {
addOne: function(){
this.counter++
}
}
});
</script>
</body>
</html>
使用计算属性:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<my-component size="BiG"></my-component>
</div>
<script>
Vue.component('my-component', {
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
},
template: '<div><p>{{ normalizedSize }}</p></div>'
})
new Vue({
el: '#app',
data: {
}
});
</script>
</body>
</html>
1.5 Prop验证
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-component v-bind="post"></my-component>
</div>
<script>
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'].indexOf(value) !== -1
}
}
},
template: '<div><p>{{ propD }}</p><p>{{ propE.message }}</p></div>'
})
new Vue({
el: '#app',
data: {
post: {
propA: '42',
propB: {name: 'Hjj'},
// propC: ''
// propD: 0,
// propE: {},
propF: 'false'
}
}
});
</script>
</body>
</html>
1.5.1 类型验证
type
可以是下列原生构造函数中的一个:
String
Number
Boolean
Array
Object
Date
Function
Symbol
type
还可以是一个自定义的构造函数。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<my-component v-bind:author="person"></my-component>
</div>
<script>
Vue.component('my-component', {
props: {
author: Person
},
template: '<div><p>{{ typeof author }}</p><p>{{ author.firstName }}</p><p>{{ author.lastName }}</p></div>'
});
new Vue({
el: '#app',
data: {
person: new Person('He', 'jiajun')
}
});
function Person (firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
</script>
</body>
</html>
1.6 非 Prop 的特性
一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.parentClass {
background: orange
}
.childClass {
padding: 5px;
}
</style>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<my-component class="parentClass"></my-component>
</div>
<script>
Vue.component('my-component', {
props: {
},
template: '<div class="childClass">Hello</div>'
})
new Vue({
el: '#app',
data: {
}
});
</script>
</body>
</html>
1.6.1 禁用特性继承
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<form>
<base-input label="Username: "
v-bind:value="username"
v-on:input="username = $event"
required placeholder="Enter your username"></base-input>
<br/>
<p>{{ username }}</p>
</form>
</div>
<script>
Vue.component('base-input', {
props: ['label', 'value'],
template: `<label>{{ label }}
<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)"></label>`
});
new Vue({
el: '#app',
data: {
username: ''
}
});
</script>
</body>
</html>
解释:组件的required
和placeholder
被继承到根元素<label>
;组件的label
和value
作为prop传递。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
</style>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<form>
<base-input label="Username: "
v-bind:value="username"
v-on:input="username = $event"
required placeholder="Enter your username"></base-input>
<br/>
<p>{{ username }}</p>
</form>
</div>
<script>
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>`
});
new Vue({
el: '#app',
data: {
username: ''
}
});
</script>
</body>
</html>
解释:inheritAttrs: false
这里的作用是不让根元素<label>
继承required
和placeholder
;v-bind="$attrs"
这里的作用是让<input>
继承required
和placeholder
;label
和value
仍然作为prop传递。
参考: