自定义指令部分
js代码
directives:{
move:direction_move
},
setup(props,{expose}){
let show = Vue.ref(false);
const bind_variable_a = Vue.ref('123')
const bind_variable_b = Vue.ref('123')
expose({test:'测试expose暴露的一个数据'})
console.log(Vue.resolveDirective(
'move'
) === direction_move);
return()=>[
Vue.h('p','使用Vue.h函数定义的VNode元素'),
Vue.h('p','如果setup函数所返回的值 是一个render 函数的情况下,那么它将覆盖template 元素中的模板标签,使用render渲染函数进行渲染'),
Vue.h('p','Vue.h是可以传递三个参数的:'),
Vue.h('ol',{},[
Vue.h('li','标签名称比如p、span、div'),
Vue.h('li','给予当前这个Element元素的attrs 或者子组件的props'),
Vue.h('li','子节点列表')
]),
Vue.h('p','除了第一个参数外,其余的参数都是可选的。'),
Vue.h('p','render 渲染函数中,v-if,bind、v-for这种Vue指令是不可以用的'),
Vue.h('p',['对于v-if 指示的演示:',show.value?Vue.h('span',{class:'green'},'可见'):Vue.h('span',{class:'red'},'不可见')]),
Vue.h('p',Vue.h('button',{
onClick(){
show.value=!show.value
}
},'点击切换')),
Vue.h('p','v-for 的演示:'),
Vue.h('ol',Array(3).fill(undefined).map((_,index)=>Vue.h('li',`测试商品${index + 1}`))),
Vue.h('p','v-if、v-for这是很简单的东西,包括directive 自定义指令,这些很普通,真正难点 v-model、插槽'),
Vue.h('p','v-model的特性:'),
Vue.h('p','v-model它绑定在input上,默认v-model:参数是value'),
Vue.h('p','v-model它绑定在子组件上,默认v-model:参数是modelValue'),
Vue.h('p',`上方input 绑定的值:${bind_variable_a.value}`),
Vue.h('p',Vue.h('label',['绑定值:',
Vue.h('input',{
type:'text',
value:bind_variable_a.value,
onInput(event){
bind_variable_a.value = event.target.value;
}
})]
)),
Vue.h('p','这是使用onChange 方法进行绑定的,它相当于v-model.lazy = 'xx''),
Vue.h('p',`下方input 绑定的值:${bind_variable_b.value}`),
Vue.h('p',Vue.h('label',['绑定值:',
Vue.h('input',{
type:'text',
value:bind_variable_b.value,
onChange(e){
bind_variable_b.value = e.target.value;
}
// 鼠标离开之后才触发,懒式加载
})]
),),
//onXXX是对v-on 的这个指令的处理方法
Vue.h('p','.stop 它相当于event.stopPropagation()'),
Vue.h('p','prevent相当于event.preventDefault()'),
Vue.h('p','self 相当于if(event.target !== event.currentTarget return'),
Vue.h('p','添加子组件,以测试slot,之前我们使用resolveComponent来反向解析子组件,但是在这个位置就不需要,直接把子组件放在这个位置上了'),
Vue.h(slotsComponent,{'test-attr':'测试属性1','test-attr-two':'测试属性2'},{
default(){
return Vue.h('p','默认插槽中设置---》测试默认的插槽位')
},
namespace_a(slot_props){
console.log(slot_props)
return Vue.h('li','命名插槽中设置---》命名插槽')
}
}),
//Vue.h 函数第三属性 是向当前VNode标签中添加innerHtml、子节点,在子组件当中使用,这个行为被理解为插槽
//我们在正常子组件当中使用 :<component>这是一个插槽<component>
// 在访问这个插槽的时候使用:<slot></slot> 是不是就相当于使用 <slot name='default'></slot>
//相当于在template 模板中创建<slot-component test-attr=‘测试属性’></slot-component>
Vue.h('p','文字大小不一,原因:'),
Vue.h('p','作为插槽,传递给子组件的任何VNode都是现在父元素当中渲染,然后再传递给子组件'),
Vue.h('p','作为插槽,它应该仅能够访问、输出父组件中的数据,不应该与子组件中的数据混在一起,而子组件中的插槽props 应该理解为子传父'),
Vue.h('p','在渲染函数中,使用子组件,并对其传递props、attr参数'),
Vue.h('p','插槽的props <slot attr="普通插槽传props"></slot>'),
Vue.h('p','Vue.resolveDirective用来解析当前子组件中定义的自定义指令'),
//
Vue.withDirectives(Vue.h('p','该p标签设置自定义指令move'),[
[Vue.resolveDirective('move'),'test','test-arg',{animate:true}],
]),
//<p v-move:test-arg.animate='test'>该p标签设置 自定义指令move</p>
//指令要是一个数组,而且指令是一个二维数组
//一维 数组,可以填写多个指令
//二维 数组,可以有4个元素
//1、指令对象
//2、值
//3、指令参数
//4、指令后缀
]
}
在上述js代码中有用到子组件,并且渲染函数还向子组件传递了props ……,那么子组件的代码如下:
<script>
import * as Vue from 'vue'
export default {
name: "slotsComponent",
props:['test-attr-two'],
setup(props,{attrs,slots }){
//经过 props 这个option的处理,attrs 将被转换为props变量,并且props的名称会被转换为更容易被js 所接受的 驼峰式
console.log(props.testAttrTwo);
console.log('props:',props);
console.log('attrs',attrs);
return()=>[
// Vue.h('p',attrs,'测试插槽slots!'),
// attrs 不用再用花括号 相当于{“test-attr”:’测试属性‘}
Vue.h('p',{'test-attr':attrs['test-attr']||'默认值'},'测试插槽slots!'),
// 使用插槽:
// 在template中使用<slot></slot>标签,在这个位置我们就不能直接使用这个标签了,应该使用slots对象。
slots.default(),
//如果具名插槽不存在的话,就会报错,之前template 使用<slot></slot>标签 name指向一个不存在的插槽,那么将忽略掉,或者仅在开发模式下提供一个警告,但是在渲染函数中,插槽不存在将会导致报错!
// 报错之后,整个Vue的渲染将出现问题,所以说,养成习惯 先判断存在不?存在再执行,不存在就取默认值==这里指"插槽吧尊在"
Vue.h('ul',slots.namespace_a?slots.namespace_a({'test-attr':'测试具名插槽传进来的参数'}):'插槽不存在!')
]
},
}
</script>
jsx->使用jsx语法返回的render渲染函数
setup(){
const test_string_a ='测试字符串';
const test_string_b =Vue.ref('测试响应变量');
const show_a = Vue.ref(false);
function toggle_show_a(){
show_a.value = !show_a.value
}
//不仅可以定义function 还可以定义jsx元素
const test_element = <p>没有任何的引号、括号,直接写元素!jsx语法,会自动创建为:Vue.h('p','...'){show_a.value?'可用':'不可用'}</p>
//所渲染出来的元素是固定的,不会再跟随响应的
const test_array = Array(5);
for(let index=0;index<test_array.length;index++){
test_array[index] = `测试元素${index + 1}`;
}
const test_array_reactive = Vue.reactive(test_array)
//测试双向绑定
const test_v_model_a = Vue.ref('input默认值')
const test_v_model_b = Vue.ref('input默认值b')
return()=>[
<div>
<p>使用jsx语法返回的render渲染函数!</p>
</div>,
<p>它返回的root元素有两个!</p>,
<div>
<p>在 return 函数的最外层,如果你返回多个元素,那么你需要返回一个数组,而且还要有逗号分隔!但是,如果你在非root元素位置添加元素,多个元素之间你也不需要再使用 数字组格式了,也就是不用逗号了</p>
<p>在 return 函数的最外层,如果你返回多个元素,那么你需要返回一个数组,而且还要有逗号分隔!但是,如果你在非root元素位置添加元素,多个元素之间你也不需要再使用 数字组格式了,也就是不用逗号了</p>
<p>先说最基本的渲染:如果我想把一个元素渲染到这个jsx render函数中,在template当中需要两个花括号包裹</p>
<p>渲染普通变量 test_string_a:{test_string_a}</p>
<p>渲染响应式对象 test_string_b:{test_string_b.value}</p>
<h3>渲染Attributes</h3>
<p>普通的attr 就直接写属性就可以了:</p>
<p><input type="text" value="普通的attrs的渲染"/></p>
<h3>动态attr 的绑定(v-bind):</h3>
<p><input type="text" value={test_string_b.value}/></p>
<p>渲染动态的attr 属性 注意后面没有“”双引号,也是使用一个花括号来进行渲染的。</p>
<p>花括号当中填写的就是js语句</p>
<p>先从最简单的v-if、v-for开始:</p>
<h3>v-if 条件判断</h3>
<p>在花括号中是js语句?那么就可以通过在花括号来进行 if else 语句或者Switch 语句、或者三目运算……</p>
<p>{show_a.value?<span class="green">元素可见</span>:<span class="red">元素不可见</span>}<button onClick={()=>show_a.value = !show_a.value}>点击切换</button></p>
<p><button onClick={toggle_show_a}>点击切换</button></p>
{test_element}
<p>虽然你可以直接定义 Element 但是这种使用括号直接渲染在render 函数之中的jsx语法,将被视作插槽语法(元素)。那么这个元素将不再属于当前子组件,那么它在style 标签 如果含有scoped 属性的时候它将不会起效</p>
<p>又有一个想法?setup 所返回的函数,它会在每次update之后,调用并与更新整个组件有关系</p>
<h3>v-for循环</h3>
<ul>
{test_array_reactive.map((value,index)=><li key="{index}">{value}</li>)}
</ul>
<h3>v-model双向数据绑定</h3>
<p>下方input标签绑定变量 test_v_model_a的值为:<span style="color:yellowGreen">{test_v_model_a.value}</span></p>
<p><label>测试绑定值:<input type="text" v-model={test_v_model_a.value}/></label></p>
<p>这时候就遇到一个问题,v-model后缀及参数问题,在jsx语法当中,不能直接v-model后面使用后缀及参数,应该使用一个数组</p>
<p>数组的第一个值为:绑定的变量、第二个值为:参数,第三个值:也是一个数组表示后缀</p>
<p>下方input标签,使用lazy 也就是使用onChange事件监听,绑定变量test_v_model_b值为:<span style="color:red">{test_v_model_b.value}</span></p>
<p><label>测试绑定值:<input type="text" v-model={[test_v_model_b.value,['lazy']]}/></label></p>
<h3>v-on事件</h3>
<p>其实已经对这个时间简单的研究过了,就是onClick、onChange这种写法,Vue的渲染函数写法,但是有一些后缀问题:</p>
<div onClick={Vue.withModifiers(()=>console.log('这是外框被单击事件'),['self'])}>
<p>这是一个带有外框的div元素,外框与button 均设置了onClick事件</p>
<button onClick={()=>console.log('这是按钮button 单击事件')}>点击触发onClick事件</button>
<p>不能直接在onClick当中添加后缀,添加后缀 使用Vue.withModifiers 该函数接受2个参数:参数1要调用的函数、参数2是一个数组,包含要添加的后缀</p>
<p>self这个后缀代表什么意思啊?if(event.target != event.currentTarget) return</p>
<a href="https://juejin.cn" onClick={Vue.withModifiers(()=>console.log('修改默认的行为'),['prevent'])}>这是一个链接,点击将出现一个输出</a>
<p>再测一个链接:<a href="https://juejin.cn" onClick={(event)=>{
event.preventDefault();
console.log('阻止浏览器a标签默认跳转行为');
}}>阻止浏览器默认行为</a></p>
<p onClick={()=>console.log('p标签点击事件')}>
<button onClick={()=>console.log('普通button按钮click单击事件,自动向上冒泡')}>普通的button按钮</button>
<button onClick={Vue.withModifiers(()=>console.log('使用stop后缀阻止事件冒泡'),['stop' +
''])}>使用stop 后缀来阻止向上冒泡的button按钮</button>
<button onClick={event => {
event.stopPropagation();
console.log('使用event.stopPropagation 阻止事件向上冒泡')
}}>使用event.stopPropagation 阻止事件向上冒泡的button按钮</button>
</p>
</div>
</div>
]
}
}