全局组件
在vue中,组件不能继承父级的数据,不能直接使用外围包裹的一些数据
vm实例中,数据存放在data属性。组件中,数据由data()方法返回。使用数据时,均用花括号{{}}解析,如{{name}}、{{msg}}
<div id="app">
<hello></hello>
</div>
<script>
//方法一
var et=Vue.extend({
template:'<h1>hello,welcome to wuhan</h1>'
});
//注册组件
Vue.component('hello',et);
//方法二:语法塘
Vue.component('hello',{
template:'<h1>{{msg}},welcome to wuhan</h1>',
// template:'<h1>{{msg}},welcome to {{name}}</h1>'
// 控制台报错: Property or method "name" is not defined on the instance
data(){
return {
msg:'Hello'
}
}
});
var vm=new Vue({
el:'#app',
data:{
name:'hubei'
}
});
</script>
局部组件
<div id="app">
<hello></hello>
</div>
<script>
//局部组件在实例内部声明,可以有多个
var vm=new Vue({
el:'#app',
components:{
hello:{
template:'<h1>{{name}}</h1>',
data(){
return {name:'wuhan'}
}
}
}
});
</script>
父子组件
<div id="app">
<parent></parent>
</div>
<template id="tp">
<div>
<div>parent</div>
<child></child>
</div>
</template>
<script>
//局部组件在实例内部声明,可以有多个
var vm=new Vue({
el:'#app',
components:{
parent:{
template:'#tp',
components:{
child:{
template:'<div>child</div>'
}
}
}
}
});
</script>
子组件向父组件传递数据
$emit( [自定义事件名] , [传递数据])
点击Child,触发“s”事件,并向事件绑定的方法传递子组件自身的age。parent组件中,@s事件发生后,执行p方法,p(data)将传进来的年龄赋值给父组件自身的age属性。
<div id="app">
<parent></parent>
</div>
<template id="tp">
<div>
<div>parent</div>{{age}}
<child @s="p"></child>
</div>
</template>
<script>
//局部组件在实例内部声明,可以有多个
var vm=new Vue({
el:'#app',
components:{
parent:{
template:'#tp',
data(){
return {age:0}
},
methods:{
p(data){
this.age=data;
}
},
components:{
child:{
template:'<div @click="sayAge">child</div>',
data(){
return {age:18}
},
methods:{
sayAge(){
//向上发射事件$emit
this.$emit('s',this.age);
}
}
}
}
}
}
});
</script>
父组件向子组件传递数据
1、传:在父组件的模板中,给子组件的n属性动态绑定父组件的name
2、收:在子组件中声明属性n。
方法一:props:[‘n’],数组中添加属性名n即可,来什么收什么。
方法二:props:{ n:String },对象中添加一个键值对key:value,key是属性名,value是属性的数据类型。n:String表示属性n只接收String类型的数据,否则,虽然收到的数据仍会显示出来,但会报错
Invalid prop: type check failed for prop "n". Expected String, got Number.
<div id="app">
<parent></parent>
</div>
<template id="tp">
<div>
<div>parent</div>
<child :n="name"></child>
</div>
</template>
<script>
//局部组件在实例内部声明,可以有多个
var vm=new Vue({
el:'#app',
components:{
parent:{
template:'#tp',
data(){
return {
//name:'Hangzhou'
name:123
}
},
components:{
child:{
template:'<div>child {{n}}</div>',
//props:['n']
//对属性的数据类型进行校验
props:{n:String}
}
}
}
}
});
</script>
注意
HTML是不区分大小写的,deliveryPrice属性在HTML中写为delivery-price
- goods.vue
<template>
<shopcart :delivery-price="seller.deliveryPrice" :min-price="seller.minPrice"></shopcart>
</template>
- shopcart.vue
<script type="text/ecmascript-6">
export default {
props: {
deliveryPrice: String
}
};
</script>
子组件改变父组件数据(*)
vue1.0可以,但vue2.0不可以。
在vue2.0中,子组件是不允许更改父组件的父组件传给子组件的是引用数据类型,此时,两者操作的是同一个地址的数据,达到子组件可以改变父组件数据的效果
<div id="app">
<parent></parent>
</div>
<template id="tp">
<div>
<div>parent</div>{{name.name}}
<child :n="name"></child>
</div>
</template>
<script>
//局部组件在实例内部声明,可以有多个
var vm=new Vue({
el:'#app',
components:{
parent:{
template:'#tp',
data(){
//2.0,返回的不再是字符串,而是一个对象,引用数据类型
return {name:{name:'Hangzhou'}}
},
components:{
child:{
template:'<div @click="update">child {{n.name}}</div>',
methods:{
update(){
this.n.name='jw'
}
},
//2.0
props:{n:Object}
}
}
}
}
});
</script>
对比vue1.0
1.0 只用加sync,就可以将子组件与父组件的数据同步,更改子组件的,父组件也会更改
<div id="app">
<parent></parent>
</div>
<template id="tp">
<div>
<div>parent</div>{{name}}
<child :n.sync="name"></child>
</div>
</template>
<script src="vue1.0.js"></script>
<script>
var vm=new Vue({
el:'#app',
components:{
parent:{
template:'#tp',
data(){
return {name:'Hangzhou'}
},
components:{
child:{
template:'<div @click="update">child {{n}}</div>',
methods:{
update(){
this.n='jw'
}
},
//1.0
props:{n:String}
}
}
}
}
});
</script>
子组件更改,父组件数据不同步
<div id="app">
<parent></parent>
</div>
<template id="tp">
<div>
<div>parent</div>
{{name}}
<child :n="name"></child>
</div>
</template>
<script src="vue2.0.js"></script>
<script>
var vm=new Vue({
el:'#app',
components:{
parent:{
template:'#tp',
data(){
return {name:'Hangzhou'}
},
components:{
child:{
template:'<div @click="update">child {{a}}</div>',
data(){
return {a:''}
},
mounted(){
this.a=this.n;
},
methods:{
update(){
this.a='jw'
}
},
props:{n:String}
}
}
}
}
});
</script>
若components这样写(不推荐),如下:
会警告
vue2.0.js:465 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “n”当父组件重新渲染时,子组件已经更改过的数据会被父组件传递过来的数据覆盖掉,因此推荐使用上一种方法。
components:{
child:{
template:'<div @click="update">child {{n}}</div>',
methods:{
update(){
this.n='jw'
}
},
props:{n:String}
}
}
组件的is特性
用于显示特定的组件,当有多个组件,但在特定时刻只需要显示其中的某个时,可以用到组件的is特性。
<div id="app">
<button @click="comp='hello'">显示英文版hello</button>
<button @click="comp='hello1'">显示中文版你好</button>
<component :is="comp"></component>
</div>
<template id="hello">
<div>
hello
</div>
</template>
<template id="hello1">
<div>
你好
</div>
</template>
<script src="vue2.0.js"></script>
<script>
var vm=new Vue({
el:'#app',
data:{
comp:'hello'
},
components:{
hello:{
template:'#hello'
},
hello1:{
template:'#hello1'
},
}
});
</script>
组件slot槽
组件标签中可以插入内容。例如中想要插入其他内容,此时就要用到slot槽,否则即使写入内容,也会被组件template模板中的内容给覆盖掉。
没有名字的slot使用步骤:
- 1、直接写入内容,如
<hello>我叫小高</hello>
- 2、组件模板中添加slot标签,如
<template>
hello<slot></slot>
</template>
具名slot使用步骤:
- 1、插入的内容添加slot属性,如
<div slot="name">我叫小高</div>
- 2、组件模板中添加slot标签,并给出name属性,且与上一步中的slot值对应,例如
<template>
hello
<slot name="name"></slot>
</template>
下面代码显示结果:
- hello
- 今年三岁了
- 我叫小高
<div id="app">
<hello>
<div slot="name">我叫小高</div>
<div slot="age">今年三岁了</div>
</hello>
</div>
<!--没有名字的slot 具有名字的slot-->
<template id="hello">
<div>
<!--slot直接使用,在<hello>标签中插入的内容会自动到插槽中去了-->
<!--没有名字的slot-->
<!--hello <slot></slot>-->
<!--具名slot-->
hello <slot name="age"></slot><slot name="name"></slot>
</div>
</template>
<script src="vue2.0.js"></script>
<script>
var vm=new Vue({
el:'#app',
data:{
comp:'hello'
},
components:{
hello:{
template:'#hello'
},
}
});
</script>
非父子组件的交互
发:点击按钮,hello组件触发send方法,send方法调用Event.$emit(‘我饿了’,this.msg),触发了’我饿了’事件,并传递hello组件的msg属性。
收:hello1组件挂载的时候,Event.$on(‘我饿了’,[function(data)])会监听事件,当监听到了’我饿了’事件,则调用回调函数,将接收到的data赋值给hello1组件的msg。
<div id="app">
<hello></hello>
<hello1></hello1>
</div>
<template id="hello">
<div>
hello
<button @click="send">传递数据</button>
</div>
</template>
<template id="hello1">
<div>hello1 {{msg}}</div>
</template>
<script src="vue2.0.js"></script>
<script>
//事件a
var Event=new Vue;//event.$on event.$emit
var vm=new Vue({
el:'#app',
components:{
hello:{
template:'#hello',
data(){
return {msg:'我非常饿'}
},
methods:{
send(){
Event.$emit('我饿了',this.msg);
}
}
},
hello1:{
mounted(){
//用箭头函数,保证this的指向问题
Event.$on('我饿了',(data)=>{
//console.log(this);//this是当前hello1组件,如果不用箭头函数,this为hello组件
this.msg=data;
console.log('msg挂载');//每点击一次按钮,都会执行mounted
});
},
data(){
console.log("data加载");//只会执行一次,在打开页面的时候
return {msg:''}
},
template:'#hello1'
},
}
});
</script>
路由
后期专题补充说明路由
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.router-link-active{
background: wheat;
}
</style>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/list">列表页</router-link>
<router-view></router-view>
</div>
<script src="vue2.0.js"></script>
<script src="vue-router2.0.js"></script>
<script>
//2.0规定,组件必须要有一个根节点
var Home={template:`<div>
<h1>首页</h1>
<router-link to="/home/login">登录</router-link>
<router-link to="/home/reg">注册</router-link>
<router-view></router-view>
</div>`}
var List={template:`<div>
<h1>列表</h1>
<router-link to="/list/news/1">消息1</router-link>
<router-link to="/list/news/2">消息2</router-link>
<router-view></router-view>
</div>`}
var router=new VueRouter({
routes:[
//方法一
// {path:'/home',component:{
// template:'<h1>首页</h1>'
// }},
//方法二
{path:'/home',component:Home
//子路由
children:[
//children中,路径最前面不能加'/'
{path:'login',component:{
template:'<div>登录</div>'
}},
{path:'reg',component:{
template:'<div>注册</div>'
}}
]
},
{path:'/list',component:List,
children:[
{path:'news/:nid',component:{
template:'<div>消息是{{$route.params.nid}}</div>'
},
beforeEnter(to,from,next){
console.log(to.params.nid);
//next();//若没有这一步,代码不会继续向下执行,组件就不会继续渲染
}}
]
},
{path:'*',component:Home},
]
})
var vm=new Vue({
router,
el:'#app'
});
</script>