likes
comments
collection
share

vue3中用全局服务的形式调用一个组件

作者站长头像
站长
· 阅读数 49

在vue项目中,通常使用一个组件需要在template中以标准的标签形式来显示的使用,但是很多时候,我不希望写模板语法,而是希望通过纯js函数调用的形式来调用组件,那么又应该如何做呢?今天就参考element-plus来编写一个message组件,主要是记录一下这个过程。

使用过element ui 的人都知道它提供了很多全局方法来调用组件,比如一个提示组件message,其主要有两种用法:

  • 全局注册了组件后,在组件内部全局属性直接使用
// main.js

import message from './message.js'

app.use(message)


// 组件内部
this.$message.success('xxxx')
this.$message({
    type:'success',
    message:'成功2'
})
  • 通过导入服务的形式调用 ,可以用于选项式或者setup中通用
import message from './message.js'
message({
    type:'success',
    message:'成功'
})
message.success('成功')
message.success('失败')
  • 好废话不多说,我们先得有这么一个sfc组件,基本代码如下: message.vue
<template>
  <div class="message" :class="type ? 'message-' + type : ''">
    <span>{{ message }}</span>
    <span class="close" @click="close">x</span>
  </div>
</template>

<script setup>
import { defineProps, defineOptions, useAttrs } from "vue";
defineOptions({
  inheritAttrs: false,
});
const attrs = useAttrs();

const props = defineProps({
  message: {
    type: String,
  },
  type: {
    type: String,
  },
  duration: {
    type: Number,
    default: 3000,
  },
});
function close() {
  if(props.duration){
    attrs.close && attrs.close();
  }
}
</script>

<style scoped>
.message {
  padding: 8px 16px;
  border-radius: 4px;
  background-color: #ddd;
  display: flex;
  justify-content: space-between;
  color: #fff;
}

.close {
  cursor: pointer;
}

.message-success {
  background-color: #67c23a;
}
.message-error {
  background-color: #f56c6c;
}
</style>

要想通过app的use方法并且注册组组件,首先需要暴露一个函数,或者一个提供了install方法的对象,如下: message.js

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

function getInstance(config) {
  const div = document.createElement("div");
  const conf = Object.assign({}, config);
  if (conf.duration === undefined) {
    conf.duration = 3000;
  }

  const close = () => {
    try {
      document.body.removeChild(div);
    } catch (error) {}
  };
  conf.close = close;

  const vnode = createVNode(Message, conf);
  render(vnode, div);
  document.body.appendChild(div);

  if (conf.duration) {
    setTimeout(() => {
      try {
        document.body.removeChild(div);
      } catch (error) {
        
      }
    }, conf.duration);
  }

  return {
    close,
  };
}
const message = (opts) => {
  return getInstance(opts);
};

message.install = (app) => {
  // 这样就可以值选项式api中通过this.$message的形式调用了 返回一个包含close的对象,可以手动关闭,也支持自动关闭
  app.config.globalProperties.$message = message;
};

export default message;

为了丰富常用功能,需要给message提供两个快捷方法:

message.success = (msg) => {
  let conf = {
    type: "success",
    message: msg,
  };
  return getInstance(conf);
};
message.error = (msg) => {
  let conf = {
    type: "success",
    message: msg,
  };
  return getInstance(conf);
};

至此第一种方式通过this调用可以了,聪明的你也一定发现,其实可以不用全局注册,然后组合式api中直接导入message,然后就可以服务的形式来调用了。

最后,看了vue3的实现方式,是不是非常简单呢?你学废了吗?当然请想一下如果vue2又该如何实现呢? 欢迎点赞收藏吐槽指点。

转载自:https://juejin.cn/post/7244802984118190140
评论
请登录