前言
大部分组件的使用,基本都是通过import
方式导入,这也是最常用的。但是有些时候也需要通过API方法的形式调用。比较常见的比如element ui
的Message 消息提示。这里主要介绍3.x版本的写法,2.x版本可以看我的另一篇文章,简单写了个例子以及自己的理解。
API方式加载组件
参考文章:
vue 3.0 封装一个message提示组件
极简系列—vue3.x消息组件message
全局API与vue2.x变化
变更前 | 变更后 |
---|---|
Vue.extend(组件选项) | Vue.createApp(组件选项) |
Vue.prototype | config.globalProperties,如const app = createApp({}) app.config.globalProperties.$http = () => {} |
写一个最简单的消息提示
消息组件:api.vue
<template>
<div class="message" v-show="showMessage">
<div class="content">{{ message }}</div>
</div>
</template>
<script>
import { defineComponent, onMounted, ref, watch } from "vue";
export default defineComponent({
props: {
messageType: {
type: String,
default: "",
},
title: {
type: String,
default: "",
},
},
setup(props) {
const showMessage = ref(false);
const message = ref("");
onMounted(() => {
message.value = props.title;
});
watch(message, (val) => {
showMessage.value = true;
setTimeout(() => {
showMessage.value = false;
}, 2000);
});
return {
showMessage,
message
};
},
});
</script>
<style scoped lang="scss">
.message {
min-width: 200px;
max-width: 300px;
min-height: 50px;
height: auto;
background: #ecf5ff;
border-radius: 10px;
line-height: 30px;
color: #409eff;
font-size: 18px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
top: -800px;
left: calc(50% - 100px);
}
</style>
出口文件:api.js
- 利用渲染函数h即createVNode,将message.vue组件编译成vnode
- 利用mount将vnode挂载到指定元素上
- 通过$el获取真实DOM
import { createApp, h } from "vue";
//导入消息组件
import MessageComponent from "./api.vue";
//处理数据
function handleData(messageType, title) {
//创建挂载容器
const div = document.createElement("div");
//创建实例
const app = createApp({
render() {
return h(MessageComponent, { messageType, title });
},
});
document.body.appendChild(app.mount(div).$el);
}
export default {
//普通提示
info(title) {
handleData("info", title);
},
};
使用
<script>
import Message from "./api.js";
import { defineComponent } from "vue";
export default defineComponent({
setup() {
const sendMessage = () => {
Message.info("哈哈哈")
};
return {
sendMessage,
};
},
});
</script>
效果图
问题(坑)
说一下遇到的一些问题,个人理解,如果有不对的地方,感谢指出。
问题1
//继承基础信息
let MessageConstructor = Vue.extend(Main);
//创建实例
let Instance = new MessageConstructor();
2.x的时候可以获取到组件实例,通过组件实例可以获取到组件的props、data、methods
return h(MessageComponent, { messageType, title });
3.x的时候,你只能通过传递参数的方式进行数据的修改。(h函数的第二个参数是组件的props属性,具体看官方文档)
问题2
//vue 3.0 封装一个message提示组件
<div id="app"></div>
<div id="message"></div>
app.mount('#message');
//极简系列---vue3.x消息组件message
const container = document.createElement("div");
document.body.appendChild(vm.mount(container).$el);
两个文章的挂载方式不同。第一种是直接在index.html
里直接写死一个div,然后挂载;第二种是动态生成div,然后挂载。虽然最终都是在body标签里多了一个div,但是推荐使用第二种。第一种消息提示出现后,多了一个滚动条;第二种消息提示出来后,未出现滚动条。两种方式具体有什么不同,个人太笨,不太清楚。
问题3
我自己写的实例
onMounted(() => {
message.value = props.title;
});
watch(message, (val) => {
showMessage.value = true;
setTimeout(() => {
showMessage.value = false;
}, 2000);
});
最初想法是直接监听props.title
但是没有监听函数没有进入。应该是渲染组件时属性直接赋值了,相当于组件最初就有初始值,属性值没有改变,没有走监听。所以只能再变通一下。
问题4,使用方式
第一种方式时导入js文件
import Message from "./api.js";
第二种方式,注册到全局
//main.js
//消息提示
import message from "../src/views/yc/test/api/api.js";
const app = createApp(App);
app.config.globalProperties.$message = message;
//使用
const { proxy } = getCurrentInstance();
const sendMessage = () => {
proxy.$myMessage.info("哈哈哈");
};