目录
一、插槽
插槽可以分为默认插槽、具名插槽(具有名字的插槽)、作用域插槽。插槽允许我们在调用子组件的时候为子组件传递模板。
1、默认插槽
没有名字的插槽就是默认插槽,一个不带 name 的 <slot> 出口会带有隐含的名字“default”。
<slot></slot>
或者
<slot name="default"></slot>
组件标签里面的内容会被渲染到默认插槽:
<body>
<div id="app">
<!-- 组件标签里面的内容需要使用插槽来接收,否则无法渲染出来,
而里面的内容会默认渲染到默认插槽中 -->
<my-a>hello vue</my-a>
</div>
<script>
// 定义组件
let myA={
template:`
<div>
<p>1111111</p>
<slot></slot>
<slot></slot>
<p>3333333</p>
</div>
`
}
new Vue({
el:"#app",
//局部注册组件
components:{
"my-a":myA
}
})
</script>
</body>
结果如下:
2、具名插槽
具有名字的插槽就是具名插槽。
当我们需要把组件标签内相应内容渲染到相应的插槽中时,使用具名插槽,此时需要在组件标签内使用template模板:
<slot name='header'></slot>
<template v-slot:header>头部内容</template>
<body>
<div id="app">
<my-a>
<!-- 使用 v-slot:插槽名 ,这样就可以把相应内容放到相应插槽中 -->
<template v-slot:footer>底部内容</template>
<!-- default 表示默认插槽 -->
<template v-slot:default>hello vue</template>
<template v-slot:center>中间内容</template>
<!-- <template v-slot:header>头部内容</template> -->
<!-- v-slot: 可以简写成 # -->
<template #header>头部内容</template>
</my-a>
</div>
<script>
// 定义组件
let myA={
template:`
<div>
<p>1111111</p>
<slot></slot>
<slot></slot>
<p>3333333</p>
<hr/>
<slot name='header'></slot>
<slot name='center'></slot>
<slot name='footer'></slot>
</div>
`
}
new Vue({
el:"#app",
components:{
"my-a":myA
}
})
</script>
</body>
结果如下:
3、作用域插槽
我们在子组件内使用插槽传递数据,传递的数据需要在组件标签内使用作用域插槽获取。
<slot :row='item'></slot>
<template slot-scope="scope">{
{scope}}</template>
<body>
<div id="app">
<!-- 父组件给子组件传递数据 :arr="arrs" -->
<my-a :arr="arrs">
<!-- v-slot对应插槽的name,这样就可以把相应内容放到相应插槽中 -->
<template v-slot:footer>底部内容</template>
<div>hello vue</div>
<template v-slot:center>中间内容</template>
<!-- <template v-slot:header>头部内容</template> -->
<!-- v-slot: 可以简写成 # -->
<template #header>头部内容</template>
<!-- 作用域插槽 slot-scope="变量" 该变量用于接收数据-->
<template slot-scope="scope">
{
{scope}}
</template>
</my-a>
</div>
<script>
// 定义组件
let myA={
// 接收父组件传递过来的数据
props:['arr'],
template:`
<div>
<p>1111111</p>
<slot></slot>
<slot></slot>
<p>3333333</p>
<hr/>
<slot name='header'></slot>
<slot name='center'></slot>
<slot name='footer'></slot>
<hr/>
<ul>
<li v-for='item in arr'>
<slot :row='item'></slot>
</li>
</ul>
</div>
`
}
new Vue({
el:"#app",
data:{
arrs:[
{id:1,name:'zhangsan'},
{id:1,name:'lisi'},
{id:1,name:'wangwu'},
]
},
components:{
"my-a":myA
}
})
</script>
</body>
结果如下:
可以看到,默认插槽的“hello vue” 没有被渲染出来,因为作用域插槽没有名字,所以也是一个默认插槽。作用域插槽它会将前面的默认插槽内容覆盖,解决办法就是给作用域插槽加上名字:
<slot name="content" :row='item'></slot>
<!-- v-slot:插槽名字="变量" -->
<template v-slot:content="scope">{
{scope}}</template>
二、自定义指令
Vue中多有的指令都以 v- 来调用。但是,有时候Vue提供给我们的指令并不能满足我们的需求,这个时候 我们就需要自定义指令。
指令允许我们对普通 DOM 元素进行底层操作。可以全局注册也可以局部注册:
全局注册:
Vue.directive()
局部注册:
在Vue实例或组件中添加选项directives
钩子函数:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
-
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 -
inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 -
update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
-
componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。 -
unbind
:只调用一次,指令与元素解绑时调用。
钩子函数的参数 有 el
、binding
、vnode
和 oldVnode。
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括v-
前缀。value
:指令的绑定值oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。arg
:传给指令的参数,可选。modifiers
:一个包含修饰符的对象。
vnode
:Vue 编译生成的虚拟节点。oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用。
<body>
<div id="app">
<!-- 自定义指令 v-focus -->
用户名:<input type="text" v-focus="bgColor">
<!-- 自定义指令 v-myshow -->
<input type="text" v-myshow="msg">
</div>
<script>
// 全局注册自定义指令 Vue.directive('指令名称',{配置对象})
Vue.directive('focus', {
inserted(el, binding) {
// console.log(el,binding);
// 让输入框自动聚焦
el.focus()
},
// 执行一次性的初始化设置
bind(el, binding, vnode) {
console.log(el,binding,vnode);
el.style.backgroundColor = binding.value
}
})
new Vue({
// 局部注册自定义指令
directives:{
// 指令名称:{配置对象}
'myshow': {
bind(el,binding,vnode){
el.value = binding.value
}
}
},
el: "#app",
data: {
bgColor: 'pink',
msg: 'hello'
}
})
</script>
</body>
结果如下:
参数binding打印结果:
三、render渲染函数
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。
在定义一个组件的时候,我们一般使用template来创建模板,而使用template来创建模板,最终会被编译成render函数,由render函数来创建一个模板。
例子:
使用template创建模板:
<body>
<div id="app">
<my-a></my-a>
</div>
<script>
let myA = {
template:`
<div>
<ul>
<li v-for='item in arrs'>
{
{item.name}}
</li>
</ul>
</div>
`,
data(){
return {
msg:"我是一个div标签",
arrs:[
{id:1, name:'zhangsan', age:12},
{id:2, name:'lisi', age:13},
{id:3, name:'wangwu', age:14},
]
}
}
}
new Vue({
el:"#app",
components:{
'my-a': myA
}
})
</script>
</body>
结果:
使用render渲染函数:
<body>
<div id="app">
<my-a></my-a>
</div>
<script>
let myA = {
render(h){
//遍历创建li标签
let lis = this.arrs.map(item => {
return h('li', {}, item.name)
})
//三个参数:
// 第一个参数:创建的标签名称,
// 第二个参数:一个数据对象,可以设置标签样式、属性等
// 第三个参数:标签内容,可以写成数组
return h('ul', {
style:{
backgroundColor: 'pink'
}
}, lis)
},
data(){
return {
msg:"我是一个div标签",
arrs:[
{id:1, name:'zhangsan', age:12},
{id:2, name:'lisi', age:13},
{id:3, name:'wangwu', age:14},
]
}
}
}
new Vue({
el:"#app",
components:{
'my-a': myA
}
})
</script>
</body>
结果如下:
四、过滤器
Vue.js 允许自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由管道符号 " | " 指示。
全局注册过滤器:
Vue.filter()
局部注册:
在Vue实例或组件中添加选项filters
例子:
使用过滤器处理时间戳和文本:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<!-- 引入momentjs -->
<script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
</head>
<body>
<div id="app">
<!-- 在插值语法中使用 -->
{
{time | fmtDate}}
<!-- 在v-bind中使用 -->
<div :title="msg | upper">鼠标悬浮查看</div>
</div>
<script>
// 全局注册过滤器 Vue.filter('过滤器名称',过滤器格式处理函数)
Vue.filter('fmtDate', function(val){
// 参数val就是需要过滤的值,即管道符前面的值
// 使用momentjs库将时间戳转换为年月日时分秒 (需要引入monentjs库)
return moment(val).format('YYYY-MM-DD HH:mm:ss')
})
new Vue({
// 局部注册过滤器
filters:{
upper(val){
// 转成大写
return val.toUpperCase()
}
},
el:"#app",
data:{
time: new Date().getTime(),
msg: 'hello'
}
})
</script>
</body>
</html>
结果如下: