如上图所示,每一个小组件都是一个个独立的文件,而在构建页面的时候会存在嵌套行为,也就是组件包裹组件的场景,所以这就牵扯到一个问题,子组件如何传值给父组件,父组件又如何传值给子组件,他们之间如何通信,搞清楚这个问题,组件化开发,基本上就理解透了!
简单来说就是:每个页面都会抽象成如上图所示的组件树,组件之间如何通信,就是我们今天要展开说的组件之间的传值。
举个例子:组件之间传值,那么这个实例就必须以组件化的方式去创建,上一章组件的使用,这个项目必须通过http serve启动,本地是不生效的!
// 项目结构├── index.html ├── main-view.js └── main.js复制代码
- 创建了一个main-view的组件,并未这个组件在一个 methods中配置了一个onChangeDescClick的点击事件,这个事件函数有个参数type通过点击动态改变。(如下)
// main-view.jsvar MainView = { // 注意这里这个#main-view,引入的内容通过设置js的type="text/x-template"将内容append进Dom! template: '#main-view', data: function () {return { desc: '这是Android的描述信息'} }, methods: {onChangeDescClick: function (type) { this.desc = '这是' + type + '的描述信息'; } } };// 导出export { MainView };复制代码
在main.js中我们在new Vue之前导入组件,并通过局部注册组件的方式注册组件!(如下)
// main.jsimport { MainView } from './main-view.js';var vm = new Vue({el: '#app',components: { 'main-view': MainView, } });复制代码
<!-- index.html --><div id="app"><main-view></main-view></div><!--<main-view></main-view>组件实际渲染的内容 --><script type="text/x-template" id="main-view"><div><button @click="onChangeDescClick('Android')">Android</button><button @click="onChangeDescClick('IOS')">IOS</button><button @click="onChangeDescClick('Vue')">Vue</button><p>{{desc}}</p></div></script><script src="./main.js" type="module"></script>复制代码
在上面的代码中,声明了一个mainView 的组件,在组件中提供了三个按钮,通过这三个按钮来改变下面的描述信息 desc,顺便回顾了以下上一节的组件使用的内容。
然后,我们又想将<p>{{desc}}</p>抽象成一个组件,通过组件的形式引入到main-view组建中,使main-view组件与desc-view嵌套,组成父子关系组件!
在index.html中继续创建一个desc-view组件,并且在子组件中的props对象中声明了一个pushSubDesc属性,默认值为''(如下)
// index.html<script type="text/javascript"> Vue.component('desc-view', {template: '<p>{{pushSubDesc}}</p>', props: {pushSubDesc: '' } }); </script><script src="main.js" type="module"></script>复制代码
然后通过v-bind:pushSubDesc='desc'来修改pubshSubDesc的值看看,发现这样依然是可以的,这就是父组件向子组件传值的方法!
但其实可以不用这么复杂的去实现这个,Vue给我在创建组件的时候提供了一对template标签可直接使用,上边只是为了回顾一下昨天的知识以及对今天的知识做一个引入理解,模拟一下真实的项目开发中如何使用!
下来我们看一下如何在单文件中组件之间传值!
<!-- 创建父组件模板 --><template id="main-view"><div> 组件:{{ fristname}} </div></template><!-- 使用组件 --><div id="app"><!-- 父组件传值给子组件 --><desc-view :fristname="name"></desc-view></div><!-- 定义和注册组件 --><script type="text/javascript"> Vue.component('desc-view',{ template:"#main-view", // 接收数据props:{ // 这里的数据类型要与父组件的类型对应fristname:String }, }); var app = new Vue({ el:"#app", data:{ name:"vue好难学" } })</script>复制代码
Prop 还支持多种类型,下面我们来看一下 Prop 支持的数据类型:
StringNumberBooleanArrayObjectDateFunctionSymbol 复制代码
看下面的示例: 1、父组件传值给子组件props:[]【数组传值】
<div id="app"><cpn :stitle="title"></cpn></div><template id="cpn"><div><h1>{{ stitle }}</h1><h2>{{ message }}</h2></div></template><script type="text/javascript">// 子组件 Vue.component('cpn',{ template:"#cpn", data:function(){ return{ message:"这是一个组件" } }, props:['stitle'] }) // 父组件const app = new Vue({ el:"#app", data:{ title:"这是一个标题" } }) </script>复制代码
2、父组件传值给子组件,对象中的对象写法
<div id="app"><cpn :stitle="title" :sname="names"></cpn></div><template id="cpn"><div><h1>{{ stitle }}</h1><h2>{{ message }}</h2><h3>{{ sname }}</h3></div></template><script type="text/javascript">// 子组件 Vue.component('cpn',{ template:"#cpn", data:function(){ return{ message:"这是一个组件" } }, props:{ // 对象的对象写法,默认值当组件中没有通过v-bind绑定时默认显示stitle:{ type:String, default:"aaaa" }, // 如果这里为数组或者对象,默认值必须使用函数sname:{ type:Array, default:function(){ return ['liudehua', 'yuxi'] } } } }) // 父组件const app = new Vue({ el:"#app", data:{ title:"这是一个标题", names:['zhangzhen', 'xingfu'], required:true // 这个属性限制必须传值,不然报错 } }) </script>复制代码
小知识点:组件中的data为什么必须是一个函数?
首先,VUE的规定是组件中的data必须是一个函数,如果写成对象会直接报错;其次,这里牵扯到一个js浅拷贝的概念,如果设置成一个对象,那么这个data中的值在复用的时候会相互影响,他们始终指向的是同一个内存地址,而函数在每次返回的时候都会新创建一个新的内存地址,这在复用过程中不会相互影响。
下一节:Vue子组件向父组件传值!