v-if 和 v-for
只要在原生的 JavaScript 中可以轻松完成的操作,Vue 的渲染函数就不会提供专有的替代方法。比如,在模板中使用的 v-if
和 v-for
:
<ul v-if="items.length">
<li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>
这些都可以在渲染函数中用 JavaScript 的 if
/else
和 map
来重写:
<script>
export default {
props:{
items:{
type:Array,
},
},
data(){
return {
}
},
render(h){
if(this.items.length){
return h('ul',this.items.map(ele =>{
return h('li',{
key:ele,
//尽管存在prop和事件,但是有时候我们仍可能需要在JS里直接访问一个子组件,那么此时,我们可以通过 ref 特性为子组件赋予一个ID引用:
ref:'li',
refInFor:true,
}, ele)
}))
}else{
return h('p','No items found')
}
}
}
</script>
v-model
渲染函数中没有与 v-model
的直接对应——你必须自己实现相应的逻辑:
管网中子组件的代码
props: ['value'],
render: function (createElement) {
var self = this
return createElement('input', {
domProps: {
value: self.value
},
on: {
input: function (event) {
self.$emit('input', event.target.value)
}
}
})
}
父组件实现v-model
<template>
<div id="app">
<mode :value = "value" v-model="value"></mode>
{{ value }}
</div>
</template>
<script>
const mode = ()=> import('./components/mode')
export default {
name: 'App',
components: {
mode
},
data(){
return{
value:''
}
}
}
</script>
事件&案件修饰符
对于 .passive
、.capture
和 .once
这些事件修饰符,Vue 提供了相应的前缀可以用于 on
:
修饰符 | 前缀 |
---|---|
.passive |
& |
.capture |
! |
.once |
~ |
.capture.once 或.once.capture |
~! |
例如:
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}
对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:
修饰符 | 处理函数中的等价操作 |
---|---|
.stop |
event.stopPropagation() |
.prevent |
event.preventDefault() |
.self |
if (event.target !== event.currentTarget) return |
按键:.enter , .13 |
if (event.keyCode !== 13) return (对于别的按键修饰符来说,可将 13 改为另一个按键码) |
修饰键:.ctrl , .alt , .shift , .meta |
if (!event.ctrlKey) return (将 ctrlKey 分别修改为 altKey 、shiftKey 或者 metaKey ) |
这里是一个使用所有修饰符的例子:
on: {
keyup: function (event) {
// 如果触发事件的元素不是事件绑定的元素
// 则返回
if (event.target !== event.currentTarget) return
// 如果按下去的不是 enter 键或者
// 没有同时按下 shift 键
// 则返回
if (!event.shiftKey || event.keyCode !== 13) return
// 阻止 事件冒泡
event.stopPropagation()
// 阻止该元素默认的 keyup 事件
event.preventDefault()
// ...
}
}
自定义指令
注意此处生成的是HTML代码是让html元素使用vue的自定义指令并不是如何实现指定所需要的效果
案例:
<script>
// 效果
// <template>
// <div>
// <input type="text" v-slice:5.number="content">
// {{ content }}
// </div>
// </template>
export default {
data(){
return {
content:"12456",
}
},
directives:{
// 自定义指令 v-slice:5.number
// 实现输入框中只能输入数字且长度有自定义指令的参数定义
'slice':{
bind (el, binding, vnode) {
const vm = vnode.context;
let { value, expression, arg, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g, '');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg);
el.oninput = function (e) {
let inputVal = el.value;
if(modifiers.number) {
inputVal = inputVal.replace(/[^0-9]/g, '');
}
el.value = inputVal.slice(0, arg);
vm[expression] = inputVal.slice(0, arg);
}
},
update (el, binding, vnode) {
const vm = vnode.context;
let { value, arg, expression, modifiers } = binding;
if(modifiers.number) {
value = value.replace(/[^0-9]/g, '');
}
el.value = value.slice(0, arg);
vm[expression] = value.slice(0, arg);
},
}
},
// 使用render函数生成最上面template代码中的效果
render(h){
return h('div',[
h('input',{
directives: [
{
name: 'slice', // v-slice
value: this.content, // v-slice="content"
expression: 'content', //字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
arg: 5, // v-slice:5="content"
modifiers: {
number: true // v-slice:5.number="content"
},
}
]
}),
this.content,
])
}
}
</script>
插槽
具名插槽
所使用的的api: vm.$slot.具名插槽的名字
vue官方给出解释
父组件代码
<script>
// html代码示例
// <template>
// <div>
// <slot>我是默认插槽</slot>
// <slot name="header">我是头部插槽header</slot>
// </div>
// </template>
export default {
render(h){
return h('div',[
h('base-slot',[
h('p',{
domProps:{
innerText:'我是默认插槽'
},
slot:'default' // 具名插槽的name
})
]),
h('i',{
domProps:{
innerText:'我是插槽header'
},
slot:'header'// 具名插槽的name
}),
])
}
}
</script>
v-slotd的render代码
<script>
// <template>
// <div>
// <slot></slot>
// <slot name="header"></slot>
// </div>
// </template>
export default {
data(){
return{
msg:'Im a slot'
}
},
render(h){
return h('div',[
this.msg,
this.$slots.header,
this.$slots.default
])
}
}
</script>
作用域插槽
获取子组件的数据,
需要使用: vm.$scopedSlots
vue官方的讲解:
父组件的代码
<script>
//最终的html代码
// <template>
// <div>
// <div-slot2>
// 子组件中template的代码
// <div>
// <strong> {{name}} </strong>
// </div>
// </div-slot2>
// </div>
// </template>
export default {
data(){
return{
obj:{
name:'张三',
age:'123',
}
}
},
render(h){
return h('div',[
this.$scopedSlots.default({
obj:this.obj,
})
])
}
}
</script>
子组件的代码//
<script>
import baseSlot2 from './base-slot2'
export default {
components:{
baseSlot2,
},
render(h){
return h('div',[
h('base-slot2',{
scopedSlots:{
default:function(props){
const {name,age} = props.obj
return h('strong',name)
}
}
})
])
}
}
</script>