一、环境准备
该项目需要使用vue,对于Vue的安装方式,这里选择采用npm 安装vue。然后在html中引入并使用vue。
- 首先在新建文件夹下进行npm初始化
npm init
npm是包管理工具,初始化时会在当前文件夹下产生一个package.json文件,该文件用来描述当前项目的依赖。
可以顺序输入当前项目的名字(不能包含大写字母、中文、特殊字符)、项目的版本号、项目描述、项目入口点、测试命令、git仓库地址、关键字、作者、协议(可写MIT,开源协议)。最后回车之后会根据刚刚输入的内容生成相应的package.json文件。
注意该json文件内不能写注释
- 其次,使用npm安装vue,默认下载最新版本
npm install vue
如果删除了node_modules文件夹,只需要执行npm install即可依据package.json文件中的dependencies属性将项目所依赖的模块重新安装。通常在将项目打包上传到git仓库时,可以选择在.gitignore文件中将node_modules文件夹下的文件忽略上传,以提高上传和下载的速度。只要package.json文件存在,其他人就可以在本地轻易的把依赖项安装回来,持续开发。
- 最终,在html文件中引入vue
<script src="./node_modules/vue/dist/vue.js"></script>
二、数据交互
1. 父传子
父组件通过props将属性值传递给子组件。
- 子组件在props中声明一个属性(变量),用于接收父组件传过来的值
- 父组件给子组件的行间属性绑定数据,该数据属于父组件
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子组件间的数据交互</title>
</head>
<body>
<div id="app">
父亲:儿子本月生活费{{money}}元
<child :my-Money='money'></child>
</div>
</body>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
money:1500
},
components:{
child:{
props:['myMoney'],
template:`<div>儿子:我收到{{myMoney}}元生活费</div>`
}
}
});
</script>
</html>
上述实例中,在子组件child中,props属性中定义的是myMoney属性。但是由于HTML特性是不区分大小写,所以父组件在传递数据时,将驼峰法转换成了短横线隔开。myMoney转换成my-money。
2. 子传父
注意父子组件通过props属性传递值,但props是单向绑定的,父组件的属性变化时,将变化传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。 子组件要给父组件传递消息可以通过$emit()调用父组件定义的方法。
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子组件间的数据交互</title>
</head>
<body>
<div id="app">
父亲:儿子本月生活费{{money}}元
<child :my-Money='money'></child>
</div>
</body>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
money:1500
},
components:{
child:{
props:['myMoney'],
template:`<div>儿子:我收到{{myMoney}}元生活费 <button @click="myMoney=2000">生活费不够</button></div>`
}
}
});
</script>
</html>
在上述实例中,父组件将自身变量money的值传递给子组件child的myMoney属性,child组件更改了传递过来的值,将myMoney的值更改为2000,自身视图跟着刷新。但是父组件并没有受到子组件这一操作的影响,父组件的money值维持不变,视图没有更新。同时,应当注意到控制台会产生警告,表示子组件这一操作并没有影响到父组件,操作不合法。
由于父子组件之间的单向数据流,子组件不能像父组件一样通过属性去影响对方。正确的做法应当是,子组件不直接更改父组件传递过来的值,而是通知父组件需要更改值,由父组件更改,才能通过单向数据流同时刷新父子组件的视图。具体实践如下:
- 首先在父组件中给子组件绑定上自定义事件,同时定义触发自定义事件时会执行的事件处理方法。
- 在子组件上触发自定义事件,调用父组件的方法,并给父组件的方法传递参数。
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子组件间的数据交互</title>
</head>
<body>
<div id="app">
父亲:儿子本月生活费{{money}}元
<!-- v-on:parent-child意为给child组件绑定parent-child事件,其值为方法名。该事件被触发时会调用doSomething方法 -->
<child :my-Money='money' v-on:parent-child="doSomething"></child>
</div>
</body>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:'#app',
data:{
money:1500
},
methods:{
doSomething(val){
console.log(val);
//父组件接收到参数后,更新自身数据
this.money=val;
}
},
components:{
child:{
props:['myMoney'],
methods:{
getMessage(){
//子组件触发自身绑定的parent-child事件,并给即将调用的父组件方法doSomething传递参数
this.$emit('parent-child',2000);
}
},
template:`<div>儿子:我收到{{myMoney}}元生活费 <button @click="getMessage">生活费不够</button></div>`
}
}
});
</script>
</html>
实际上子传父采用的方式就是应用了发布-订阅模式。有兴趣可以了解一下发布-订阅模式的原理,主要与this.$on() 以及this.$emit()有关。
== 注意:在js中,对象和数组都是引用类型,指向同一个内存空间,如果props是一个对象或者数组,在子组件内部改变它就会影响父组件的状态。==