Vue实现移动端 message-box 与 alert 弹框@郝晨光

GIF.gif

前言

最近在做移动端的项目,需要制作移动端的alert弹框和message-box提示信息;之前使用Vue框架的element-ui时,就记得element-ui的弹框,今天深入的研究了一下源码,然后简单制作了一点小demo

用到的知识点

Vue组件的定义,Vue的extend

Vue.extend(options)

options参数是一个对象,一个Vue组件配置项的对象,例如

// 创建一个构造器,
const Profile = Vue.extend({
// 模板使用参数内的template模板
  template: `<div>{{message}}</div>`,
// data内的为默认数据
  data() {
      return {
          message: ''  
      }
  }
})
// 创建一个基于构造器的Vue实例,并且给data重新赋值
const Message = new Profile({
    data: {
        message: 'message'
    }
})
// 将这个实例挂载到 id 为 app 的DOM节点上
Message.$mount('#app');

正文

看完了基本原理,大部分同学应该就已经可以明白这个东西是怎么实现的了吧!,接着我带着大家来看看具体的实现步骤

首先需要先定义一个Vue的组件,这个组件不直接挂载到任何DOM节点中,而是作为一个模板,一个构造器来使用
<template>
	<transition name="fade">
            <!-- 使用fade淡入淡出动画,使用type变量来控制class类名,达到更改type值就可以修改样式的效果 -->
		<div :class="['plugins-message-box',type]" v-show="visible">
            <!-- 使用iconClass来控制icon的类名,我使用的是阿里的字体图标库iconfont,可以根据个人爱好来更换 -->
			<div :class="['message-icon','iconfont',iconClass]"></div>
            <!-- 输出消息 -->
			<div class="message-container">{{message}}</div>
		</div>
	</transition>
</template>

<script>
      // 定义每一个type对应的class类名
	const typeClass = {
		success: 'icon-success',
		error: 'icon-error',
		default: 'icon-success'
	};
	export default {
		name: "messageMain",
            // 定义的是默认数据,默认值
		data() {
			return {
				visible: false, // 控制DOM显示隐藏
				type: 'default', // 默认type值为default
				icon: '', // 默认使用icon为空,则使用type值对应的icon
				message: '', // 默认的message为空,由外部传入
				duration: 2000 // 默认显示时间为2000ms
			}
		},
		computed: {
                      // 如果外部传入icon则使用外部的icon,如果没有。则使用type值对应的icon
			iconClass() {
				if(this.icon) {
					return this.icon;
				}else {
					return typeClass[this.type];
				}
			}
		}
	}
</script>
可以看到这是一个非常简单的Vue组件模板,使用的是vue-cli工具构建的,最终它抛出了一个对象,而我们接着就应该来定义构造器
import Vue from 'vue'; // 引入Vue
import MessageMain from './messageMain'; // 引入上边定义好的message模板

const MessageBox = Vue.extend(MessageMain); // 使用Vue.extend来创建一个构造器
let instance; // instance 变量用来保存实例
let timer = null; // timer 变量用来保存定时器

// 定义一个function,参数为options,默认为一个对象
const Message = function(options = {}) {
    // 如果当前处在服务器端,则直接返回
	if(Vue.prototype.$isServer) return;
    // 如果当前定时器已开启,说明页面上已经有一个message-box了,则不能再继续创建新的message-box
	if(timer) return;
    // 对options做处理,如果直接传入string,则使其保存在options的message属性上
	if(typeof options === 'string') {
		options = {
			message: options
		}
	}
    // 初始化实例,并将options作为新的data传入,Vue会将options合并到原有的data上,覆盖原有的默认值,但是,在options中没有设置的是不会被改变的
	instance = new MessageBox({
		data: options
	});
    // 调用$mount方法,将当前实例渲染为真实DOM,生成$el,,如果不执行这一步,将拿不到 $el 的值,但是不指定DOM节点接管当前实例
	instance.vm = instance.$mount();
    // 使用原生js的API将当前实例的真实DOM追加到body中
	document.body.appendChild(instance.vm.$el);
    // 实例上的vm就是我们的Vue组件,所以我们可以通过vm访问到当前实例中的所有属性
    // 将visible设置为true,即显示当前message-box
	instance.vm.visible = true;
    // 开启定时器
	timer = setTimeout(() => {
       // 在时间结束后将当前实例手动卸载
		instance.vm.$destroy();
       // 使用原生API将当前实例生成的DOM节点在真实的DOM树中删除
		instance.vm.$el.parentNode.removeChild(instance.vm.$el);
       // 清除定时器
		timer = null;
	}, instance.vm.duration);
    // 定时器的时间使用vm中定义的时间
	return instance.vm;
};

// 最终抛出一个对象,对象上我们可以使用 install 来扩展Vue的插件
// 当我们的对象上有install方法的时候,它接收第一个参数为Vue,
// 我这里为了方便使用,还在当前抛出的对象上定义了一个message方法,为了方便在axios的拦截器中使用;
export default {
	message: Message,
	install(Vue) {
		Vue.prototype.$message = Message;
        Vue.message = Message;
	}
};
接着来看一下使用方法,首先要在main.js中将这个插件安装到Vue上
import Message from './plugins/Message';

Vue.use(Message); // 因为我们的对象上定义了install方法,所以可以直接调用Vue的use方法
安装完成之后,我们就可以在任意组件内使用了,这个是我们刚刚在文章开头看到的页面,现在只有调用message-box的方法;
我们直接使用this.$message就可以调用我们的message-box,并且显示都没有任何问题,当然,也可以通过传入icon和duration来修改图标和时间
<template>
	<div class="test">
		<div class="test-message">
			<button @click="messageClick('default')">
				default
			</button>
			<button @click="messageClick('success')">
				success
			</button>
			<button @click="messageClick('error')">
				error
			</button>
		</div>
	</div>
</template>

<script>
	export default {
		name: "test",
		methods: {
			messageClick(type) {
				this.$message({
					type,
					message: type
				})
			}
		}
	}
</script>

GIF.gif

看完了message-box,我想你对alert的做法也有了一定的想法了吧!接着我们来看一下alert的做法
在alert中,我们不需要定义type,也不需要修改样式,
对于alert来说,我们需要有一个头部,一个内容区,还有一个确认按钮,
而我们的内容区,使用的是v-html来渲染内容,便于我们可以使用原生的DOM标签来实现一些简单的样式
而我们在这个组件内,当点击确定按钮的时候,我们将卸载当前组件,并将当前组件从DOM结构删除
<template>
	<transition name="fade">
		<div class="plugins-alert-box" v-show="visible">
			<div class="plugins-alert-container">
				<div class="alert-box-title">
					{{title}}
				</div>
				<div class="alert-box-message" v-html="message">
				</div>
				<div class="alert-box-btn">
					<button @click="btnClick">确定</button>
				</div>
			</div>
		</div>
	</transition>
</template>

<script>
	export default {
		name: "alertMain",
		data() {
			return {
				visible: false,
				message: '',
				title: '提示'
			}
		},
		methods: {
          // 点击确定按钮的时候,首先隐藏当前元素,然后将当前元素从DOM结构中删除,并手动卸载当前实例
			btnClick() {
				this.visible = false;
				this.$el.parentNode.removeChild(this.$el);
				this.$destroy();
			}
		}
	}
</script>

接着我们再来看定义构造器的代码
import Vue from 'vue'; // 引入Vue
import alertMain from './alertMain'; // 引入定义好的alert的模板

const AlertBox = Vue.extend(alertMain); // 创建一个构造器
let instance; // instance 变量用来保存实例

// 定义 Alert函数,接收options参数,默认为一个对象
const Alert = function(options = {}) {
	if(Vue.prototype.$isServer) return; // 判断当前如果是在服务器端渲染的话,直接返回
    // 同样的,我们还要处理options
	if(typeof options === 'string') {
		options = {
			message: options
		}
	}
    // 创建一个alert-box实例 ,将options作为新的data传入
	instance = new AlertBox({
		data: options
	});
    // 调用$mount方法,创建真实DOM,获取到vm
	instance.vm = instance.$mount();
    // 调用原生API将当前实例的真实DOM追加到body中
	document.body.appendChild(instance.vm.$el);
    // 让当前DOM显示
	instance.vm.visible = true;
	return instance.vm;
};

// 抛出对象,以及install方法,原理我们在上边已经讲过了
export default {
	alert: Alert,
	install(vue) {
		vue.prototype.$alert = Alert;
	}
}

接着就是alert-box的使用方法了,同样是需要先use一下
import Alert from './plugins/Alert';

Vue.use(Alert);
最后来使用一下这个alert-box
<template>
	<div class="test">
		<div class="test-message">
			<button @click="alertClick">alert</button>
		</div>
	</div>
</template>

<script>
	export default {
		name: "test",
		methods: {
			alertClick() {
				this.$alert({
					message: `<b>加粗文字</b>`
				})
			}
		}
	}
</script>

GIF.gif

结言
我没有帖出css样式文件,因为样式文件其实没有多少东西,我觉得你写的会比我写的更优秀,更完美
看完这篇文章不知道你有没有什么收获,如果可以理解的话,希望你通过这篇文章写一个dialog组件,巩固一下知识,顺手点个关注
感谢您的查阅,代码冗余或者有错误的地方望不吝赐教;菜鸟一枚,请多关照
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js是一种流行的JavaScript框架,用于构建现代Web应用程序,如移动应用程序和单页应用程序。使用Vue.js开发移动应用程序时,经常需要使用各种UI组件。其中,el-table是一个常用的表格组件,可以方便地展示数据。 移动端的el-table组件需要考虑到手机屏幕的大小和触摸操作的交互设计。因此,我们需要手写实现一套适用于移动端的el-table组件。 首先,我们需要设计一个表格结构,包括表头、表体和表尾。在移动端,由于屏幕较小,通常需要使用滚动条来滚动表体。因此,我们需要给表格设置固定高度,并设置overflow: auto属性。 其次,我们需要实现表格的数据绑定和分页功能。通常情况下,移动端的数据量较小,因此我们可以一次性将所有数据加载到前端进行分页展示。我们可以使用分页器组件实现分页,并通过计算分页数据来动态更新表格数据。 最后,我们需要考虑到表格的交互设计。在移动端,我们通常使用左右滑动来进行某些操作。例如,我们可以使用左滑删除删除某一行数据,右滑编辑某一行数据。此外,我们还可以添加筛选功能和搜索功能,方便用户快速查找需要的数据。 总之,Vue.js手写实现移动端el-table组件需要考虑到表格结构、数据绑定、分页功能和交互设计等方面。通过仔细设计和实现,我们可以创建出易用性、高效性和美观性的el-table组件,满足用户需要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值