本文记录vue组件系统下的创建与使用,包含组件之间如何传值;vue的数据请求。参考来源于IT营的大地老师关于Vue教程,需要的可留言邮箱,我会直接发百度云链接,无偿。
关于组件,借用官方的介绍,很清楚了,下图:
组件的注册与使用:
- 定义组件
- 引入组件
- 挂载组件
- 使用组件
举个例子,定义一个主页组件Home.vue,然后在根组件App.vue中使用这一组件。
首先是定义组件,先在src文件夹下新建一个components文件夹用来存放组件。进入components文件夹新建Home.vue。自己定义的组件与根组件一样,有template标签,也可有script标签、style标签。
Home.vue
<template>
<div>
<h2>{{ msg }}</h2>
</div>
</template>
<script>
export default{
data(){
return{
msg:'这是一个Home组件,在根组件中进行挂载'
}
}
}
</script>
定义好组件之后,在需要使用此组件的组件中进行自定义组件的引入、挂载、使用。例子中我们需要在根组件中使用自定义Home组件,如下图所示:(emmm,忽略IDE背景)
搞定,看看效果:(由于在demo中还有其他组件,页面上其他组件内容已马赛克)
以上。
组件中数据和方法的传递(分以下四种情况):
- 父组件传递数据和方法(甚至是整个父组件实例)到子组件
- 父组件主动获取子组件的数据和方法
- 子组件主动获取父组件的数据和方法
- 非父子组件之间数据的传递
第一种, 父组件传递数据和方法(甚至是整个父组件实例)到子组件。
分三步走:1.父组件调用子组件的时候,在标签中绑定动态属性;2.在子组件中通过props去接收父组件传递过来的数据或方法。3.和data里面的数据同样使用方式去使用,模板中直接用{{ props中的自定义命名 }},在<script>中用this.props中的自定义命名。下面例子以Home.vue为父组件,Header.vue为子组件,父组件传递一个数据和一个方法到子组件。
Home.vue(父组件)
<template>
<div>
<!-- 模板中使用子组件 -->
<!-- 在使用时给标签绑定动态属性,将数据传至子组件 -->
<!-- =号前是自定义命名,引号内是父组件中需要传递的数据或方法 -->
<v-header :fromHomeNews="homeNews" :fromHomeFunction="homeRun"></v-header>
</div>
</template>
<script>
import Header from './Header.vue'; //引入子组件
export default{
data(){
return{
homeNews:'这条数据来自Home组件'
}
},
methods:{
homeRun:function () {
alert('这个消息来自Home组件中的方法');
}
},
components:{
'v-header':Header, //挂载子组件
}
}
</script>
Header.vue(子组件)
<template>
<div id="headMsg">
<h1>{{ headerMsg }}</h1>
<p>{{ fromHomeNews }}</p> <!-- 在子组件的模板中使用父组件传递过来的数据 -->
<button @click="showHomeData()">点击显示父组件数据</button>
<button @click="fromHomeFunction()">点击调用父组件方法</button>
</div>
</template>
<script>
export default{
data(){
return{
headerMsg:'这是头部组件,在Home组件中进行挂载'
}
},
props:['fromHomeNews','fromHomeFunction'] //接收父组件传递过来的数据和方法
,methods:{
showHomeData:function () {
//<script>中使用父组件传递过来的数据
alert(this.fromHomeNews);
}
}
}
</script>
<style>
#headMsg{
color: red;
border-bottom: 1px solid #eee;
}
</style>
效果如下:
点击第一个按钮:
点击第二个按钮:
如果觉得这种父传子的方法很繁杂,那就对了。毕竟需要在标签中绑定那么多数据,不可能需要传一百个那就绑定一百个,这不现实。所以,在父组件向子组件传递数据中,有一种方法,最为简单粗暴,就是直接将整个父组件实例传过去(视情况而定,这种不代表就是最好)。举例还是由Home.vue向Header.vue传递,如下代码所示:
Home.vue
<template>
<div>
<!-- 模板中使用子组件 -->
<!-- 在使用时给标签绑定动态属性,将数据传至子组件 -->
<!-- =号前是自定义命名,引号内是父组件中需要传递的数据或方法 -->
<!-- :home="this"是直接把父组件中所有数据和方法都传递过去 -->
<v-header :fromHomeNews="homeNews" :fromHomeFunction="homeRun" :home="this"></v-header>
</div>
</template>
<script>
import Header from './Header.vue'; //引入子组件
export default{
data(){
return{
homeNews:'这条数据来自Home组件',
}
},
methods:{
homeRun:function () {
alert('这个消息来自Home组件中的方法');
}
},
components:{
'v-header':Header, //挂载子组件
}
}
</script>
Header.vue
<template>
<div id="headMsg">
<h1>{{ headerMsg }}</h1>
<p>{{ fromHomeNews }}</p> <!-- 在子组件的模板中使用父组件传递过来的数据 -->
<p>{{ home.homeNews }}</p> <!-- 两个p标签中都是引用同一个来自父组件的数据 -->
<button @click="showHomeData()">点击显示父组件数据</button>
<!-- 下面两个按钮执行的都是来自父组件的同一个方法 -->
<button @click="fromHomeFunction()">点击调用父组件方法</button>
<button @click="home.homeRun()">点击调用父组件方法</button>
</div>
</template>
<script>
export default{
data(){
return{
headerMsg:'这是头部组件,在Home组件中进行挂载'
}
},
props:['fromHomeNews','fromHomeFunction','home'] //接收父组件传递过来的数据和方法
,methods:{
showHomeData:function () {
//<script>中使用父组件传递过来的数据(两个写法都可以,因为在父组件中已经全部传过来了)
// alert(this.fromHomeNews);
alert(this.home.homeNews);
}
}
}
</script>
<style>
#headMsg{
color: red;
border-bottom: 1px solid #eee;
}
</style>
注意:传递实例跟传其他数据或者方法一样,都是在使用模板标签的时候绑定属性,但是绑定的内容只能是“this”,这个“this”代表的是当前父组件整个实例。接收也是同样在子组件的props数组中接收。但是在子组件用的时候就有点不同了,需要在指代this的自定义命名后加上父组件中的数据名或方法名。比如例子中Header.vue里面的homeNews和homeRun()都是在父组件中定义的数据名和方法名。
第二种, 父组件主动获取子组件的数据。
分两步走:父组件在调用子组件模板时,给子组件标签添加ref属性。如:<v-header ref="header"></v-header>。再通过this.$refs.header.数据名/方法名的形式去调用。
第三种, 子组件主动获取父组件的数据。
一步走就行,即直接以this.$parent.数据名/方法名的形式去调用。前提是子组件已经在父组件中挂载(这句好像是废话。。)
第二第三种合为一个例子,代码如下:
Home.vue
<template>
<div>
<v-header ref="header"></v-header>
<label>父组件按钮:</label>
<button @click="getChildData()">点击主动获取子组件的数据</button>
</div>
</template>
<script>
import Header from './Header.vue'; //引入子组件
export default{
data(){
return{
homeNews:'这条数据来自Home组件',
}
},
methods:{
homeRun:function () {
alert('这个消息来自Home组件中的方法');
},
getChildData:function () {
alert(this.$refs.header.headerNews);
},
},
components:{
'v-header':Header, //挂载子组件
}
}
</script>
Header.vue
<template>
<div id="headMsg">
<h1>{{ headerMsg }}</h1>
<label>子组件按钮:</label>
<button @click="getParentData()">点击主动获取父组件的数据</button>
</div>
</template>
<script>
export default{
data(){
return{
headerMsg:'这是Header组件,在Home组件中进行挂载',
headerNews:'这条数据是子组件中的数据',
}
},
methods:{
headerRun:function () {
alert('这个消息来自header组件中的方法');
},
getParentData:function () {
alert(this.$parent.homeNews); //this.$parent.homeNews 主动获取父组件中的homeNews
}
}
}
</script>
<style>
#headMsg{
color: red;
border-bottom: 1px solid #eee;
}
</style>
注意:主动获取的方式只能在组件的<script>标签中使用,在<template>中不生效。
效果如下:
点击子组件按钮:
点击父组件按钮:
第三种, 非父子组件之间数据的传递。
这种非父子组件传值的方式实际上并不常用,后面会有别的方式。主要是记录一下。此种方式主要分两大部分:首先新建js文件并在其中一次依次进行vue的引入、vue的实例化、暴露此实例,然后在组件中按需求进行广播或者接受数据,其中广播方式为:VueEvent.$emit('自定义名称',数据);接受方式为:VueEvent.$on('自定义名称',参数为被传递数据的回调函数);下面以Home组件广播数据,somgNews组件接收数据为例:
新建js文件名为VueEvent.js
//引入Vue
import Vue from 'vue';
//实例化Vue
var VueEvent = new Vue();
//暴露这个实例
export default VueEvent;
/*
* 使用方法:
* 在需要广播或者接收广播的组件中引入这个实例;
* 广播:VueEvent.$emit('自定义名称',数据);
* 接收广播: VueEvent.$on('自定义名称',参数为被传递数据的回调函数)
*/
Home.vue
<template>
<div id="homeArea">
<h2>{{ homeMsg }}</h2>
<button v-on:click="toNews()">广播Home组件数据</button>
</div>
</template>
<script>
import VueEvent from '../model/VueEvent';
export default{
data(){
return{
homeMsg:'我是Home组件',
}
},
methods:{
toNews:function () {
VueEvent.$emit('to-News',this.homeMsg); //广播homeMsg
}
}
}
</script>
<style>
#homeArea{
border-bottom: 1px solid #d4d4d4;
}
</style>
someNews.vue
<template>
<div>
<h2>{{ newsMsg }}</h2>
</div>
</template>
<script>
import VueEvent from '../model/VueEvent';
export default {
data(){
return {
newsMsg:'我是someNews组件'
}
},
mounted(){
VueEvent.$on('to-News',function (data) {
alert('someNews组件弹出框:'+data); //data参数即为所接收数据
})
}
}
</script>
效果如下: (点击广播按钮)
以上。
vue数据请求:
关于数据请求有很多第三方插件,官方也提供了一个叫vue-resource的请求插件,github搜索vue-resource,第一个:
github上的README文件中有介绍插件的安装与用法:
这里我使用npm安装方式,cmd进入到项目文件夹,输入如下命令:
npm install vue-resource --save
注意一下官方命令并没有在后面加上--save。加上--save是为了让它写入依赖中,方便以后项目转移时进行npm install的时候会自动添加这一插件。
插件安装完成之后,需要在main.js文件中引入vue-resource:
接下来在模板中使用这一插件。先写一个button按钮触发请求数据方法,将接受的数据存入list数组中,并且在ul>li中渲染出来。代码如下:
<template>
<div>
<button v-on:click="requestSource()">请求数据</button>
<ul>
<li v-for="item in list">{{ item.title }}</li>
</ul>
</div>
</template>
<script>
export default{
data(){
return{
list:[]
}
},
methods:{
requestSource:function () {
var urlApi = 'https://api.douban.com//v2/movie/top250';
this.$http.get(urlApi).then(function (response) {
console.log(response);
//this.list = response.body.result; //赋值给list
},function (err) {
console.log(err);
alert('请求数据失败');
});
}
},
mounted(){
//也可以在生命周期函数中调用请求数据方法,使得页面一进来就请求数据并且渲染出来
this.requestSource();
}
}
</script>
但是由于跨域请求,所以我们需要用jsonp的方式去解决跨域问题,代码修改如下:
<template>
<div>
<hr>
<h2>这是一个请求数据组件,在Home组件进行挂载</h2>
<button v-on:click="requestSource()">{{ msg }}</button>
<ul>
<li v-for="item in list">{{ item.title }}</li>
</ul>
</div>
</template>
<script>
export default{
data(){
return{
msg:'请求数据',
list:[]
}
},
methods:{
requestSource:function () {
var urlApi = 'https://api.douban.com//v2/movie/top250';
//解决跨域问题
this.$http.jsonp(urlApi,{},
{
headers: {},
emulateJSON: true }).then(function (response) {
console.log(response);
this.list = response.body.subjects;
},function (err) {
console.log(err);
alert('请求数据失败');
});
}
},
mounted(){
this.requestSource();
}
}
</script>
页面一进来就会请求数据,不用点击按钮。效果如下图(这里是取到数据中的title字段显示到页面之中):
以上。