//- 父组件发送的形式是以属性的形式绑定值到子组件身上。
//- 然后子组件用属性props接收
<div id="app">
<menu-item title=‘来自父组件的值‘></menu-item> //给子组件传入一个静态的值
//2.需要动态的数据的时候 需要属性绑定的形式设置 此时 ptitle 来自父组件data 中的数据 . 传的值可以是数字、对象、数组等
<menu-item :title=‘ptitle‘ content=‘hello‘></menu-item>
</div>
<script type="text/javascript">
Vue.component(‘menu-item‘, { //menu-item 为 子组件
props: [‘title‘, ‘content‘], // 3、 子组件用属性props接收父组件传递过来的数据
data: function() {
return { msg: ‘子组件本身的数据‘}
},
template: ‘<div>{{msg + "----" + title + "-----" + content}}</div>‘
});
var vm = new Vue({
el: ‘#app‘,
data: {
pmsg: ‘父组件中内容‘,
ptitle: ‘动态绑定属性‘
} });
</script>
// 子组件用`$emit()`触发事件 // 父组件用v-on 监听子组件的事件
// `$emit()` 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
<div id="app">
<div :style=‘{fontSize: fontSize + "px"}‘>{{pmsg}}</div>
<!--父组件用v-on 监听子组件的事件 这里 enlarge-text 是从 $emit 中的第一个参数对应 handle 为对应的事件处理函数-->
<menu-item :parr=‘parr‘ @enlarge-text=‘handle($event)‘></menu-item>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
Vue.component(‘menu-item‘, { //子组件向父组件传值-携带参数
props: [‘parr‘],
template: `
<div>
<ul><li :key=‘index‘ v-for=‘(item,index) in parr‘>{{item}}</li></ul>
### 1、子组件用$emit()触发事件
### 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
<button @click=‘$emit("enlarge-text", 5)‘>扩大父组件中字体大小</button>
</div>` });
var vm = new Vue({
el: ‘#app‘,
data: {
pmsg: ‘父组件中内容‘,
parr: [‘apple‘,‘orange‘,‘banana‘],
fontSize: 10 },
methods: {
handle: function(val){
this.fontSize += val; // 扩大字体大小
} } });
</script>
//借助于事件中心 var hub = new Vue()
- 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
- 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
- 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
<div id="app">
<div>父组件</div>
<div> <button @click=‘handle‘>销毁事件</button></div>
<test-tom></test-tom>
<test-jerry></test-jerry>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript">
var hub = new Vue(); //1、 提供事件中心 //兄弟组件之间数据传递
Vue.component(‘test-tom‘, {
data: function(){
return {num: 0}},
template: `<div>
<div>TOM:{{num}}</div>
<div>
<button @click=‘handle‘>点击</button>
</div> </div>`,
methods: {
handle: function(){
//2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件
hub.$emit(‘jerry-event‘, 2);
}},
mounted: function() {
// 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on(方法名
hub.$on(‘tom-event‘, (val) => {
this.num += val;
})}
});
Vue.component(‘test-jerry‘, {
data: function(){
return {num: 0} },
template: `
<div> <div>JERRY:{{num}}</div>
<div>
<button @click=‘handle‘>点击</button>
</div> </div> `,
methods: {
handle: function(){
//2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据) 触发兄弟组件的事件
hub.$emit(‘tom-event‘, 1);
} },
mounted: function() {
// 3、接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
hub.$on(‘jerry-event‘, (val) => {
this.num += val;
})}
});
var vm = new Vue({
el: ‘#app‘,
data: { },
methods: {
handle: function(){
//4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
hub.$off(‘tom-event‘);
hub.$off(‘jerry-event‘);
}} });
</script>
父组件可以作为其所有子组件的依赖项提供程序,而不管组件层次结构有多深。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这个数据。
如果要将 todo-items 的长度直接传递给 TodoListStatistics,我们将把这个属性向下传递到层次结构:TodoList -> TodoListFooter -> TodoListStatistics。
通过 provide/inject 方法,我们可以直接执行以下操作:
const app = Vue.createApp({})
app.component(‘todo-list‘, {
data() {
return {
todos: [‘Feed a cat‘, ‘Buy tickets‘]
}
},
provide: {
user: ‘John Doe‘
},
template: `
<div>
{{ todos.length }}
<!-- 模板的其余部分 -->
</div>
`
})
app.component(‘todo-list-statistics‘, {
inject: [‘user‘],
created() {
console.log(`Injected property: ${this.user}`) // > 注入 property: John Doe
}
})
要访问组件实例 property,我们需要将 provide 转换为返回对象的函数
这使我们能够更安全地继续开发该组件,而不必担心可能会更改/删除子组件所依赖的某些内容。
app.component(‘todo-list‘, {
data() {
return {
todos: [‘Feed a cat‘, ‘Buy tickets‘]
}
},
provide() {
return {
todoLength: this.todos.length
}
},
template: `
...
`
})
处理响应性
在上面的例子中,如果我们更改了 todos 的列表,这个更改将不会反映在注入的 todoLength property 中
如果我们想对祖先组件中的更改做出反应,我们需要为我们提供的 todoLength 分配一个组合式 API computed property:
app.component(‘todo-list‘, {
// ...
provide() {
return {
todoLength: Vue.computed(() => this.todos.length)
}
}
})
A,Prop 类型
// 到这里,我们只看到了以字符串数组形式列出的 prop:
props: [‘title‘, ‘likes‘, ‘isPublished‘, ‘commentIds‘, ‘author‘]
// 通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // 或任何其他构造函数
}
B,传递静态或动态的 Prop
//1. 你已经知道了可以像这样给 prop 传入一个静态的值:
<blog-post title="My journey with Vue"></blog-post>
//2. 你也知道 prop 可以通过 v-bind 或简写 : 动态赋值,例如:
<!-- 动态赋予一个变量的值 -->
<blog-post :title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post :title="post.title + ‘ by ‘ + post.author.name"></blog-post>
// 我们传入的值都是字符串类型的,但实际上任何类型的值都可以传给一个 prop。
//3. 传入一个数字
<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。 -->
<blog-post :likes="42"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post :likes="post.likes"></blog-post>
//4. 传入一个布尔值
<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。 -->
<blog-post is-published></blog-post>
<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。 -->
<blog-post :is-published="false"></blog-post>
<!-- 用一个变量进行动态赋值。 -->
<blog-post :is-published="post.isPublished"></blog-post>
// 5.传入一个数组
<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。 -->
<blog-post :comment-ids="[234, 266, 273]"></blog-post>
<!-- 用一个变量进行动态赋值。 -->
<blog-post :comment-ids="post.commentIds"></blog-post>
// 6.传入一个对象
<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。 -->
<blog-post
:author="{
name: ‘Veronica‘,
company: ‘Veridian Dynamics‘
}"
></blog-post>
<!-- 用一个变量进行动态赋值。 -->
<blog-post :author="post.author"></blog-post>
// 7.传入一个对象的所有 property
<!-- 如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:-->
<blog-post v-bind="post"></blog-post>
post: {
id: 1,
title: ‘My Journey with Vue‘
}
C,单向数据流
1,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
2,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。
如果你这样做了,Vue 会在浏览器的控制台中发出警告。
3,这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 作为其初始值:
4,这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
5,注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
D,Prop 验证
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组
app.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
}
},
// 具有默认值的函数
propG: {
type: Function,
// 与对象或数组默认值不同,这不是一个工厂函数 —— 这是一个用作默认值的函数
default: function() {
return ‘Default function‘
}
}
}
})
type 可以是下列原生构造函数中的一个:
String Number Boolean Array Object Date Function Symbol
此外,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:
function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
// 用于验证 author prop 的值是否是通过 new Person 创建的
app.component(‘blog-post‘, {
props: {
author: Person
}
})
E,Prop 的大小写命名
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,
camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
const app = Vue.createApp({})
app.component(‘blog-post‘, {
// camelCase in JavaScript
props: [‘postTitle‘],
template: ‘<h3>{{ postTitle }}</h3>‘
})
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
原文:https://www.cnblogs.com/xm0328/p/14250042.html