Vue3登录注册模态框
源码:地址
前段时间写下的Vue.extend 登录注册模态框是基于 Vue 2.x 中 Vue.extend
版本来做
而这段时间内都是在学习 Vue 3.0 且也完全重构了该项目,记录学习下重构的过程与思考。
组件
组件还是那几个组件,需要改动的地方不是很多,只是把其改成 Vue 3 的形式sigin.vue
和 register.vue
组件分别修改
javascript
// sigin.vue
<template>
<div>
<button @click="onClick">登录确认</button>
</div>
</template>
<script>
export default {
name: "Sigin",
emits: ['sigin'],
setup(props, { emit }) {
const onClick = () => {
emit("sigin")
}
return {
onClick
}
}
};
</script>
// register.vue
<template>
<button @click="onClick">注册确认</button>
</template>
<script>
export default {
name: "Register",
emits: ['register'],
setup(props, { emit }) {
const onClick = () => {
emit("register")
}
return {
onClick
}
}
};
</script>
index.vue
组件
javascript
<template>
<div v-show="show">
<Sigin v-if="type === 'sigin'" @sigin="loginCallback" />
<Register v-if="type === 'register'" @register="loginCallback" />
</div>
</template>
<script>
import Sigin from "./sigin.vue";
import Register from "./register.vue";
import { ref } from 'vue';
export default {
components: {
Register,
Sigin
},
props: {
visible: Boolean,
type: String,
close: [Function, Boolean]
},
emits: ['destroy'],
setup(props, { emit }) {
const show = ref(props.visible);
const doClose = () => {
show.value = false;
emit('destroy');
}
const loginCallback = () => {
if (!props.close) return;
props.close().then(valid => {
if (valid) {
doClose();
}
});
}
return {
show,
doClose,
loginCallback
}
}
};
</script>
子类
由于 Vue.extend
被废弃,Vue 3
这里使用 h
和 render
两个函数,我们来看下这两个函数介绍,具体使用情况,可以查看文档
h
函数参数:type
它的类型可以是HTML 标签名、组件或异步组件props
是一个对象,与我们模板组件内的attribute
、prop
、事件相对应
render
渲染函数接收一个组件和容器
修改 index.js
javascript
import { render, h } from "vue";
import ModalCops from "./index.vue";
let instance;
const ModalBox = ({type, ok}) => {
if (instance) {
instance.component.proxy.doClose();
}
// 组件接收的 props
let _opt = {
visible: true,
type,
close: () => {
return new Promise(resolve => {
const before = ok ? ok() : false;
if (before && before.then) {
before.then(
() => resolve(true),
() => {
console.log("reject");
}
);
} else if (typeof before === "boolean" && before !== false) {
resolve(true);
}
});
}
};
instance = h(ModalCops, _opt); // 组件
const container = document.createElement('div');
// 组件销毁时
instance.props.onDestroy = () => {
render(null, container);
}
// 渲染组件
render(instance, container);
// 将模态框添加至 body
document.body.appendChild(container.firstElementChild);
};
ModalBox.sigin = ok => {
return ModalBox({
type: "sigin",
ok
});
};
ModalBox.register = ok => {
return ModalBox({
type: "register",
ok
});
};
ModalBox.close = () => {
instance.component.proxy.doClose();
instance.component.proxy.show = false;
};
export default {
install(app) {
app.config.globalProperties.$loginer = ModalBox;
}
};
最后在全局挂载
javascript
import { createApp } from 'vue'
import Login from './Login.vue'
import LoginModal from "./LoginModal/index.js";
createApp(Login).use(LoginModal).mount('#app')
Login.vue
组件中使用
javascript
import { ref, getCurrentInstance } from "vue";
export default {
setup(props) {
const { proxy } = getCurrentInstance();
const isOk = ref(true);
const onLogin = (type) => {
const funcs = {
sigin: () => {
console.log("登录请求");
},
register: () => {
console.log("注册请求");
},
};
proxy.$loginer({
type,
ok: () => {
return new Promise((resolve, reject) => {
if (isOk.value) {
funcs[type]();
resolve();
} else {
reject();
}
});
},
});
};
return {
isOk,
onLogin,
};
},
};
最后还是放一下效果
注意
在修改其中的部分代码时,我们需要注意的几个点
- 全局挂载
Vue 3
还是提供 use
函数,来使用我们的插件,不过需要挂载的属性变了,不再是直接挂载在 Vue.prototype
上,而是需要添加到全局实例的 config.globalProperties
对象上
javascript
install(app) {
app.config.globalProperties.$loginer = ModalBox;
}
- 组件销毁时的
onDestroy
事件
这个事件对应了 index.vue
模板组件中 emit
出的 destroy
事件,这是由于 Vue
源码中 packages\runtime-core\src\componentEmits.ts
中emit
函数给我们事件自动加上了 on
前缀
总结
学了就要用。本次是在学习 Vue3
后就在项目中全面使用,其中也碰到不少需要规避的坑,也尝试着阅读部分源码,收获满满😁
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情