文章目录
组件基础
组件介绍
- 模块化就是将系统功能分离成独立的功能部分的方法,一般指的是单个的某一种东西,例如js、css
- 而组件化针对的是页面中的整个完整的功能模块划分,组件是一个html、css、js、image等外链资源,这些部分组成的一个聚合体
- 优点:代码复用,便于维护
- 划分组件的原则:复用率高的,独立性强的
- 组件应该拥有的特性:可组合,可重用,可测试,可维护
Vue组件是可复用
的 Vue 实例
,且带有一个名字:例如 <button-counter>
。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
<div id="app">
<button-counter></button-counter>
</div>
组件的注册
全局组件注册
- 全局组件注册代码
//创建组件
const Hello=Vue.extend({
template:`<h1>hello world</h1>`
})
// 全局注册
Vue.component('hello',Hello)
- 全局组件注册的组件可以在任意vue实例下使用
<div id="app">
<hello></hello>
</div>
<div id="app2">
<hello></hello>
</div>
<script src="./base/vue.js"></script>
<script>
// 创建组件
const Hello=Vue.extend({
template:`<h1>hello world</h1>`
})
// 全局注册
Vue.component('hello',Hello)
new Vue({
el:"#app",
})
new Vue({
el:"#app2",
})
</script>
- 注册成功并复用,会出现两个hello world
局部组件注册
- 局部组件注册代码
// // 创建组件
const Hello=Vue.extend({
template:`<h1>hello world</h1>`
})
new Vue({
el:"#app",
// 局部注册
components:{
hello:Hello
}
})
- 局部组件注册的组件只能在当前注册的vue实例下使用
<div id="app">
<hello></hello>
</div>
<div id="app2">
<hello></hello>
</div>
<script src="./base/vue.js"></script>
<script>
// // 创建组件
const Hello=Vue.extend({
template:`<h1>hello world</h1>`
})
new Vue({
el:"#app",
// 局部注册
components:{
hello:Hello
}
})
new Vue({
el:"#app2",
})
new Vue({
el:"#app"
})
</script>
- 只会出现一个hello world ,并报错
组件注册简写
全局组件注册简写
Vue.component('组件名',{template:''})
Vue.component("hello",{
template:`<h1>hello Vue</h1>`
})
局部组件注册简写
components{hello:{template:""}}
new Vue({
el:"#app",
components:{
hello:{
template:`<h1>hello Vue</h1>`
}
}
})
data必须是一个函数
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
- 简单案例
- 注册一个组件,定义数据msg=1,当点击按钮时,msg=2,
- 如果data方法不返回一个对象的话,当组件复用时,点击一个按钮,另一个按钮的数据也会改变
因为如果data方法不返回对象浏览器会直接报错,所以我们这里用一个Vue实例来模拟这种情况
<div id="app">
<button @click='change'>msg={{msg}}</button>
<hr>
<button @click='change'>msg={{msg}}</button>
</div>
<script src="./base/vue.js"></script>
<script>
// Vue实例
new Vue({
el:"#app",
data:{
msg:1
},
//点击按钮数据改变
methods:{
change(){
this.msg=2
}
}
})
</script>
- 如果data方法返回一个对象的话,当组件复用时,点击一个按钮,每一个组件实例都拥有独立的data属性
<div id="app">
<!-- 组件复用 -->
<hello></hello>
<hr>
<hello></hello>
</div>
<script src="./base/vue.js"></script>
<script>
// 注册全局组件
Vue.component("hello",{
// 模板
template:"<button @click='change'>msg={{msg}}</button>",
// data方法返回一个对象
data(){
return {
msg:1
}
},
//点击按钮数据改变
methods:{
change(){
this.msg=2
}
}
})
// Vue实例
new Vue({
el:"#app"
})
</script>
template组件模板
- 可以在body里创建template标签在组件里指定template
- 模板内容必须有根元素
- 必须用id作为标记
- template标签不会被渲染在页面上
<div id="app">
<hello></hello>
</div>
<!-- 必须是id作为标记 -->
<template id="hello">
<!-- 必须有根元素 -->
<div>
<h1>这是h1标签</h1>
<p>这是p标签</p>
</div>
</template>
<script src="./base/vue.js"></script>
<script>
//注册全局组件
Vue.component("hello", {
template: "#hello"
})
new Vue({
el: "#app",
})
</script>
- 运行结果如下,且template标签不会被渲染在页面上
注意浏览器规则,利用is放入组件
vue在解析模板的时候会根据某些html的规则,
例如,在table里只能放tr,td,th…,如果放入组件不会解析 这个时候我们可以放入tr使用is方式来标识这个tr其实是组件
- 不使用is方式
- 没有在tr标签中
<div id="app">
<table>
<tbody>
<tr>
<hello></hello>
</tr>
</tbody>
</table>
</div>
<script src="./base/vue.js"></script>
<script>
Vue.component("hello", {
template: "<p>这是一个组件</p>"
})
new Vue({
el: "#app",
})
</script>
- 使用is方式
<div id="app">
<table>
<tbody>
<tr is="hello"></tr>
</tbody>
</table>
</div>
<script src="./base/vue.js"></script>
<script>
//注册全局组件
Vue.component("hello", {
template: "<p>这是一个组件</p>"
})
new Vue({
el: "#app",
})
</script>
动态组件(is切换)
在不同组件之间进行动态切换,可以通过Vue 的 component元素加一个特殊的 is attribute 来实现
- 简单案例,点击按钮切换组件
<div id="app">
<!-- 添加点击事件 利用三目运算符 如果msg的值为my-a就切换成my-b 否则 切换为my-a -->
<button @click="msg=msg==='my-a'?'my-b':'my-a'">切换a,b组件</button>
<!--实现组件切换 msg是组件名称 component 不会渲染在页面上-->
<component :is="msg"></component>
</div>
<script src="./base/vue.js"></script>
<script>
new Vue({
el: "#app",
data:{
msg:"my-a"
},
//两个组件
components:{
"my-a":{
template:"<h1>这是a组件</h1>"
},
"my-b":{
template:"<h1>这是b组件</h1>"
},
}
})
</script>
-component
不会被渲染在页面上
组件嵌套
应用中划分的组件可能会很多,为了更好的实现代码复用,所以必然会存在组件的嵌套关系
组件设计初衷就是要配合使用的,最常见的就是形成父子组件的关系:组件 A 在它的模板中使用了组件 B。
<div id="app">
<father></father>
</div>
<script src="./base/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg: "my-a"
},
components: {
// 父组件
father: {
// 在父组件中引用子组件
template: "<div>这是父亲组件<son></son></div>",
// 子组件
components: {
son: {
template: "<p>这是儿子组件</p>"
},
}
},
}
})
</script>
插槽
- vue里提供了一种将父组件的内容和子组件的模板整合的方法:内容分发,通过slot插槽来实现
<slot></slot>
匿名插槽
在父组件中使用子组件的时候,在子组件标签内部写入内容。在子组件的模板中可以通过<slot></slot>
来使用
<div id="app">
<hello>
<div>联通卡</div>
<div>移动卡</div>
</hello>
</div>
<!-- 匿名插槽 -->
<template id="hello">
<div>
<slot></slot>
</div>
</template>
<script src="./base/vue.js"></script>
<script>
new Vue({
el:"#app",
components:{
hello:{
template:"#hello"
}
}
})
</script>
- 不管什么内容都被放在一个插槽中,如果有两个
<slot></slot>
,运行之后
<template id="hello">
<div>
<slot></slot>
<slot></slot>
</div>
</template>
具名插槽
- 父组件在子组件标签内写的多个内容我们可以给其设置slot属性来命名,在子组件的模板通过通过使用
带有name属性
的slot标签来放置对应的slot。
<div id="app">
<hello>
<div slot="a">联通卡</div>
<div slot="b">移动卡</div>
</hello>
</div>
<!-- 具名插槽 -->
<template id="hello">
<div>
<slot name="a"></slot>
<hr>
<slot name="b"></slot>
</div>
</template>
<script src="./base/vue.js"></script>
<script>
new Vue({
el:"#app",
components:{
hello:{
template:"#hello"
}
}
})
</script>
- 新版本2.6+支持
v-slot方式
- v-slot在使用时,需要
在template标签内
<div id="app">
<hello>
<!-- v-solt方式-->
<template v-slot:a>
<div>联通卡</div>
</template>
<template v-slot:b>
<div>移动卡</div>
</template>
</hello>
</div>
<template id="hello">
<div>
<slot name="a" ></slot>
<hr>
<slot name="b" ></slot>
</div>
</template>
<script src="./base/vue.js"></script>
<script>
new Vue({
el:"#app",
components:{
hello:{
template:"#hello"
}
}
})
</script>
接收props的具名槽口
<slot name="b" :msgb="msg"></slot>
<template v-slot:b="info"></template>
<div id="app">
<hello>
<template v-slot:a>
<div>联通卡</div>
</template>
<!-- info 自己写的一个名字,可以随便起 -->
<template v-slot:b="info">
<div>移动卡 {{info.msgb}}</div>
</template>
</hello>
</div>
<template id="hello">
<div>
<slot name="a"></slot>
<hr>
<slot name="b" :msgb="msg"></slot>
</div>
</template>
<script src="./base/vue.js"></script>
<script>
Vue.component("hello", {
template: "#hello",
data() {
return {
msg: "你好"
}
}
})
new Vue({
el:"#app"
})
</script>
过滤器
过滤器必须要要有返回值 return
,通过管道符|
连接
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。
-
在双花括号中
{{ message | capitalize }}
-
在
v-bind
中
<div v-bind:id="rawId | formatId"></div>
vue1.0的有默认的过滤器,但是在2.0的时候全部给去掉了
所以在vue中如果想要使用过滤器就需要自定义
自定义的方法有两种:全局定义和局部定义,
- 全局定义的过滤器在任意的实例、组件中都可以使用,
- 局部定义就是在实例、组件中定义,只能在这个实例或组件中使用
- 当全局过滤器和局部过滤器重名时,会采用局部过滤器。
- 全局定义
Vue.filter(name,handler)
name是过滤器的名字,handler是数据格式化处理函数,接收的第一个参数就是要处理的数据,返回什么数据,格式化的结果就是什么
在模板中通过 | (管道符) 来使用,在过滤器名字后面加()来传参,参数会在handler函数中第二个及后面的形参来接收
Vue.filter('firstUpper',function (value,num=1,num2) {
console.log(num2)
return value.substr(0,num).toUpperCase()+value.substr(num).toLowerCase()
})
- 局部定义
在实例、组件的配置项中设置 filters,键名为过滤器名,值为handler
filters:{
firstUpper:function (value,num=1,num2) {
console.log(num2)
return value.substr(0,num).toUpperCase()+value.substr(num).toLowerCase()
}
}
- 运行上述代码查看结果
- 从0到第num位大写,从num+1位到最后小写,默认num为1,并打印输出num2
<div id="app">
<p>{{msg | firstUpper(2,3)}}</p>
</div>
<script src="./base/vue.js"></script>
<script>
// 全局过滤器
Vue.filter('firstUpper', function (value, num = 1, num2) {
console.log(num2)
return value.substr(0,num).toUpperCase() + value.substr(num).toLowerCase()
})
new Vue({
el: "#app",
data: {
msg: "world"
},
//局部过滤器
// filters: {
// firstUpper: function (value, num = 1, num2) {
// console.log(num2)
// return value.substr(0, num).toUpperCase() + value.substr(num).toLowerCase()
// }
// }
})
</script>