前端笔记之vue3 之 render函数和createVNode函数使用

初学vue3的时候倒是扒了一点点源码,似是而非,而且一直做的工作都是很简单的功能,怎么说呢,ui框架也几乎让我很容易的就可以写出一个成型的页面,有时就忘了初学的时候的一些心得。
本内容只说createVNode函数的用法,不做源码探究

1.简单使用-创建一个组件

<template>
<RenderTest>RenderTest>
template>
<script setup>
import { defineComponent, createVNode } from "vue";

const RenderTest = defineComponent({
  render(){
  // 参数1:元素名字符串; 参数2:元素属性; 元素子节点,支持createVNode嵌套
    return createVNode("div", {class: "text"}, "render-text")
  }
});
</script>

效果图:
前端笔记之vue3 之 render函数和createVNode函数使用_第1张图片

2.简单使用-渲染组件

虽然在日常中这么写特别鸡肋,甚至有些傻逼,但是别急,慢慢来。
先写一个简单要引用的子组件

<template>
  <div>{{title}}div>
template>

<script setup lang="ts" name="SimpleTemplate">
import {defineProps} from "vue";
defineProps<{title: string}>();
script>

父组件

<template>
  <SimpleTemplateCopy />
template>

<script setup>
import { defineComponent, createVNode } from "vue";
import SimpleTemplate from "./SimpleTemplate/index.vue";

const SimpleTemplateCopy = defineComponent({
  render(){
    return createVNode(SimpleTemplate, {title: "twoB"})
  }
})
script>

3.日常使用-我用到它们的地方

element-plus说实话很不错,但是太常使用它有些审美疲劳,但是它的一些组件确实很好用,特别是那些提示弹窗之类,发现了吗,它们都是在函数去调用的,那么如何在纯js中去使用一个已经封装好了的组件呢?反正我是用它们。
简单的实现一下吧。
手写先写一个confirm的组件

<template>
<div class="small-window">
  <div class="upper-tip">
    <span>{{ title }}span>
  div>
  <div class="message-content">
    {{ message }}
  div>
  <div class="button-area">

    <div class="my-button" style="background-color: #11a9ea" @click="submitCallBack">{{ submitText }}div>
    <div class="my-button" style="background-color: #cecece" @click="cancelCallBack">{{ cancelText }}div>
  div>
div>
template>

<script setup lang="ts" name="Confirm">
import {defineProps} from "vue";
defineProps<{
  title: {type: string, default: "提示"},
  message: string,
  submitText: string,
  cancelText: string,
  cancelCallBack: () => void,
  submitCallBack: () => void,

}>()
script>

<style scoped lang="less">
.small-window{
  width: 500px;
  height: 350px;
  background-color: white;
  border: 1px solid rgba(169, 169, 169, 0.92);
  border-radius: 15px;
  display: flex;
  flex-direction: column;

  .upper-tip{
    font-size: 18px;
    height: 45px;
    width: 100%;
    font-weight: 700;
  }
  .message-content{
    width: calc(100% - 40px);
    padding: 15px 20px 15px 20px;
    height: 150px;
    text-indent: 32px;
    display: flex;
    justify-content: center;
    font-size: 16px;
  }
  .button-area{
    display: flex;
    justify-content: end;
    width: calc(100% - 40px);
    padding: 15px 20px 15px 20px;

    .my-button{
      width: 68px;
      margin-left: 20px;
      height: 50px;
      cursor: pointer;
    }
  }
}
style>

然后给这个组件找个挂载点以及render到dom上

import {createVNode, render} from "vue";
import Confirm from "./Confirm.vue";


export default ({title, message, submitText, cancelText}) => {

    const mask = document.createElement('div');
   	mask.setAttribute('style', 'position: fixed; background-color: rgba(0, 0, 0, 0.5); width: 100vw; height: 100%; display: flex; justify-content: center; align-items: center');
	mask.setAttribute('key', Date.now().toString());
    document.body.appendChild(mask);
    return new Promise((reslove, reject) => {

        // 封装组件属性方法
        const submitCallBack = () => {
            console.log(456)
            //调用完毕后应该清空节点
            render(null, mask)
            mask.remove();
            reslove(true)
        }

        // 封装组件属性方法
        const cancelCallBack= () => {
            console.log(456)
            //清空节点
            render(null, mask);
            mask.remove();
            reject()
        };

        // 在此处才创建节点并挂载属性
        const VNode = createVNode(Confirm, {
            title,
            message,
            submitText,
            cancelText,
            cancelCallBack,
            submitCallBack
        })
        render(VNode, mask);
    });
};

然后使用它

<template>

  <button @click="openMyConfirm">12313213button>
template>

<script setup>


import myConfirm from "./Confirm/index.js"


const openMyConfirm = () => {
  myConfirm({title: "提示", message: "你好呀", submitText: "你好", cancelText: "我不好"}).then(() => {
    console.log('点击确认事件处理')
  }).catch(e => {
    console.log('点击取消事件处理')
  })
}
script>

效果图:很丑,但是起码他是个成熟的confirm了
前端笔记之vue3 之 render函数和createVNode函数使用_第2张图片

4.生产中的正常使用

贴一个简单的tsx的代码,说实话tsx搭配createVNode简直舒服极了

import {createVNode, defineComponent, render} from "vue";
import styles from "./errordatacord.module.less";
interface A {
  unusualField: string,
  resultValue: string,
  healthRecordNo: string,
  name: string,
}
interface Prop extends A{
  cancelCallBack: () => void
}

const errorDataCord = defineComponent<Prop>({
  name: "ErrorDataCord",
  setup(props, {attrs}){
    return ()=> <>
      <div class={styles["error-data-cord"]}>
        <div class={styles["upper-sidebar"]}>
          <span>异常结果值</span>
          <div
            class={styles["close-icon"]}
            onClick = { attrs.cancelCallBack as () => void }
          >×</div>
        </div>
        <div class={styles["main-content"]}>
          <div>
            <span>异常字段:{attrs.unusualField}</span>
            <span>异常结果值:{attrs.resultValue}</span>
          </div>
          <div>
            <svg viewBox="0 0 1024 1024" version="1.1"
                 xmlns="http://www.w3.org/2000/svg" p-id="1486" width="48" height="48">
              <path
                d="M511.903244 0.000096a511.903244 511.903244 0 0 1 335.957502 898.350359l-9.598786 8.638907A511.999232 511.999232 0 1 1 511.903244 0.000096z m0 742.274102A281.436398 281.436398 0 0 0 272.605515 875.409357a433.289189 433.289189 0 0 0 225.283502 71.510954h14.014227a433.097213 433.097213 0 0 0 239.393717-71.510954 281.628374 281.628374 0 0 0-239.393717-133.135159z m0-665.483816a435.112958 435.112958 0 0 0-299.674091 750.625046 358.322672 358.322672 0 0 1 599.44417 0A435.112958 435.112958 0 0 0 511.903244 76.790382z m0 127.951814A204.838088 204.838088 0 1 1 307.161144 409.484296a204.7421 204.7421 0 0 1 204.7421-204.7421z m0 76.790286a128.047802 128.047802 0 0 0 0 255.999616 128.047802 128.047802 0 0 0 0-255.999616z"
                p-id="1487" fill="#cdcdcd"></path>
            </svg>
            <span>{attrs.name}</span>
            <span>{attrs.healthRecordNo}</span>
          </div>
        </div>
      </div>
    </>;
  }
});

export default (option: A, htmlElement: HTMLElement) => {
  return new Promise((resolve) => {
    const cancelCallBack = () => {
      render(null, htmlElement);
    };
    const VNode = createVNode(errorDataCord,  {
      ...option,
      cancelCallBack
    });
    render(VNode, htmlElement);
    resolve(true);
  });
};

你可能感兴趣的:(前端,javascript,vue.js,css)