函数式组件
函数式组件:通过函数调用的方式添加组件。
传统调用组件方式的困扰:
<Child v-if='isShow' :msg='msg'/> <botton @click='btnClick' /> import Child from '@/components/Child' let isShow = ref(false); let msg = ref('111'); let btnClick = ()=>{ isShow.value = true; msg.value = 222;
...
isShow.value = false; }
1,这种非马上就要渲染的组件,需要大量代码去控制他,比如需要申明是否添加组件的变量,传递的属性变量==
2,其他地方也要这么写,让人头皮发麻
函数式调用组件:
let btnClick = ()=>{
createChildComponent("222");
}
//调用函数,就会自动添加组件,参数通过函数传递。
//调用方便,简单粗暴。
函数式组件的实现:toast举例
<!--Toast.vue 组件文件的创建是一样的--> <template> <div class="page"> <div class="toast">{{msg}}</div> </div> </template> <script setup> import { ref,defineProps } from 'vue'; let {msg} = defineProps({ msg:{ default:"请求成功!" } }); </script> <style lang='scss' scoped> .page{ position: fixed; width: 100vw; height: 100vh; .toast{ background-color: rgba(0,0,0,0.6); margin-bottom: 10px; border-radius: 5px; width: 160px; height: 30px; display: flex; align-items: center; justify-content: center; font-size: 20px; color:#eeeeee; } } </style>
<!--Toast.js 里面导出创建上面toast组件的函数--> import { createApp } from "vue"; import Toast from "@/components/Toast.vue"; //dom要挂载到的dom export default function createToastComponent(msg) { //createApp创建组件实例 let instance = createApp(Toast,{msg}); let mountNode = document.createElement('div'); document.body.appendChild(div); //将组件挂载相应的dom上 instance.mount(mountNode); setTimeout(()=>{ //卸载组件 instance.unmount(); //卸载组件后,把渲染的html一并清除 document.body.removeChild(mountNode); },1000); } <!--Parent.vue调用--> import createToastComponent from '@components/Toast.js' let btnClick()=>{ createToastComponent('222'); }
说明:
1,CreateApp(component,prop)返回一个组件实例,第一个参数是个组件,第二个参数是要传递的属性
比如文件main.js 就有下面两句
import App from './App.vue'
let app = createApp(App);
2,mount 将组件实例挂载到一个dom上,参数是一个dom元素(比如createElement,或queryElement的元素)或类选择器,
mount挂载到dom上,会导致dom里面的所有内容全部清空。这就是上面的例子中为什么新建一个dom来挂载mount的原因。
mount挂载dom必须已经渲染出来,main.js 中的app.mount('#app');
生成的index.html入口是下面这样的,通过defer加载js文件,保证下面的<div id='app'></div>先渲染出来
<!DOCTYPE html> <html lang=""> <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"> <link rel="icon" href="/favicon.ico"> <title>screen</title> <script defer src="/js/chunk-vendors.js"></script><script defer src="/js/app.js"></script></head> <body> <noscript> <strong>We're sorry but screen doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
3,unmount卸载组件函数
render+h实现:
import Toast from "@/components/mobile/Toast.vue";
export function createToast(msg,mountNode){
//必须加上key,否则这个函数第二次调用的时候没效果,因为已经有相同key的元素了。改变了key,相当于注销了之前的元素,然后进行重新绘制了。
let vnode = h(Toast,{msg,key:new Date()});
render(vnode,mountNode);
}
h函数,createVnode函数的缩写,创建虚拟dom,返回的是一个虚拟dom,并且不能通过这个虚拟dom获取组件的高级特征(比如组件difineExpose==)
h(元素/组件,prop参数/事件,child),详情可见官网。
render绘制函数
render(虚拟节点,父元素) //会绘制到父元素内的最后面(不会覆盖父元素的内容)
使用h+render做的函数式组件优缺点:
1,缺点:只能做简单的组件的绘制,而且组件已经转成了虚拟dom,然后将虚拟dom绘制出来,丧失了组件的大部分特征。
2,有点:不需要重新额外添加容器元素。