小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
TIP 👉 长江后浪推前浪,一代新人换旧人。《增广昔时贤文》
前言
在我们日常项目开发中,我们可能会会涉及到移动端底部弹出窗口功能,所以封装了这款底部弹出窗口组件。一、底部弹出窗口组件(只移动端可用)
此组件建议使用js方式调用
popupBottomBox 方法参数
1. title
- 窗口标题
- 值为字符串
2. content
- 内容组件
- 值为Vue对象,必填
3. contentProps
- 弹窗内容组件的props
- 值为Object类型,属性名为组件的props的属性
4. contentEvents
- 弹窗内容组件的事件
- 值为Object类型,属性名为组件事件名,属性值为事件回调方法
5. contentWrapperStyle
- 内容包裹器样式
- 值为Object类型,属性名为驼峰格式的样式名,属性值为样式值字符串
6. className
- 弹框自定义样式名
- 值为字符串
7. showCancel
- 是否显示取消按钮
- 值为布尔类型
- 默认值为true
8. onConfirm
- 点击“确认”按钮的回调函数
- 函数参数:value 内容组件获取的值
- 执行后窗口自动关闭如果函数返回 false,则窗口不关闭
9. onCancel
- 点击“取消”按钮的回调函数
- 函数无参数
- 执行后窗口自动关闭如果函数返回 false,则窗口不关闭
二、底部窗口示例
<script>
import ScrollSelect from '@/components/m/scrollSelect'
import popupBottomBox from '@/components/m/bottomBox'
popupBottomBox({
title: '请选择',
content: ScrollSelect,
contentProps: {
value: '01',
options: [
{ value: '01', text: '第一项' },
{ value: '02', text: '第二项' },
{ value: '03', text: '第三项' },
{ value: '04', text: '第四项' },
{ value: '05', text: '第五项' }
]
},
onConfirm: (val) => {
console.log('确定的值为', val)
},
onCancel: () => {
console.log('取消')
}
})
</script>
实现popupBottomBox.vue
<!-- 底部窗口组件 -->
<template>
<div class="bottombox-wrap">
<transition name="mask">
<div class="popup-mask" v-show="visible" @click="handelCancel" @touchmove.prevent="" @mousewheel.prevent=""></div>
</transition>
<transition name="pop" :duration="300">
<div class="bottombox" v-show="visible" :class="className" @touchmove.prevent="" @mousewheel.prevent="">
<div v-if="showOptionBar" class="option-pane">
<div class="cancel" v-show="showCancel" @click="handelCancel">取消</div>
<div class="ok" @click="handelConfirm">确认</div>
<div class="title" v-show="title">{{title}}</div>
</div>
<div class="bottombox-pane">
<div class="content-wrap" :style="contentWrapperStyle">
<slot>
<component v-if="content" :is="content" v-bind="contentProps" v-on="contentEvents" @change="onChange" ref="bottomboxContent"></component>
</slot>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name: 'BottomBox',
props: {
// 是否显示窗口
value: {
type: Boolean,
default: false
},
// 标题
title: {
type: String,
default: ''
},
// 是否显示顶部操作按钮
showOptionBar: {
type: Boolean,
default: true
},
// 是否显示取消按钮
showCancel: {
type: Boolean,
default: true
},
// 弹窗内容组件
content: Object,
// 弹窗内容组件的props
contentProps: Object,
// 弹窗内容组件的事件
contentEvents: Object,
// 内容包裹器样式
contentWrapperStyle: Object,
/* 点击“取消”按钮时的回调函数 */
onCancel: {
type: Function,
default: () => true
},
/* 点击“确定”按钮时的回调函数 */
onConfirm: {
type: Function,
default: () => true
},
// 样式名
className: {
type: String,
default: ''
}
},
data () {
return {
// 是否显示
visible: this.value,
// 当前内容组件的值
currentContentValue: this.contentProps && this.contentProps.value
}
},
watch: {
value (val) {
this.visible = val
}
},
methods: {
// 内容组件change事件监听
onChange (val) {
this.currentContentValue = val
},
/**
* 关闭窗口
* @param delayTime 延时关闭时间(单位:毫秒)
*/
close (delayTime) {
if (delayTime && typeof delayTime === 'number' && delayTime > 0) {
setTimeout(() => {
this.visible = false
this.$emit('input', this.visible)
this.$emit('close')
}, delayTime)
} else {
this.visible = false
this.$emit('input', this.visible)
this.$emit('close')
}
},
// 点击“取消”时的处理方法
handelCancel () {
if (this.showCancel && (this.onCancel() !== false)) {
this.close()
}
},
// 点击“确定”时的处理方法
handelConfirm () {
let val = this.currentContentValue
// 如果内容组件没有初始值,并且未滚动选择值,则通过内容组件的getDefaultValue方法获取默认值
if (!this.contentProps.value && !this.currentContentValue && this.$refs.bottomboxContent.getDefaultValue) {
val = this.$refs.bottomboxContent.getDefaultValue()
}
if (this.onConfirm(val) !== false) {
this.close()
}
}
}
}
</script>
<style lang="scss" scoped>
.bottombox-wrap {
z-index: 999;
}
.popup-mask {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .5);
transition: all .3s ease;
z-index: 10000;
}
.bottombox {
position: fixed;
width: 100%;
// height: 300px;
bottom: 0;
left: 0;
background-color: #FFF;
// box-shadow: 0 0 10px rgba(0, 0, 0, .3);
transition: all .3s ease;
z-index: 10000;
.option-pane{
padding: 0 4em;
height: $app-title-bar-height;
line-height: $app-title-bar-height;
// border-bottom: solid 1px $base-border-color;
background-color: #f5f5f5;
font-size: 32px;
.cancel, .ok {
position: absolute;
top: 0;
@include base-font-color();
}
.cancel {
left: 1em;
}
.ok {
right: 1em;
}
.title {
text-align: center;
color: $light-font-color;
}
}
.bottombox-pane {
display: flex;
flex-direction: column;
height: 100%;
.title {
flex: none;
height: $app-title-bar-height;
line-height: $app-title-bar-height;
border-bottom: solid 1px #E5E5E5;
font-size: 32px;
text-align: center;
padding: 0 3em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #666;
}
.content-wrap {
position: relative;
}
}
}
.pop-enter-active, .pop-leave {
transform: translateY(0);
}
.pop-enter, .pop-leave-active {
transform: translateY(100%);
}
.mask-enter-active, .mask-leave {
opacity: 1;
}
.mask-enter, .mask-leave-active {
opacity: 0;
}
</style>
index.js
/**
* 底部窗口组件
*/
import Vue from 'vue'
import BottomBox from './BottomBox.vue'
// BottomBox构造函数
const BottomBoxConstructor = Vue.extend({
extends: BottomBox
})
function initInstance (instance, options) {
// 窗口标题
instance.title = options.title || ''
// 是否显示顶部操作按钮
instance.showOptionBar = typeof options.showOptionBar === 'boolean' ? options.showOptionBar : true
// 是否显示取消按钮
instance.showCancel = typeof options.showCancel === 'boolean' ? options.showCancel : true
// 窗口高度
// instance.height = typeof options.height === 'number' && options.height >= 100 && options.height <= 1200 ? options.height : 300
// 窗口内容组件
instance.content = typeof options === 'object' && options._isVue ? options : options.content
// 窗口内容组件参数
instance.contentProps = typeof options.contentProps === 'object' ? options.contentProps : {}
// 窗口内容组件事件
instance.contentEvents = typeof options.contentEvents === 'object' ? options.contentEvents : {}
// 内容包裹器样式
instance.contentWrapperStyle = options.contentWrapperStyle
// 自定义样式名
instance.className = options.className || ''
// “确定”回调函数
if (options.onConfirm && typeof options.onConfirm === 'function') {
instance.onConfirm = options.onConfirm
}
// “取消”回调函数
if (options.onCancel && typeof options.onCancel === 'function') {
instance.onCancel = options.onCancel
}
// 父节点
let parentElement = options.parentElement || document.body
// 关闭时移除
instance.$on('close', () => {
setTimeout(() => {
parentElement.removeChild(instance.$el)
instance.$destroy()
}, 2000)
})
// console.log('instance.$el=', instance.$el)
// 将节点添加到文档
parentElement.appendChild(instance.$el)
instance.visible = true
instance.closed = false
}
// 显示弹出窗口
export function popupBottomBox (options = {}) {
let instance = new BottomBoxConstructor({
el: document.createElement('div')
})
initInstance(instance, options)
return instance
}
export default popupBottomBox
「欢迎在评论区讨论」