Question :什么是组件化?
将想要的各种功能,丢进一个个的组件,就叫做组件化。
在vue中,每一个template组件,面只能有一个元素,该唯一元素,可以有子元素,且子元素没有上限。template模板在没有调用的情况下,不被识别。
一、组件用法
1.在html中或模板字符串中写好模板 (template script textarea)
<template id="tem">
<div>
<p>i am first p</p>
<p>i an sceond p</p>
</div>
</template>
2.调用Vue.extend()创建组件构造器,使template变成组件。
(已经在html中创建啦。)
在js中构造模板如下:
使用模板字符串,先创建,再注册。在注册中表明标识符和创建字符串的变量。
let pro = Vue.extend({
template:`
<div>
<p>我是一个p</p>
<button >点我点我????</button>
</div>
`
})
/* 注册组件 */
Vue.component("my-pro",pro);
3.调用Vue.component()注册组件,只有注册过的组件,才能被挂载元素调用。
my-pro类似组件的标识符,便于调用。
Vue.component("my-pro",{
template:"#tem"//选中模板
})
4.挂载元素 div#app 直接调用。
<div id="app">
<!-- 使用模板标识符,调用模板 -->
<my-pro></my-pro>
</div>
二、局部组件和全局组件。
全局组件,单独写在外部的组件,如上3中注册的组件my-pro为全局组件。
局部组件,写在实例Vue中的组件。
如下:
- 模板写在挂载元素前面(针对script)。
- 使用script创建的模板注意这是type = "text/x-template"。
<body>
<!-- 使用template作为模板 -->
<template id="tem">
<p>我是#tem</p>
</template>
<!-- 使用script作为 -->
<script type="text/x-template" id="rip" >
<p>我是script模板</p>
</script>
<div id="box">
<!-- 调用通过template创建的局部组件 -->
<lly></lly>
<!-- 调用通过script创建的局部组建 -->
<srci></srci>
</div>
</body>
<!-- 引入vue.js -->
<script src="vue.js"></script>
<script>
new Vue({
el:"#box",
components:{
"lly":{
template:"#tem"
},
"srci":{
template:"#rip"
}
}
})
</script>
三、父子组件。
1.构造父子组件
父子组件存在依赖关系。
①:全局分别构造父子组件。
②:在父组件中注册子组件。
③:全局注册父组件。
综上构成依赖关系。
2.调用父子组件。
父子组件嵌套调用。
①:挂载中直接调用父组件。
②:父模板中任意位子调用组件。
<body>
<!-- 挂载元素 -->
<div id="app">
<!-- 调用父组件 -->
<tem-parent></tem-parent>
</div>
<!-- 子组件 -->
<template id="tem-child">
<p>我是儿子</p>
</template>
<!-- 父组件 -->
<template id="tem-parent">
<div>
<p>我是爸爸</p>
<!-- 父组件中调用子组件 -->
<tem-child></tem-child>
</div>
</template>
</body>
<script src="./vue.js"></script>
<script>
let child = Vue.extend({
template:"#tem-child"
})
let parent = Vue.extend({
template:"#tem-parent",
/* 父组件中注册子组件 */
components:{
"tem-child":child
}
})
/* 注册父组件 */
Vue.component("tem-parent",parent);
/* 实例化vue */
new Vue({
el:'#app'
})
</script>
nice!
四、挂载数据
多次调用模板,会相互影像数据。要将返回数据作为对象全部return。
举个点赞栗子:
![](https://img.haomeiwen.com/i13182420/07ea9d68582fce44.gif)
代码如下:
<body>
<!-- 先写个模板 -->
<template id="tem">
<div>
<!-- 点击调用foo方法 -->
<button @click = "foo()">点赞{{count}}</button>
</div>
</template>
<!-- 再写个挂载div -->
<div id="app">
<div class="con">
<tem></tem>
<tem></tem>
<tem></tem>
<tem></tem>
<tem></tem>
<tem></tem>
</div>
</div>
</body>
<script src="./vue.js"></script>
<script>
/* 注册组件 */
Vue.component("tem",{
template:"#tem",
data(){
return{
/* 返回数据对象 */
count:0
}
},
methods:{
foo(){
this.count++;
}
}
})
new Vue({
el: '#app'
})
</script>
vue实现分页效果。上一页下一页~
效果图如下:
![](https://img.haomeiwen.com/i13182420/b39f4673d1e96b39.gif)
复习一波鼠标点击的五中状态:
- a:link 未访问时的状态(鼠标点击前显示的状态)
- a:hover 鼠标悬停时的状态
- a:visited 已访问过的状态(鼠标点击后的状态)
- a:active 鼠标点击时的状态
- a:focus 点击后鼠标移开保持鼠标点击时的状态(只有在<a href="#"></a>时标签中有效)
<style>
.box{
height: 45px;
margin: 60px auto;
padding: 5px 30px;
}
button{
width: 90px;
height: 100%;
text-align: center;
}
span{
display: inline-block;
width: 50px;
text-align: center;
background-color: rgba(202, 152, 163, 0.2);
margin: 5px;
}
.act{
background-color: rgba(202, 152, 163, 0.6);
}
span:active{
background-color: rgba(30, 152, 163, 0.6);
}
</style>
<body>
<template id="tem">
<div class="box">
<!-- 点上一张被选中的减减 -->
<button v-show = "active != 1" @click = "active--">上一页</button>
<!-- 动态生成span -->
<span v-for = "index in pages" :class ="{act:active == index}" @click = "goto(index)">{{index}}</span>
<button v-show = "active != allpage" @click = "active++">下一页</button>
</div>
</template>
<!-- Vue 挂载元素 -->
<div id="app">
<!-- 引入辣个模板 -->
<tem></tem>
</div>
</body>
<script src="./vue.js"></script>
<script>
/* 注册辣个组件 */
Vue.component("tem",{
template:"#tem",
data(){
return{
allpage:15,//总页
opcpage:5,//显示页
active:1 //当前显示页,默认为1
}
},
computed:{
pages(){
let pag = []; //保存需要显示的页数。
/* 当当前显示页<显示页数 */
if(this.active < this.opcpage){
/* 取小 */
let i = Math.min(this.opcpage,this.allpage);
while(i){
pag.unshift(i--);
}
}else{
//获取起始位子
let mid = this.active - Math.floor(this.opcpage / 2);
let i = this.opcpage;
if(mid > (this.allpage -this.opcpage)){
mid = (this.allpage - this.opcpage)+1;
}
while (i--) {
pag.push(mid++)
}
}
return pag;
}
},
methods:{
goto(cur){
if(cur != this.active){
this.active = cur;
}
}
}
})
/* 实例化辣个Vue */
new Vue({
el:"#app"
})
</script>
emmm,这个思路每台明白,复制一波,很难受。
五、组件通信 props
props 可以是数组或对象,用于接收来自父组件的数据。在组件中使用变量,在父组件(挂载app中传递参数。)
1.传递变量
<!-- 整个模板 -->
<template id = "tem">
<div>
<h1>{{mse}}</h1>
<p>{{msg}}</p>
</div>
</template>
<!-- div -->
<div id = "app">
<!-- 调用模板,传参 -->
<my-pro mse = "我是模板1" msg= "我是p"></my-pro>
</div>
</body>
<script src="./vue.js"></script>
<script>
Vue.component("my-pro",{
/* 用于接受父组件的数据 */
props:["mse","msg"],
template:"#tem"
})
new Vue({
el:"#app",
})
</script>
2.传递属性
将props中值定义为属性,属性值通过实例Vue中的data传输,在模板中直接写属性值,通过调用者(挂载div#app)使用属性名传data值。
<body>
<template id="tem">
<div>
<!-- 在模板中写属性 -->
{{aa}}
</div>
</template>
<div id="app">
<!-- 调用时,通过属性传值 -->
<my-pro :aa = "msg"></my-pro>
</div>
</body>
<script src="./vue.js"></script>
<script>
Vue.component("my-pro",{
template:"#tem",
props:["aa"] //定义属性aa 通过data传值
})
new Vue({
el:"#app",
data:{
msg:"我是莉莉娅"
}
})
</script>
六、子组件响应。
通过$.emit(“xxx”)中的xxx 作为该模板的属性,触发父组件的事件。
![](https://img.haomeiwen.com/i13182420/44be2097af895289.gif)
<template id="btn">
<!-- 调用组件中的方法 -->
<button @click = 'fn()'>点击了{{count}}次</button>
</template>
<div id="app">
<!--xxx作为父组件属性监听父组件的方法 -->
<my-btn @xxx = 'all()'></my-btn>
<my-btn @xxx = 'all()'></my-btn>
<my-btn @xxx = 'all()'></my-btn>
<my-btn @xxx = 'all()'></my-btn>
<my-btn @xxx = 'all()'></my-btn>
<p>总共点击了{{soc}}下</p>
</div>
</body>
<script src="./vue.js"></script>
<script>
/* 注册组件 */
Vue.component("my-btn",{
template:'#btn',
data(){
return {
count : 0
}
},
methods:{
fn(){
this.count ++;
//响应父组件的xxx事件,通过xxx事件调用父组件的all事件
this.$emit('xxx');
}
}
})
new Vue({
el:'#app',
data:{
soc:0
},
methods:{
all(){
this.soc ++;
}
}
})
</script>
七、三层通信(可以说是每句话都写注释了!)
nice!
1.创建内层模板。
在内层模板中直接调用该props中的属性名。
2.创建中间层模板
中间层调用内层模板使用内层属性名 ,并将自身属性名赋值。
3.挂载元素作为最外层,即三层。
外层调用中间层模板使用中间层属性名 ,将实例vue中data数据名赋值。
4.引入vue.js
5.构建内层模板。
6.注册中间层模板,并在内部注册内层模板。
7.实例vue。
<body>
<!-- 三层通信,调用者作为最高层一层层传输数据。 -->
<!-- 创建内层模板 -->
<template id="in-set">
<div>
<!-- 内层直接调用属性名 -->
{{tmin}}
</div>
</template>
<!-- 创建中间层模板 -->
<template id="mid">
<div>
<!-- 中间层调用内层模板使用内层属性名 并将自身属性名赋值-->
<in-set :tmin="tmid"></in-set>
</div>
</template>
<!-- 挂载元素作为最外层 -->
<div id="out-set">
<!-- 外层调用中间层模板使用中间层属性名 将实例vue中data数据名赋值 -->
<mid :tmid = "msg"></mid>
</div>
</body>
<!-- 引入vue -->
<script src="./vue.js"></script>
<script>
/* 构建内层模板 */
let tmin = Vue.extend({
template:"#in-set",
props:["tmin"]
})
/* 注册中间层模板,并且在内部注册内层模板 */
/* 中间层模板,标识为mid */
Vue.component("mid",{
template:"#mid",
props:["tmid"],
components:{
/* 注册内层模板,标识为in-set */
"in-set":tmin
}
})
new Vue({
el:"#out-set",
data:{
msg:"我是一条数据。"
}
})
</script>
一个傻了吧唧的demo
数据渲染,和emm多次复用。
![](https://img.haomeiwen.com/i13182420/d8b5a33880b5dd37.png)
八、插槽 slot
①:匿名插槽、
定义:
<slot>自定义部分</slot>
调用:
<h1>自定义</h1>
在挂在元素中调用模,模板中的slot块可自定义内容。自定义内容湖识别slot标签并自定插入。
②:命名插槽
定义:
<slot name='s1'>自定义部分</slot>
调用:
<h1 slot='s1'>自定义</h1>
写好相应名字调用
网友评论