业务背景
弹窗是页面交互中的重要组成部分,前端开发的同学应该经常与它打交道。小编的日常是做面向C端的H5活动页面,弹窗处理是每天都要面对的情况。根据日常工作中的场景,我总结了弹窗有以下特点:
不同的活动页面,弹窗样式基本不同;
不同的CSS开发者,弹窗的html结构不尽相同;
同一个活动页面中的弹窗样式基本相同,但弹窗文案、按钮文案、按钮交互都不尽相同;
第一点和第二点导致我们无法抽离出适用于所有页面的弹窗组件,只能根据每次的活动页进行定制化。
第三点是我们这篇文章重点分析的情况,最常规的做法就是每个弹窗拥有独立的html结构和添加对应的事件处理逻辑。
这样固然能解决问题,但是当页面逻辑复杂、弹窗特别多的情况下,你会发现html中存在大量的弹窗dom结构,不仅影响代码美观,也增加了html文件大小和渲染解析时间。最不能忍的是,每处理一种情况,都要去增加对应的弹窗,工作相当繁琐。
比如以下弹窗:
![c5288e6ed98ffd0fe9fa6ef639c13551.png](https://i-blog.csdnimg.cn/blog_migrate/529930370faf3c12bcff52c1266dfa81.png)
![5d9e11cd19525247bf0cb19a4ef370f3.png](https://i-blog.csdnimg.cn/blog_migrate/04648f816c73939a64cc36f754dd6607.png)
![9f9e2a49c4f9890b69755c3dc0e4c27a.png](https://i-blog.csdnimg.cn/blog_migrate/4b91dd94c2b821a1a61694eff480f9a0.png)
![af3a3f401008d25e7bef48250acc324c.png](https://i-blog.csdnimg.cn/blog_migrate/a9d7b75dad9f0fafe86408ddb14b7d3f.png)
这些还只是一类逻辑出现的弹窗,如果页面逻辑复杂,可能会出现几十个这种弹窗。上面的弹窗样式基本相同,不同的就是文案、按钮处理逻辑等,怎么抽离他们呢?
抽离方案
1. ES6 + Zepto 原生撸
let commonPop = {
init: function (param) {
let popHtml = `
class="m-popup-inner dn" id="commonPop">
class="popup-info">
class="title">${param.title}
class="c-des-info">${param.desc}
class="popup-btn">"javascript:;" class="c-btn-link dn leftBtn">${param.leftBtnTxt}"javascript:;" class="c-btn-link dn rightBtn">${param.rightBtnTxt}
`
$('body').append(popHtml);
if(param.leftBtnTxt) {
$('#commonPop .leftBtn').removeClass('dn'); // 避免按钮不存在的情况
$('#commonPop .leftBtn').on('click', function() {
param.leftCallback && param.leftCallback();
$('#commonPop').remove(); // 销毁弹窗
})
}
if(param.rightBtnTxt) {
$('#commonPop .rightBtn').removeClass('dn'); // 避免按钮不存在的情况
$('#commonPop .rightBtn').on('click', function() {
param.rightCallback && param.rightCallback();
$('#commonPop').remove(); // 销毁弹窗
})
}
$('#commonPop').removeClass('dn');
}
}
export default commonPop;
调用时只需要传对应参数就行,比如:
import commonPop from './commonPop';
// 第一个弹窗
let param = {
title: '开通成功',
desc: '已为你开通25天会员',
leftBtnTxt: '我知道了'
}
commonPop.init(param);
// 第二个弹窗
let param = {
title: '账号提示',
desc: '请您确认两方的账号绑定手机号一致后点击领取',
leftBtnTxt: '换绑手机号',
leftCallback: function(){
goChangePhone();
},
rightBtnTxt: '关闭'
}
commonPop.init(param);
// 第三个弹窗
let param = {
title: '注册提示',
desc: '完成注册即可激活权益',
leftBtnTxt: '取消',
rightBtnTxt: '前往注册'
rightCallback: function(){
goRegister();
}
}
commonPop.init(param);
// 第四个弹窗
let param = {
title: '实名认证提示',
desc: '你需要实名认证后才可激活权益',
leftBtnTxt: '取消',
rightBtnTxt: '前往认证'
rightCallback: goRealName.bind(this)
}
commonPop.init(param);
2. VUE版本
// commonPop.vue
<template>
<div v-if="show">
<div class="cover">div>
<div class="m-popup">
<div class="pop-info">
<div class="c-tit" v-html="title">div>
<div class="c-text">{{desc}}div>
div>
div>
<div class="pop-btn">
<a href="javascript:;" class="c-btn-link" v-if="leftBtnTxt" @click="leftCallback">{{leftBtnTxt}}a>
<a href="javascript:;" class="c-btn-link highlight" v-if="rightBtnTxt" @click="rightCallback">{{rightBtnTxt}}a>
div>
div>
div>
template>
// index.js
import vue from 'vue'
import popUpComponent from './commonPop.vue'
// 返回一个 扩展实例构造器
const PopUpConstructor = vue.extend(popUpComponent)
function showPopUp(popData) {
// 实例化一个 commonPop.vue
const popUpDom = new PopUpConstructor({
el: document.createElement('div'),
data() {
return {
title: popData.title,
descFirst: popData.descFirst,
leftBtnText: popData.leftBtnText,
rightBtnText: popData.rightBtnText,
show: true
}
},
methods: {
leftCallback: function(){
this.show = false;
popData.leftCallback && popData.leftCallback()
},
rightCallback: function(){
this.show = false;
popData.rightCallback && popData.rightCallback()
}
}
})
// 把 实例化的 popUp.vue 添加到 body 里
document.body.appendChild(popUpDom.$el)
return popUpDom;
}
// 注册为全局组件的函数
function registryPopUp() {
// 将组件注册到 vue 的 原型链里去,
// 这样就可以在所有 vue 的实例里面使用 this.$popUp()
vue.prototype.$popUp = showPopUp
}
export default registryPopUp
调用时只需要传对应参数就行,比如:
// 第一个弹窗
let param = {
title: '开通成功',
desc: '已为你开通25天会员',
leftBtnTxt: '我知道了'
}
this.$popUp(param);
// 第二个弹窗
let param = {
title: '账号提示',
desc: '请您确认两方的账号绑定手机号一致后点击领取',
leftBtnTxt: '换绑手机号',
leftCallback: function(){
goChangePhone();
},
rightBtnTxt: '关闭'
}
this.$popUp(param);
// 第三个弹窗
let param = {
title: '注册提示',
desc: '完成注册即可激活权益',
leftBtnTxt: '取消',
rightBtnTxt: '前往注册'
rightCallback: function(){
goRegister();
}
}
this.$popUp(param);
// 第四个弹窗
let param = {
title: '实名认证提示',
desc: '你需要实名认证后才可激活权益',
leftBtnTxt: '取消',
rightBtnTxt: '前往认证'
rightCallback: goRealName.bind(this)
}
this.$popUp(param);
总结
两种方案的原理基本一样,都是在触发弹窗展示后,动态的添加dom结构到html中,点击弹窗按钮执行逻辑后,删除对应的dom结构,这样就避免了html页面中出现过多弹窗dom造成的页面臃肿问题。
优化点无大小,只要能够提高页面性能、有利于维护代码、减少重复劳动力、提高工作效率,都可以在日常的工作中进行优化整理。
推荐阅读
定制武汉加油,中国加油
牛逼这个春节的红包封面新姿势!
发声B站up主实名举报千亿涉赌帝国“中福在线”
回忆20年前的BAT 、谷歌、微软网站居然长这样!
木兰木兰编程语言,当事人最新回复来了
实践终于知道怎么做微信动态红包
木兰国产自主研发编程语言火了,同行十二年,不知Python是木兰?
原创细恐至微,那些与闰年有关的bug
![3e60b5ecec9d2af07828b3b9575bf892.png](https://i-blog.csdnimg.cn/blog_migrate/86dbf286eb9aa2fb421364fe15a182cb.png)
![1235d37846fb6e9f4608e4e52f29d888.png](https://i-blog.csdnimg.cn/blog_migrate/052e2c18ea517bce414cc13cd33f6107.png)
.NET Core已经崛起
长按关注,刷新认知
dotNet全栈开发