组件
1.全局组件 在所有被vue挂载的页面目标中都可以使用
全局组件的渲染
Vue.component("组件标签名称",{
//组件的封装信息
template:"组件显示的页面html",
// data: 组件使用的变量
methods:{
组件的事件驱动函数
}
})
组件的优点:
提高了页面代码的复用率 因为组件可以反复使用
后期维护更方便
全局组件 是 所有被Vue对象挂载的目标里面都可以使用的组件
注意:
组件的标签内部不能写任何内容 写了也会被覆盖 不会渲染到页面
除非使用 slot插槽(后面讲)
组件标签的行内样式 也同样会生效 但是不推荐
建议在组件的template模板里面写
因为组件要多次复用 在模板里面写 所有引入该组件的地方都会生效
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<!--在页面使用组件-->
<aaa >
<!--此处内容不会被渲染-->
哈哈,我是aaa组件标签的内部内容
</aaa>
<bbb></bbb>
<bbb></bbb>
<bbb></bbb>
</div>
<div id="box">
<h1>{{msg}}</h1>
<aaa></aaa>
<aaa></aaa>
<bbb></bbb>
<bbb></bbb>
</div>
<script src="js/vue.js"></script>
<script>
// 注册全局组件
Vue.component("aaa",{
// 推荐在这写样式
template:"<h1 style='font-size: 100px;'>我是aaa组件的页面模板</h1>"
})
Vue.component("bbb",{
template:"<ul><li>我是第一条</li><li>唐雪案终于平反</li></ul>"
})
var vm=new Vue({
el:'#app',
data:{
msg:'我是app的vue对象挂载的目标',
}
})
const vm1=new Vue({
el:"#box",
data:{
msg:"我是box的vue对象挂载的目标"
}
})
</script>
</body>
</html>
2.局部组件(使用的最多)
所谓的局部组件
就是在那个Vue对象里面注册的 就只能在那个Vue挂载的目标里面使用
如何注册局部组件:
在Vue对象的大括号里面写上
components:{
组件标签名:{
// 组件的配置对象
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<aaa></aaa>
<aaa></aaa>
</div>
<div id="box">
<h1>{{msg}}</h1>
<!--<aaa></aaa> 报错 不存在这个组件 因为aaa是vm对象的局部组件-->
<bbb></bbb>
</div>
<script src="js/vue.js"></script>
<script>
var vm=new Vue({
el:'#app',
data:{
msg:'我是app的vue',
},
components:{
aaa:{
template:"<ul><li>我是第一条</li><li>唐雪案终于平反</li></ul>"
}
}
});
const vm1=new Vue({
el:"#box",
data:{
msg:"我说box的vue"
},
components:{
bbb:{
template:"<ol><li>我是bbb第一条</li><li>唐雪案bbb终于平反</li></ol>"
}
}
})
</script>
</body>
</html>
组件的变量数据和事件的使用:
1.组件所渲染的变量
在组件的配置大括号里面定义data
data必须是一个函数
这个函数必须return一个大括号
在大括号里面定义变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<aaa></aaa>
<aaa></aaa>
<aaa></aaa>
<v-qq></v-qq>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("aaa",{
template:"<h1 @click='show'>我是aaa组件的模板----{{msg}}---{{str}}</h1>",
data:function(){
return{
msg:"我是组件的msg变量",
str:"我是第二个变量"
}
},
/* data:{
msg:"呵呵" 这种格式不对
}
*/
methods:{
show(){
alert("我是aaa组件的点击事件")
}
}
})
var vm=new Vue({
el:'#app',
data:{
msg:'我是app的vue代码',
},
components:{
"v-qq":{
template:"<h1 @click='show'>我是v-qq组件---{{msg}}</h1>",
data(){
return{
msg:"我是qq组件数据"
}
},
methods:{
show(){
alert("我是qq组件的点击事件")
}
}
}
}
});
</script>
</body>
</html>
template属性
* 如果没定义该属性 则Vue对象的默认页面就是el的挂载目标所在的html部分为默认页面
*
* 但是一旦定义template 那么会把template里面的模板页面直接覆盖el的挂载目标
* 甚至连挂载目标本身都没有了 直接全部覆盖
组件的模板必须至少包含一个根元素
也就是说 组件的模板最外层必须是单个元素
里面包含着可以有很多兄弟元素
解决代码过长:
1.字符串作为template的值 作为页面模板
2.反引号 模板字符串 作为template的值
3.利用template标签(推荐使用)
在vue的挂载目标之外 定义template标签
内部定义组件的模板内容
给template标签添加id
在组件的template属性写上值: #template标签的id即可
<template id="aa">
<div>
<h1>我是aaa组件</h1>
<ol>
<li>我是新闻1</li>
<li>奥利给</li>
<li>新闻3</li>
</ol>
</div>
</template>
<div id="app">
<aaa></aaa>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("aaa",{
// 1.字符串页面模板
// template:"<h1>我是aaa组件</h1>",
// 2.利用ES6的反引号 模板字符串
/*template:`
<div>
<h1>我是h1</h1>
<ul>
<li>我是列表1</li>
<li>我是2</li>
<li>我不是3</li>
</ul>
</div>
`,*/
// 3.利用template标签关联组件的模板
template:"#aa"
})
var vm=new Vue({
el:'#app',
data:{
msg:'Hello Vue!',
}
});
</script>
子组件的渲染方式:
* 1.在指定的组件的大括号里面 定义components属性
*
* 2.在components的大括号里面 定义一个键
*
* 3.键名就是子组件的标签名 值是一个json
*
* 4.在子组件的json里面配置 template data methods
*
* 子组件就只能在父组件的模板里面使用
* 出了父组件 再也找不到这个组件
<template id="parent">
<div>
<h1>我是parent父组件的模板</h1>
<ol>
<li>我是父组件的列表1</li>
<li>我是列表2</li>
<li>我是3</li>
</ol>
<!--在父组件的模板里面 引入子组件标签-->
<child></child>
</div>
</template>
<template id="child">
<div>
<h2>我是child子组件的模板</h2>
<ol>
<li>我是子组件的列表1</li>
<li>我是列表2</li>
<li>我是3</li>
</ol>
</div>
</template>
<div id="app">
<parent></parent>
<!--<child></child> 报错 因为 child是parent的子组件
只能在parent的template模板里面引入
-->
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("parent",{
template:"#parent",
// 定义子组件
components:{
child:{
template:"#child",
}
}
})
var vm=new Vue({
el:'#app',
data:{
msg:'Hello Vue!',
}
});
</script>
通过component标签能够实现渲染指定组件
component标签是vue特有的 所以必须写到vue里面
component 标签的is属性 值是一个组件的标签名
is=哪个组件的标签名 就渲染哪个组件
如果把 is用v-bind指令绑定 就可以实现动态切换显示的组件
<template id="index">
<div>
<h1>我是首页</h1>
<ul>
<li>猜你喜欢</li>
<li>限时抢购</li>
<li>今日推荐</li>
</ul>
</div>
</template>
<template id="gwc">
<div>
<h1>我是购物车</h1>
<ul>
<li>商品1</li>
<li>商品2</li>
<li>商品3</li>
</ul>
</div>
</template>
<template id="user">
<div>
<h1>我是个人中心</h1>
<ul>
<li>修改密码</li>
<li>VIP板栗</li>
<li>退出登录</li>
</ul>
</div>
</template>
<div id="app">
<!--<component is="user"></component>-->
<p>
<button @click="show(index)" v-for="(item,index) in btnArr">{{item}}</button>
</p>
<component :is="msg"></component>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("index",{
template:"#index"
})
Vue.component("gwc",{
template:"#gwc"
})
Vue.component("user",{
template:"#user"
})
var vm=new Vue({
el:'#app',
data:{
msg:"index",
btnArr:["首页","购物车","个人中心"]
},
methods:{
show(index){
if(index==0){
this.msg="index"
}else if(index==1){
this.msg="gwc"
}else if(index==2){
this.msg="user"
}
}
}
});
</script>
slot插槽
* 我们之前学习组件时 就说到了 组件标签内部所有的内容
* 在组件加载出来后 都会被覆盖掉 再也找不到
* 但是如果这个组件不是我们封装的
* 我们在使用时 需要插入一些自定义内容 根本无法实现
*
* 所以Vue为了能够让组件实现封装后 别人也能插入内容
* 也就是 组件标签内部的内容做一个保留
* 推出了一个人slot插槽
*
* 在组件模板中 自己找个位置 定义slot标签
* 这样 以后 该组件在使用时 内部所有嵌套的内容
* 自动被保存 并放到模板的slot标签的那个位置
*
* slot标签只能使用一次 也就是所保留的内容只能渲染一次
*
* slot标签默认的就是会 把组件标签内部的所有内容 都保留下来
* 但是如果只想保留一部分 或者 分批次保留呢?
*
* 那么就要通过 name和slot属性做对应
*
* 步骤:
* 1.把想保留你的页面的父元素 加一个slot属性
* 等于一个自己起的名字
*
* 2.在组件模板里面 定义slot标签 name属性等于刚才外部起的那个slot名字
*
* 就实现了保留指定元素的效果
*
* 多个部分可以起不同的slot名字 进行不同位置的保留
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<template id="bbb">
<h1>我是bbb组件的内容</h1>
</template>
<template id="aaa">
<div>
<h1>我是一个aaa组件</h1>
<!--<slot></slot>-->
<slot name="a"></slot>
<ul>
<li>奥利给</li>
<li>奥利奥</li>
<li>泡一泡</li>
</ul>
<!--<slot></slot>-->
<!--<child></child>-->
<slot name="b"></slot>
<!--<slot name="b"></slot> 只能保留一次-->
</div>
</template>
<div id="app">
<!--<aaa>
<ol>
<li>我是要放入这个自定义组件内部的内容1</li>
<li>我是内容2</li>
</ol>
</aaa>-->
<!--<aaa>
<bbb></bbb>
哈哈
</aaa>-->
<aaa>
<dl slot="a">
<dt>四大坚果</dt>
<dd>花生</dd>
<dd>瓜子</dd>
<dd>烤鱼片</dd>
<dd>把脚收一下</dd>
</dl>
<ol slot="b">
<li>2020年</li>
<li>哈哈哈</li>
</ol>
</aaa>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("bbb",{
template:"#bbb"
})
Vue.component("aaa",{
template:"#aaa",
})
var vm=new Vue({
el:'#app',
data:{
msg:'Hello Vue!',
}
});
</script>
父组件给子组件传参
* 父组件的变量zai9子组件无法直接使用
* 所以我们要使用 父组件给子组件传参的方式 让数据传给子组件使用
*
* 父-->子传参的步骤:
* 1.在父组件的模板里面 找到子组件标签
*
* 2.给这个子组件标签通过v-bind绑定一个自定义属性(属性名自己起)
*
* 3.绑定的这个自定义属性的值就是父组件要传给子组件的变量
*
* 4.在子组件的对象大括号里面 定义props
*
* 5.props的值有两种格式:
* 1.props:["qq"] 值是一个数组 数组里面都是字符串元素
* 每一个字符串就是父组件模板中 给子组件标签绑定的那个自定义属性名
*
* 这个自定义属性 就可以直接当做当前子组件date里面的一个变量
* 直接可以在子组件页面上渲染使用
*
* 2.props:{
* 那个自定义属性名:大写的传过来的值的类型名称,
* 那个自定义属性名:大写的传过来的值的类型名称,
*
* }
* props:{
* 自定义属性名1:String,
* 自定义属性名:Number,
*
* }
* 传给子组件的变量 在父组件 值发生改变时 会自动再次传给子组件
* 让子组件也跟着更新
<template id="parent">
<div>
<h1 @click="show">我是父组件的模板----{{msg_parent}}----{{num_parent}}</h1>
<ul>
<li >我是父组件数据1</li>
<li>奥利给</li>
<li>哈哈</li>
</ul>
<child :qq="msg_parent" :ww="num_parent">
</child>
</div>
</template>
<template id="child">
<div>
<h1>我是子组件的模板-----{{qq}}----{{ww}}</h1>
<ul>
<li>我是子组件数据1</li>
<li>我也是2</li>
<li>嘿嘿</li>
</ul>
</div>
</template>
<div id="app">
<parent></parent>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("parent",{
template:"#parent",
data(){
return{
msg_parent:"我是父组件的变量数据",
num_parent:56
}
},
methods:{
show(){
// 点击父组件 把 数据改变
this.msg_parent="我是新改变的父组件数据"
}
},
components:{
child:{
template:"#child",
// 注册 子组件标签上面绑定的那个自定义属性
// props:["qq","ww"]
props:{
qq:String,
ww:Number
//
}
}
}
})
var vm=new Vue({
el:'#app',
data:{
}
});
</script>
子组件给父组件传参
子组件的变量无法在父组件中直接使用
所以需要子组件给父组件传参
子组件--->父组件传参的步骤:
前提: 子组件给父组件传参必须依靠一个子组件的事件驱动(点击事件 鼠标移入 键盘按下等等等等等等)
1.给子组件添加一个事件(什么事件都行 看具体需求)
2.在事件驱动函数里面 调用 this.$emit()方法
3.this.$emit("自己起一个事件名称 随便什么名字",要给父组件传过去的变量数据);
4.在父组件的模板里面 找到子组件标签
5.给子组件标签 通过v-on绑定 $emit第一个参数的这个事件
@$emit第一个参数的名称="父组件的methods里面的一个驱动函数"
6.通过绑定事件 关联一个父组件的驱动函数
7.这个驱动函数第一个参数对应的就是$emit第二个参数 也就是那个传过来的变量
8.这个时候这个变量还无法直接渲染到父组件页面
9.在父组件的data里面定义一个变量 作为转接
10.在父组件对应的驱动函数被触发时 直接在驱动函数里面 给data的变量赋值
11.而data变量就可以直接渲染在父组件的页面上了
ps:
如果子组件的数据发生改变 但是没有重新执行$emit 那么父组件是无法接受到改变的
<template id="parent">
<div>
<h1 >我是父组件的模板----{{parent_aa}}</h1>
<ul>
<li >我是父组件数据1</li>
<li>奥利给</li>
<li>哈哈</li>
</ul>
<child @child_event="parent_method">
</child>
</div>
</template>
<template id="child">
<div>
<h1 @click="show">我是子组件的模板----{{msg_child}}</h1>
<ul @click="change">
<li>我是子组件数据1</li>
<li>我也是2</li>
<li>嘿嘿</li>
</ul>
</div>
</template>
<div id="app">
<parent></parent>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("parent",{
template:"#parent",
data(){
return{
parent_aa:""
}
},
methods:{
parent_method(a){
// 这句话是$emit方法触发的 第一个参数 就是子组件穿过来的数据
console.log("父组件的驱动函数被触发,接收第一个参数:",a);
this.parent_aa=a; //给data变量赋值 让data里面的变量渲染页面
}
},
components:{
child:{
template:"#child",
data(){
return {
msg_child:"我是子组件的变量数据"
}
},
methods:{
show(){
// 给父组件传参的方法
this.$emit("child_event",this.msg_child)
},
change(){
// 改变this.msg_child变量的数据 但是不$emit
this.msg_child="子组件新数据";
// 如果只是改变子组件本身数据 而不重新执行$emit 那么父组件不会接受改变
// this.$emit("child_event",this.msg_child);//更新一下父组件的数据
}
}
}
}
})
var vm=new Vue({
el:'#app',
data:{
}
});
</script>
父组件调用子组件的方法
methods:{
parentMethod() {
console.log(this.$refs.child1) //返回的是一个vue对象,所以可以直接调用其方法
this.$refs.child1.childMethod(this.flag);
}
}