uniapp使用@uni-ku/root插件实现全局组件

最近做的uniapp项目中,发现uniapp的App.vue并没有template作为根目录,按照uniapp官网的说法,app.vue并不是页面,而是用来监听应用的生命周期、做一些全局样式和一些全局的变量(globalData),所以你在这里写template是没有用的。

那么问题来了,没有根目录那就没办法写全局组件了,在uniapp这种项目中,就得每个页面都去引入组件,那这样的话就会有重复的代码一直复制粘贴了。为了解决这个问题,我找到了两种办法,一种是使用插件在每个组件中都导入一遍对应的全局组件,一种是通过插件虚拟出根组件来,然后将全局会用到的组件放进来,使之成为一个真正的全局组件。

现在着重讲一下第二种办法,我们将会用到@uni-ku/root。(背景,本项目是由cli创建)

首先进行插件依赖的安装

bash 复制代码
npm install @uni-ku/root -D

然后,修改 vite.config.js 的配置

javascript 复制代码
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import AutoImport from 'unplugin-auto-import/vite'
import UniKuRoot from '@uni-ku/root'

// https://vitejs.dev/config/
export default defineConfig({
  ...
  plugins: [
    UniKuRoot(),  // 用来"虚拟"出一个根组件,让 uni-app 也能像 Vue 一样使用 App.vue,也就是能够用来做一些全局的组件挂载使用等操作
    uni(),
    AutoImport({
      imports: ['vue', 'pinia'],
    }),
  ],
  ....
})

然后在 src 下创建App.ku.vue,内容如下:

html 复制代码
<template>
  <KuRootView />
  <!-- 以下会组件被全局插入 -->
  <!-- Toast轻提示,需要引入@/components/toast/useToast.js然后再使用showToast打开 -->
  <Toast />
</template>
<script setup>
import Toast from '@/components/toast/index.vue'
</script>

<KuRootView /> 类似vuerouter的routerview标签,但是在uniapp中这个并不一样,比如vuerouter里面有各种生命周期等等。

toast.vue代码如下

html 复制代码
<template>
  <view v-if="visible" class="toast-mask" :class="{ 'can-penetrate': maskCanPenetrate }">
    <view class="toast-box" @tap.stop>
      <!-- 图标 -->
      <view v-if="iconType" class="toast-icon-box">
        <svg v-if="iconType === 'success'" class="success-icon toast-icon"><use href="#SelectCircleFilled"></use></svg>
        <svg v-else-if="iconType === 'fail'" class="fail-icon toast-icon"><use href="#CloseCircleFilled"></use></svg>
      </view>
      <!-- 文案 -->
      <text class="toast-title">{{ title }}</text>
    </view>
  </view>
</template>

<script setup>
import { useToast } from './useToast'

const { visible, title, iconType, maskCanPenetrate, showToast, hideToast } = useToast()

/* 导出给外部调用 */
defineExpose({ showToast, hideToast })
</script>

<style lang="scss" scoped>
.toast-mask {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  z-index: 9999;
  overflow: hidden;
  .can-penetrate {
    pointer-events: none;
  }
}
.toast-box {
  background-color: #fff;
  box-shadow: 0 8rpx 32rpx 0 rgba(0, 0, 0, 0.1);
  border-radius: 1998rpx 1998rpx 1998rpx 1998rpx;
  text-align: center;
  position: absolute;
  padding: 24rpx 48rpx;
  top: 112rpx;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;

  .toast-icon-box {
    display: flex;
    align-items: center;
    .toast-icon {
      margin-right: 16rpx;
      width: 32rpx;
      height: 32rpx;
      &.success-icon {
        color: $G6;
      }
      &.fail-icon {
        color: $R6;
      }
    }
  }
}

.toast-title {
  font-size: 32rpx;
  line-height: 32rpx;
  color: $T10;
}
</style>

useToast.js

javascript 复制代码
const visible = ref(false) // toast开关
const title = ref('') // 内容
const iconType = ref('fail') // icon: success / fail / ''
const toastDuration = ref(2000) // 默认延迟2000ms关闭
const maskCanPenetrate = ref(true) // 是否可以点击穿透(有宽高100%的蒙层存在),默认可以
let timer = null

export const useToast = () => {
  // 打开toast
  const showToast = ({ type = 'success', text = '', duration = 2000, canPenetrate = true } = {}) => {
    if (timer) clearTimeout(timer)
    visible.value = true
    iconType.value = type
    title.value = text
    toastDuration.value = duration
    maskCanPenetrate.value = canPenetrate

    if (toastDuration.value > 0) {
      timer = setTimeout(() => {
        hideToast()
      }, toastDuration.value)
    }
  }
  // 关闭toast
  const hideToast = () => {
    visible.value = false
    console.log('hideToast')
    if (timer) clearTimeout(timer)
    timer = null
  }
  return {
    visible,
    title,
    iconType,
    toastDuration,
    maskCanPenetrate,
    showToast,
    hideToast,
  }
}

onUnmounted(() => clearTimeout(timer))

现在toast就变成了全局的,我们只需要在需要使用到toast的页面引入useToast.js,然后操作里面的方法就可以打开了

html 复制代码
<template>
  <button @click="showToast">打开toast</button>
</template>
<script setup >
import { useToast } from '@/components/toast/useToast.js'

const { showToast } = useToast()


</script>
<style lang="scss" scoped>
// ....
</style>

这样就解决了在uniapp开发过程中一些全局组件的重复引入的问题了,代码也美观一些,更容易理解。

相关推荐
计算机毕设定制辅导-无忧学长2 小时前
基于uni-app的“民族风韵”特色购物小程序
uni-app
一个处女座的程序猿O(∩_∩)O2 小时前
UniApp 生命周期全解析:从应用到页面,再到组件的完美协奏曲
前端·uni-app
龙颜2 小时前
从0-1封装一个React组件
前端·react.js
空空kkk3 小时前
SpringMVC——异常
java·前端·javascript
DcTbnk3 小时前
脚本猫中的新建脚本:定时脚本、后台脚本、普通脚本,三个区别
前端
冴羽3 小时前
涨见识了,Error.cause 让 JavaScript 错误调试更轻松
前端·javascript·node.js
一千柯橘3 小时前
Electron 第一步
前端·electron
code_Bo3 小时前
Ant Design Vue 日期选择器英文不变更中文问题
前端·vue.js·ant design
啃火龙果的兔子3 小时前
react-i18next+i18next-icu使用详解
前端·javascript·react.js