赞
踩
onX
onMounted(()=>{
console.log('123');
})
setup没有create和beforeCreated这两个声明周期,因为这两个做的事情可以在setup中做,而其他生命周期就是onX的i形式出现。
我们知道vue2的痛点就是逻辑都写一起了,只要业务一复杂,代码量大。vue3的好处就是能将功能拆分出来,形成每个文件,这样就将代码逻辑抽离出来,一个功能一块代码。
比如我们现在做一个计数器,那么我们可以
import {ref, Ref} from 'vue'
export const useConter = () => {
const state = ref<number>(123)
const add = () => {
state.value++
}
return {state, add}
}
创建一个文件,写一个hooks
然后
setup(props, context) {
const { state, add } = useConter()
return { state, add };
},
回到app.vue中在setup中使用。
这样我们的计数器这块的功能代码就已经被抽离出去了。
改变title
export const useTitle = (title: string) => {
const titleRef = ref<string>(title)
watch(titleRef, (n: string) => {
document.title = n
})
return { titleRef }
}
可以看到,我们需要依赖watch的值监听n的改变才会改变document.title,这也是与react不同的一点,react只要值改变了就会重新刷新组件,所以会自动更新其依赖的值,而vue不会,如果你将document.title = titleRef.value,当其值改变的时候,document.title并不会刷新,所以需要依赖watch来手动改变它的值。
比如
export const useTitle = (title: string) => {
const titleRef = ref<string>(title)
document.title = titleRef.value
return { titleRef }
}
这样写,当titleRef改变的时候,其不会运行。响应式只会去修改template上的内容,不会重新刷新该hooks。这也是与react相差很大的一点。
vue3还有一个大胆的实验性语法
<script lang="ts" setup>
import { ref } from 'vue'
import AA from './component/aa.component.vue'
const test = ref('test')
</script>
在script上面加上setup,那么就不用返回了,这个定义的变量或者引入的组件可以直接在template使用,而
props和emit则是这样使用
<script lang="ts" setup>
import { ref, defineEmits, defineProps } from 'vue'
import AA from './component/aa.component.vue'
const test = ref('test')
const props = defineProps({
test: String
})
const emit = defineEmits(['in', 'on'])
emit('in', '传过去的值')
</script>
通过defineProps还有defineEmits来使用props和emit。不过这个还是实验性语法,不知道会不会正式被更新。
vue需要使用模板来创建Html,但是在某种特殊情况上需要使用js来,那么就需要渲染函数,它比模板更接近编译器。
template会被渲染函数生成对应的vnode,如果想用js的编程能力,可以自己来编写createVnode函数,生成对应的vNode。
h函数就是用来创建vnode的,准备的命名应该是CreateVnode函数,但是为了简便就称为h函数。
import {defineComponent, h} from 'vue'
export default defineComponent({
render(){
return h('h2', {class: 'aa'}, '123123')
}
})
渲染出来就是
<h2 class="aa" data-v-55c42084="">123123</h2>
setup代替render
export default defineComponent({
setup() {
return () => {
return h("h2", { class: "aa" }, "123123");
};
},
});
只要返回的时候返回一个函数,该函数返回一个vnode即可代替render。
import CC from "./cc.component.vue";
export default defineComponent({
setup() {
return () => {
return h(
CC,
{},
{
default: (props) => h("span", null, `插槽${props.name}呀`),
}
);
};
},
});
将default这个插槽传进去cc
import { h, defineComponent } from "vue";
export default defineComponent({
setup(props, context) {
return () => {
return h("div", null, [
h("h2", null, "cc"),
context.slots.default
? context.slots.default({ name: "我是cc传出去的" })
: h("span", {}, "默认插槽"),
]);
};
},
});
cc里通过context.slots.default去拿到该函数并且调用返回vnode。
在vue中使用jsx,只需要在Babel中配置对应的插件即可。
npm install @vue/babel-plugin-jsx -D
在babel.config.js文件里面配置
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
'@vue/babel-plugin-jsx'
]
}
<script lang='tsx' > import { h, defineComponent, render, ref } from "vue"; export default defineComponent({ setup() { const state = ref<number>(0); return () => { return ( <div> <h2>{state.value}</h2> <button onClick={() => { state.value++; }} > + </button> </div> ); }; }, }); </script>
有template就没有render,有render就没template
好家伙,我看到了react的影子。就是组件的传递这些还是用slot这些。
<input type="text" v-focus>
这个v-focus就是自定义指令
export default defineComponent({ name: "AA", components: {}, props: { data: String, }, //自定义指令 directives: { focus: { mounted(el, bindings, vnode, preVnode){ console.log('ipt标签已挂载'); el.focus() console.log(el) console.log(bindings); console.log(vnode); console.log(preVnode); } } },
通过directives来定义自定义指令。
focus就是自定义指令,里面有几个生命周期,mounted就是v-focus对应的dom挂载的时候调用的。
el能拿到dom,然后调用.focus就可以获取焦点。
这是局部指令,只能在该组件使用。
bindings是一个对象,可以拿到v-focus.ccc=“123”中的123的值和ccc的修饰符
vnode是该虚拟节点对象
app.directive("focus", {
mounted(el) {
el.focus();
},
});
在main.ts中的app上挂载这方法,就可以在全局上使用。
created 在绑定元素挂在前调用
beforeMounted
mounted
beforeUpdate
updared
beforeUnmount
unmount
import { App, onMounted } from "vue"; const formater = (app: App<Element>, key: string) => { app.directive(key, { mounted(el,bindings) { const textContent = el.textContent; const foramtter = bindings.value || 'HH-MM-YY' console.log('textContent', textContent); console.log('bindings', bindings.value); }, }); }; export { formater }
在main.ts中使用即可
const app = createApp(App);
app
.use(store, key)
.use(router)
.use(i18n)
.use(ElementPlus)
.mount("#app");
app.config.globalProperties.$tt = t;
//注册指令
formater(app, 'formater')
<div v-formater="'hh-mm-cc'">12321321321</div>
我们知道,组件A在在组件B中使用的时候,那么a的template会被挂载到b的template的某个位置。
teleport的功能是将组件挂载到另一个app
类似于react的Portals
他有两个属性,
to:指定将其中的内容移动到目标元素,可以选择选择器
disabled:是否禁用teleport功能。
<teleport to="#lin">aaa</teleport>
这样aaa就会挂载在id为lin的组件上,与app同为兄弟节点,
我们刚才使用全局指令就是给全局添加一个功能,但其实vue也可以使用插件的模式。
有两种模式:
1 一个对象,但是必须包含install函数,会在安装插件时执行
2 函数类型, 这个函数会在安装插件时自动执行
const testPlugins = {
install(){}
}
export { testPlugins }
在main.ts中
app
.use(store, key)
.use(router)
.use(i18n)
.use(ElementPlus)
.use(testPlugins)
使用app.use()包裹起来,源码中会调用该对象的install方法并且执行。
就像 testPlugins.install(app)这样操作,将app传进去。
const testPlugins = {
install(app: App<Element>){
app.config.globalProperties.name = '123'
}
}
app.config就是其配置属性,在globalProperties上面增加属性相当于在全局增加属性,也就是说在其他组件可以通过this.name拿到123这个值。
因为setup是没有this的,所以只能通过
const instance = getCurrentInstance()
console.log(instance?.appContext.config.globalProperties.$name);
getCurrentInstance可以拿到当前的组件实例,而全局属性只能从appcontext全局上下文中拿到,这样就能拿到我们定义的属性。
const testPlugins = (app: App<Element>) => {
app.config.globalProperties.$name = "123";
};
通过函数,vue内部还是会调用testPlugins(app)调用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。