首页 > 其他分享 >一文掌握Vue3函数式组件中的confirm实现技巧!

一文掌握Vue3函数式组件中的confirm实现技巧!

时间:2024-01-18 17:00:50浏览次数:35  
标签:vue const render confirm title Vue3 组件

在做后台项目时候,使用声明式组件比较多,就是写一个.vue文件,在里面写 templatescriptstyle哪里需要,就在哪里导入。

而对于前台项目而言,我们期望可以直接通过方法的形式调用,利用函数式组件,在封装时除了要写.vue,还要多一个手动渲染和卸载的步骤。我们可以通过 h 函数可以生成一个vnode,该vnode利用render函数渲染和卸载。

<template>
  <!-- 声明式组件 -->
  <el-row class="mb-4">
    <el-button type="primary"  @click="open">Primary</el-button>
    <el-button type="success">Success</el-button>
  </el-row>
</template>

<script lang="ts" setup>
// 函数式组件
import { ElMessage } from 'element-plus'
// 通常是在某个交互完成时触发
const open = () => {
  ElMessage('this is a message.')
}
</script>

1.1. h 函数

Vue中,提供了一个h()函数用于创建 vnodes。创建虚拟节点时会多种不同情况,比如传入标签名和属性,就会创建一个标签的虚拟节点,传入组件名和属性,就会创建一个组件的虚拟节点。

h()接收三个参数(要渲染的dom,attrs 对象,子元素)

h()有一个更准确的名称是 createVnode(),考虑到多次使用,一个简短的名字会更省力。

import { h } from 'vue'

// 使用 h 创建普通标签  
const vnode1 = h('div', { class: 'bar', innerHTML: 'hello' })
// vnode1 等同于 <div class="bar">hello</div>
  
// 使用 h 创建组件
const vnode2 =  h(myComponent, {
		//组件的属性
    title: '测试'
})
// vnode2 等同于 <myComponent title="测试"/>

1.2. render 函数

render()接收标签或者组件的 vnode,将其渲染成为真实 DOM,并挂载到一个指定的父节点上。

import { h, render } from 'vue'

render(vnode2, document.body)
render(null, document.body)     // 当第1个参数为null时,相当于从父节点上移除此组件。

1.3. confirm组件

以实现 comfirm 组件为例,具体实现逻辑如下:

  1. 创建一个 confirm 组件
  2. 创建一个 comfirm.js 模块,该模块返回一个 promise
  3. 同时利用 h()生成 confirm.vuevode
  4. 最后利用 render函数,渲染 vnodebody

1.3.1. 构建 confirm.vue 组件

<script setup>
  import { ref, onMounted } from 'vue'
  // 因为将来 confirm 组件是以方法调用的形式展示,所以我们需要手动导入需要使用到的其他通用组件
  import mButton from '@/libs/button/index.vue'

  const props = defineProps({
    // 标题
    title: {
      type: String
    },
    // 描述
    content: {
      type: String,
      required: true
    },
    // 取消按钮文本
    cancelText: {
      type: String,
      default: '取消'
    },
    // 确定按钮文本
    confirmText: {
      type: String,
      default: '确定'
    },
    // 取消按钮事件
    cancelHandler: {
      type: Function
    },
    // 确定按钮事件
    confirmHandler: {
      type: Function
    },
    // 关闭 confirm 的回调
    close: {
      type: Function
    }
  })

  // 控制显示处理
  const isVisible = ref(false)
  /**
   * confirm 展示
   */
  const show = () => {
    isVisible.value = true
  }

  /**
   * 处理动画 (render 函数的渲染,会直接进行)
   */
  onMounted(() => {
    show()
  })

  /**
   * 取消事件
   */
  const onCancelClick = () => {
    if (props.cancelHandler) {
      props.cancelHandler()
    }
    close()
  }

  /**
   * 确定事件
   */
  const onConfirmClick = () => {
    if (props.confirmHandler) {
      props.confirmHandler()
    }
    close()
  }

  // 关闭动画处理时间
  const duration = '0.5s'
  /**
   * 关闭事件,保留动画执行时长
   */
  const close = () => {
    isVisible.value = false
    // 延迟一段时间进行关闭
    setTimeout(() => {
      if (props.close) {
        props.close()
      }
    }, parseInt(duration.replace('0.', '').replace('s', '')) * 100)
  }
</script>


<template>
  <!-- 基于 tailwindcss 创建对应样式 -->
  <div>
    <!-- 蒙版 -->
    <transition name="fade">
      <div
        v-if="isVisible"
        @click="close"
        class="w-screen h-screen bg-zinc-900/80 z-40 fixed left-0 top-0"
        ></div>
    </transition>

    <!-- 内容 -->
    <transition name="up">
      <div
        v-if="isVisible"
        class="w-[80%] fixed top-1/3 left-[50%] translate-x-[-50%] z-50 px-2 py-1.5 rounded-sm border dark:border-zinc-600 cursor-pointer bg-white dark:bg-zinc-800 xl:w-[35%]"
        @click="close"
        >
        <!-- 标题 -->
        <div class="text-lg font-bold text-zinc-800 dark:text-zinc-200 mb-2">{{ title }}</div>
        <!-- 文本 -->
        <div class="text-base tex-zinc-800 dark:text-zinc-200 mb-2">{{ content }}</div>
        <!-- 按钮 -->
        <div class="flex justify-end">
          <m-button type="info" class="mr-2" @click="onCancelClick">{{ cancelText }}</m-button>
          <m-button type="primary" @click="onConfirmClick">{{ confirmText }}</m-button>
        </div>
      </div>
    </transition>
  </div>
</template>

<style lang="scss" scoped>
  .fade-enter-active,
  .fade-leave-active {
    transition: all v-bind(duration);
  }

  .fade-enter-from,
  .fade-leave-to {
    opacity: 0;
  }

  .up-enter-active,
  .up-leave-active {
    transition: all v-bind(duration);
  }

  .up-enter-from,
  .up-leave-to {
    opacity: 0;
    transform: translate3d(-50%, -100%, 0);
  }
</style>

1.3.2. 创建 confirm.js 模块

import { h, render } from 'vue'
import confirmComponent from './confirm.vue'

/**
 * @param {*} title 标题
 * @param {*} content 内容
 * @param {*} cancelText 取消文本
 * @param {*} confirmText 确认文本
 */
export const confirmBox = (title, content, cancelText, confirmText) => {
  return new Promise((resolve, reject) => {
    // 不传入标题,只传入内容时
    if (title && !content) {
      content = title
      title = ''
    }

    // 取消按钮事件
    const cancelHandler = () => {
      reject(new Error('取消按钮点击'))
    }

    // 确定按钮事件
    const confirmHandler = () => {
      resolve()
    }

    // 关闭弹层事件
    const close = () => {
      render(null, document.body)
    }
    
    // 1. 生成 vnode
    const vnode = h(confirmComponent, {
      title,
      content,
      cancelText,
      confirmText,
      cancelHandler,
      confirmHandler,
      close
    })

    // 2. render 渲染
    render(vnode, document.body)
  })
}

1.3.3. 触发 comfirm 组件

import  { confirmBox } from './confirm.js'

const onDeleteAllClick = () => {
  confirmBox('要删除所有历史记录吗?').then(() => {
    // 点击确定后执行事件
    ...
  })
  .catch(()=>{
    // 点击取消后执行事件
    ...
  })
}

学子资料:点此下载


标签:vue,const,render,confirm,title,Vue3,组件
From: https://blog.51cto.com/u_15723831/9317053

相关文章

  • vue+antd-vue(自定义iconfont图标组件)
    1.方式一代码如下import{createFromIconfontCN}from'@ant-design/icons-vue';constIconFont=createFromIconfontCN({scriptUrl:newURL('./assets/font/iconfont.js',import.meta.url).href});app.component('IconFont',IconFont);......
  • 异步加载树形组件(antd-vue)
    1、html<a-directory-tree:tree-data="useDataSourceTreeList"v-model:selectedKeys="selectedKey"v-if="datasourceId"blockNodeclass="tree-card":showIco......
  • 使用JSZip库解压后台返回的Blob格式文件,并回显到element-ui的el-upload组件
    有一个报告列表,点击编辑的时候需要回显新建时上传的附件。后台提供了一个下载接口,但是会将所有上传的文件打包为一个压缩的blob。类似这种:leturlArr=[];urlArr=urlArr.concat(this.downLoadUrl.split(";"));this.$http.downLoadFile({url:urlArr.......
  • Vue3.0 路由动画(页面跳转)
    前言vue3.0的页面组件之前切换的动画效果,在移动端H5页面,交互体验比较好,就是带Vue3的Transition组件 之前的写法是 Transition的组件要包在routerView外面,但是3.0的语法就是要在在里面了,不然会黄色警告<divclass="animation"><RouterViewv-slot="{Component,......
  • 小程序 单选组件
    wxml<viewid='screen'><van-popupget-container="#screen"show="{{visible}}"closeableroundposition="bottom"bind:close="close_pop"custom-style="height:70%;width:100%;z-index:9999......
  • HBuilderX mac M1 打包 vite/vue3 报错处理办法(pnpm)
    项目运行h5的时候都没有问题,但是要运行到微信开发者工具的时候打包报11:40:54.480Specificallythe"esbuild-darwin-arm64"packageispresentbutthisplatform11:40:54.480needsthe"esbuild-darwin-64"packageinstead.Peopleoftengetintothis很好看去论......
  • 探索Web开发的未来——使用KendoReact服务器组件
    KendoUI是带有jQuery、Angular、React和Vue库的JavaScriptUI组件的最终集合,无论选择哪种JavaScript框架,都可以快速构建高性能响应式Web应用程序。通过可自定义的UI组件,KendoUI可以创建数据丰富的桌面、平板和移动Web应用程序。通过响应式的布局、强大的数据绑定、跨浏览器兼容......
  • vue3+lottie-web加载json格式动画
    项目中要用动画设计说gif会失真,用json格式动画吧。我虎躯一震,json格式动画什么鬼?lottie库什么鬼。。。。不废话,直接上重点环境:编辑器webstorm,前端技术栈vue3+vite+ts安装lottie-webyarnaddlottie-web引入lottie,引入json格式动画文件.importlottiefrom'lott......
  • echarts 常用的自定义组件
    一、自定义tooltip:多条曲线,series中name过长,鼠标悬浮时,文字过长,展示样式需自定义tooltip:{trigger:'axis',formatter:function(params){if(!params||params.length==0){return}varresult='<divstyle="padding-bottom:5px;">&#......
  • 你不知道的vue3:使用runWithContext实现在非 setup 期间使用inject
    前言日常开发时有些特殊的场景需要在非setup期间调用inject函数,比如app中使用provide注入的配置信息需要在发送http请求时带上传给后端。对此我们希望不在每个发起请求的地方去修改,而是在发起请求前的拦截进行统一处理,对此我们就需要在拦截请求的函数中使用inject拿到app注入的......