弹窗示例 | 弹窗示例 |
---|---|
- 用命令行
npm init vue@latest
新建的项目,并运行起来 -
components文件夹下新建一个文件夹hl-alert,该文件夹下新增hl-alert.vue和index.js文件,目录结构如下图
2.1 hl-alet.vue文件中定义传入组件的属性和方法,内容如下:
<template>
<div class="base-alert" ref="hlAlert">
<div class="base-alert-bg"></div>
<div class="m-pop-content">
<img src="~@/assets/close.png" alt="" class="m-pop-close" v-if="isCloseIcon" @click="handleCancel"/>
<div class="m-pop-title" v-html="title" v-if="title"></div>
<div class="m-pop-detail">
<div v-html="message" v-if="message" class="m-pop-message"></div>
<div v-html="subMessage" v-if="subMessage" class="m-pop-submessage"></div>
</div>
<div class="g-row-flex-right g-btn-group">
<button :class="['u-base-pop-cancel', cancelBtnClass]" @click="handleCancel" v-if="!hideCancel">{{cancelBtnText}}</button>
<button class="u-base-pop-create" @click="handleOk">{{ensureBtnText}}</button>
</div>
</div>
</div>
</template>
<script>
import { defineComponent, onMounted, ref } from 'vue'
export default defineComponent({
name: 'HlAlert',
props: {
title: {
type: String,
default: '信息提示',
},
message: {
type: String,
default: '',
},
subMessage: {
type: String,
default: '',
},
cancelBtnClass: {
type: String,
default: '',
},
ensureBtnText: {
type: String,
default: '确定',
},
cancelBtnText: {
type: String,
default: '取消',
},
isCloseIcon: {
type: Boolean,
default: false,
},
callback: {
type: Function,
},
callbackCancel: {
type: Function,
},
hideCancel: {
type: Boolean,
default: false,
},
closeFromWindowClick: {
type: Boolean,
default: true
}
},
setup (props) {
const hlAlert = ref(null)
function removeModal () {
props.closeFromWindowClick && window.removeEventListener('click', removeModal)
let parent = (hlAlert.value && (hlAlert.value).parentNode) || null
if (hlAlert.value && document.body.contains(parent)) {
document.body.removeChild(parent)
}
}
function handleCancel () {
removeModal()
props.callbackCancel && props.callbackCancel()
}
function handleOk () {
removeModal()
props.callback && props.callback()
}
onMounted(() => {
setTimeout(() => {
props.closeFromWindowClick && window.addEventListener('click', removeModal)
}, 100)
})
return {
hlAlert,
handleOk,
handleCancel
}
}
})
</script>
<style lang="scss">
@mixin box-sizing($value) {
box-sizing: $value;
-webkit-box-sizing: $value;
-o-box-sizing: $value;
-moz-box-sizing: $value;
}
@mixin box($w, $h) {
height: $h;
width: $w;
padding: 0;
box-sizing: border-box;
@include box-sizing(border-box);
}
.base-alert {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
@include box(100%, 100%);
top: 0;
left: 0;
z-index: 2;
.g-row-flex-right {
display: flex;
align-items: center;
justify-content: flex-end;
}
.m-pop-close {
position: absolute;
right: 16px;
top: 16px;
cursor: pointer;
z-index: 2;
}
.m-pop-title {
font-size: 15px;
font-weight: 500;
color: #5A6371;
text-indent: 24px;
line-height: 40px;
padding-top: 10px;
}
.m-pop-content {
@include box(auto, auto);
min-width: 372px;
min-height: 156px;
background: #fff;
z-index: 1;
box-shadow: 3px 5px 21px 0px rgba(183, 183, 183, 0.29);
border: 1px solid #EBEBEB;
padding-bottom: 24px;
position: relative;
border-radius: 8px;
}
.base-alert-bg {
position: fixed;
@include box(100%, 100%);
top: 0;
left: 0;
}
.m-pop-detail {
padding-top: 32px;
}
.m-pop-message {
text-align: center;
font-size: 14px;
font-weight: bold;
color: #737478;
margin-bottom: 5px;
}
.m-pop-submessage {
font-size: 14px;
font-weight: 400;
color: #5A6371;
text-align: left;
padding-left: 40px;
max-width: 372px;
margin: auto;
}
.g-edit-list {
margin-bottom: 16px;
}
.g-btn-group {
margin-top: 30px;
padding-right: 16px;
}
.g-message-info {
font-size: 14px;
font-weight: 400;
text-align: center;
}
// 按钮样式
.u-base-pop-create,
.u-base-pop-cancel {
@include box(90px, 32px);
cursor: pointer;
border: none;
outline: none;
display: flex;
align-items: center;
justify-content: center;
color: #EFF7FF;
font-size: 14px;
font-weight: 500;
border-radius: 4px;
}
.u-base-pop-create {
background: #536FFF;
}
.u-base-pop-cancel {
background-color: #fff;
border: 1px solid;
color: #2F51FF;
border-color: #536FFF;
margin-right: 20px;
margin-bottom: 0;
}
}
</style>
2.2 vue2移除了vue.extend,我们使用createVNode和render来渲染弹窗
然后挂载到 config.globalProperties 上
index.js内容如下:
import {createVNode, render} from 'vue'
import HlAlert from './hl-alert.vue'
const myAlert = function(options) {
const container = document.createElement('div')
const vm = createVNode(
HlAlert,
options
)
render(vm, container)
document.body.appendChild(container)
}
const MyHlAlert = {
install(app) {
// 配置此应用
app.config.globalProperties.$hlAlert = myAlert
}
}
export default MyHlAlert
- main.js中引入弹窗组件
import { createApp } from 'vue'
import App from './App.vue'
import HlAlert from './components/hl-alert/index'
import './assets/main.css'
const app = createApp(App)
app.use(HlAlert)
app.mount('#app')
- 页面中使用
<script setup>
import {getCurrentInstance} from 'vue'
const {appContext} = getCurrentInstance()
const globalProxy = appContext.config.globalProperties
function alert () {
globalProxy.$hlAlert({
title: '审核未通过原因',
subMessage: '审核未通审核未通审核未通审核未通审核未通',
isCloseIcon: true,
cancelBtnClass: 'm-red', // 取消按钮的class
callback: () => {
console.log('确定按钮')
}
})
}
function alert2 () {
globalProxy.$hlAlert({
title: '信息提示',
subMessage: '只展示一个按钮',
isCloseIcon: true,
ensureBtnText: '确定', // 确认按钮的文字
cancelBtnText: '取消', // 取消按钮的文字
hideCancel: true // true 隐藏取消按钮
})
}
function alert3 () {
globalProxy.$hlAlert({
title: '信息提示',
subMessage: '确定按钮文字修改',
isCloseIcon: true,
ensureBtnText: '知道了', // 确认按钮的文字
cancelBtnText: '取消', // 取消按钮的文字
hideCancel: true // true 隐藏取消按钮
})
}
function alert4 () {
globalProxy.$hlAlert({
title: '信息提示',
subMessage: '<p style="text-align: left;color: red;">审核未通审核未通审核未通审核未通审核未通</p>',
isCloseIcon: true,
cancelBtnClass: 'm-red', // 取消按钮的class
callback: () => {
console.log('确定按钮')
}
})
}
</script>
<template>
<div>
<button @click="alert">click1</button>
<button @click="alert2">click2</button>
<button @click="alert3">click3</button>
<button @click="alert4">click4</button>
</div>
</template>
<style lang="scss">
.base-alert .m-red {
border: 1px solid #536FFF;
background: transparent;
color: #536FFF;
margin-right: 16px;
}
</style>
- 如果想把该组件发布到npm上,请参考文章 npm 发布自己写的vue3的组件