Vue组件开发技巧总结


Posted in Javascript onMarch 04, 2018

前言

临近毕业,写了个简单个人博客,项目地址是点我访问项目地址(顺便求star),本篇是系列总结第一篇。接下来会一步一步模仿一个低配版的Element 的对话框和弹框组件。

正文

Vue 单文件组件开发

当使用vue-cli初始化一个项目的时候,会发现src/components文件夹下有一个HelloWorld.vue文件,这便是单文件组件的基本开发模式。

// 注册
Vue.component('my-component', {
 template: '<div>A custom component!</div>'
})

// 创建根实例
new Vue({
 el: '#example'
})

接下来,开始写一个dialog组件。

Dialog

目标对话框组件的基本样式如图:

Vue组件开发技巧总结

根据目标样式,可以总结出:

  1. dialog组件需要一个titleprops来标示弹窗标题
  2. dialog组件需要在按下确定按钮时发射出确定事件(即告诉父组件确定了)
  3. 同理,dialog组件需要发射出取消事件
  4. dialog组件需要提供一个插槽,便于自定义内容

那么,编码如下:

<template>
 <div class="ta-dialog__wrapper">
 <div class="ta-dialog">
  <div class="ta-dialog__header">
  <span>{{ title }}</span>
  <i class="ios-close-empty" @click="handleCancel()"></i>
  </div>
  <div class="ta-dialog__body">
  <slot></slot>
  </div>
  <div class="ta-dialog__footer">
  <button @click="handleCancel()">取消</button>
  <button @click="handleOk()">确定</button>
  </div>
 </div>
 </div>
</template>

<script>
export default {
 name: 'Dialog',

 props: {
 title: {
  type: String,
  default: '标题'
 },
 },

 methods: {
 handleCancel() {
  this.$emit('cancel')
 },

 handleOk() {
  this.$emit('ok')
 },
 },
}
</script>

这样便完成了dialog组件的开发,使用方法如下:

<ta-dialog 
 title="弹窗标题" 
 @ok="handleOk" 
 @cancel="handleCancel">
 <p>我是内容</p>
</ta-dialog>

这时候发现一个问题,通过使用v-if或者v-show来控制弹窗的展现时,没有动画!!!,看上去很生硬。教练,我想加动画,这时候就该transition组件上场了。使用transition组件结合css能做出很多效果不错的动画。接下来增强dialog组件动画,代码如下:

<template>
 <transition name="slide-down">
 <div class="ta-dialog__wrapper" v-if="isShow">
  // 省略
 </div>
 </transition>
</template>

<script>
export default {

 data() {
 return {
  isShow: true
 }
 },

 methods: {
 handleCancel() {
  this.isShow = false
  this.$emit('cancel')
 },

 handleOk() {
  this.isShow = true
  this.$emit('ok')
 },
 },
}
</script>

可以看到transition组件接收了一个nameprops,那么怎么编写css完成动画呢?很简单的方式,写出两个
关键class(css 的 className)样式即可:

.slide-down-enter-active {
 animation: dialog-enter ease .3s;
}

.slide-down-leave-active {
 animation: dialog-leave ease .5s;
}

@keyframes dialog-enter {
 from {
 opacity: 0;
 transform: translateY(-20px);
 }

 to {
 opacity: 1;
 transform: translateY(0);
 }
}

@keyframes dialog-leave {
 from {
 opacity: 1;
 transform: translateY(0);
 }

 to {
 opacity: 0;
 transform: translateY(-20px);
 }
}

就是这么简单就开发出了效果还不错的动效,注意transition组件的name为slide-down,而编写的动画的关键className为slide-down-enter-active和slide-down-leave-active。

封装Dialog做MessageBox

Element的MessageBox的使用方法如下:

this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
 confirmButtonText: '确定',
 cancelButtonText: '取消',
 type: 'warning'
}).then(() => {
 this.$message({
 type: 'success',
 message: '删除成功!'
 });
}).catch(() => {
 this.$message({
 type: 'info',
 message: '已取消删除'
 });   
});

看到这段代码,我的感觉就是好神奇好神奇好神奇(惊叹三连)。仔细看看,这个组件其实就是一个封装好的dialog,

Vue组件开发技巧总结

接下来,我也要封装一个这样的组件。首先,整理下思路:

  1. Element的使用方法是this.$confirm,这不就是挂到Vue的prototype上就行了
  2. Element的then是确定,catch是取消,promise就可以啦

整理好思路,我就开始编码了:

import Vue from 'vue'
import MessgaeBox from './src/index'

const Ctur = Vue.extend(MessgaeBox)
let instance = null

const callback = action => {
 if (action === 'confirm') {
 if (instance.showInput) {
  instance.resolve({ value: instance.inputValue, action })
 } else {
  instance.resolve(action)
 }
 } else {
 instance.reject(action)
 }

 instance = null
}

const showMessageBox = (tip, title, opts) => new Promise((resolve, reject) => {
 const propsData = { tip, title, ...opts }

 instance = new Ctur({ propsData }).$mount()
 instance.reject = reject
 instance.resolve = resolve
 instance.callback = callback

 document.body.appendChild(instance.$el)
})


const confirm = (tip, title, opts) => showMessageBox(tip, title, opts)

Vue.prototype.$confirm = confirm

至此,可能会疑惑怎么callback呢,其实我编写了一个封装好的dialog并将其命名为MessageBox,
它的代码中,有这样两个方法:

onCancel() {
 this.visible = false
 this.callback && (this.callback.call(this, 'cancel'))
},

onConfirm() {
 this.visible = false
 this.callback && (this.callback.call(this, 'confirm'))
},

没错,就是确定和取消时进行callback。我还想说一说Vue.extend,代码中引入了MessageBox,

我不是直接new MessageBox而是借助new Ctur,因为这样可以定义数据(不仅仅是props),例如:

instance = new Ctur({ propsData }).$mount()

这时候,页面上其实是还没有MessageBox的,我们需要执行:

document.body.appendChild(instance.$el)

如果你直接这样,你可能会发现MessageBox打开的时候没有动画,而关闭的时候有动画。解决方法也很简单,
appendChild的时候让其仍是不可见,然后使用类这样的代码:

Vue.nextTick(() => instance.visible = true)

这样就有动画了。

总结

  1. 通过transition和css实现不错的动画。其中,transition组件的name决定了编写css的两个关键类名为[name]-enter-active和[name]-leave-active
  2. 通过Vue.extend继承一个组件的构造函数(不知道怎么说合适,就先这样说),然后通过这个构造函数,便可以实现组件相关属性的自定义(使用场景:js调用组件)
  3. js调用组件时,为了维持组件的动画效果可以先document.body.appendChild 然后Vue.nextTick(() => instance.visible = true)

到此,简单的Vue组件开发就总结完了,我写的相关代码在地址,https://github.com/mvpzx/elapse/tree/master/be/src/components

Javascript 相关文章推荐
在Javascript中为String对象添加trim,ltrim,rtrim方法
Sep 22 Javascript
求解开jscript.encode代码的asp函数
Feb 28 Javascript
JS打开图片另存为对话框实现代码
Dec 26 Javascript
深入理解javascript中defer的作用
Dec 11 Javascript
点击显示指定元素隐藏其他同辈元素的方法
Feb 19 Javascript
阿里巴巴技术文章分享 Javascript继承机制的实现
Jan 14 Javascript
jQuery 弹出层插件(推荐)
May 24 Javascript
Bootstrap基本样式学习笔记之表格(2)
Dec 07 Javascript
详解vue项目中如何引入全局sass/less变量、function、mixin
Jun 02 Javascript
vuex页面刷新后数据丢失的方法
Jan 17 Javascript
layui数据表格实现重载数据表格功能(搜索功能)
Jul 27 Javascript
JavaScript HTML DOM 元素 (节点)新增,编辑,删除操作实例分析
Mar 02 Javascript
代码详解javascript模块加载器
Mar 04 #Javascript
Vue用v-for给src属性赋值的方法
Mar 03 #Javascript
vue中v-for加载本地静态图片方法
Mar 03 #Javascript
基于vue中解决v-for使用报红并出现警告的问题
Mar 03 #Javascript
基于Vuejs的搜索匹配功能实现方法
Mar 03 #Javascript
vue.js select下拉框绑定和取值方法
Mar 03 #Javascript
Vuejs在v-for中,利用index来对第一项添加class的方法
Mar 03 #Javascript
You might like
关于PHP递归算法和应用方法介绍
2013/04/15 PHP
php+mysql实现数据库随机重排实例
2014/10/17 PHP
使用symfony命令创建项目的方法
2016/03/17 PHP
PHP实现统计所有字符在字符串中出现次数的方法
2017/10/17 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
2017/12/25 PHP
Javascript 强制类型转换函数
2009/05/17 Javascript
jquery tablesorter.js 支持中文表格排序改进
2009/12/09 Javascript
早该知道的7个JavaScript技巧
2013/03/27 Javascript
js控制href内容的连接内容的变化示例
2014/04/30 Javascript
Jquery中Event对象属性小结
2015/02/27 Javascript
js+html5实现canvas绘制网页时钟的方法
2016/05/21 Javascript
jQuery3.0中的buildFragment私有函数详解
2016/08/16 Javascript
浅析JS中的 map, filter, some, every, forEach, for in, for of 用法总结
2017/03/29 Javascript
从零开始学习Node.js系列教程之设置HTTP头的方法示例
2017/04/13 Javascript
基于vue实现一个神奇的动态按钮效果
2019/05/15 Javascript
[00:34]拔城逐梦,热血永恒!2020(秋)完美世界城市挑战赛报名开启
2020/10/09 DOTA
python使用心得之获得github代码库列表
2014/06/25 Python
python中ConfigParse模块的用法
2014/09/29 Python
django model去掉unique_together报错的解决方案
2016/10/18 Python
Python实现树莓派WiFi断线自动重连的实例代码
2017/03/16 Python
Python 实现网页自动截图的示例讲解
2018/05/17 Python
Python操作mongodb的9个步骤
2018/06/04 Python
使用pandas对两个dataframe进行join的实例
2018/06/08 Python
深入浅析Python的类
2018/06/22 Python
Python装饰器语法糖
2019/01/02 Python
linux中如何使用python3获取ip地址
2019/07/15 Python
window7下的python2.7版本和python3.5版本的opencv-python安装过程
2019/10/24 Python
用python爬取历史天气数据的方法示例
2019/12/30 Python
Kmeans均值聚类算法原理以及Python如何实现
2020/09/26 Python
详解python对象之间的交互
2020/09/29 Python
美国生鲜及杂货电商:FreshDirect
2018/01/29 全球购物
写给老婆的保证书
2015/02/27 职场文书
小学四年级班主任工作经验交流材料
2015/11/02 职场文书
python元组打包和解包过程详解
2021/08/02 Python
POST提交数据常见的四种方式
2022/01/18 HTML / CSS
macos系统如何实现微信双开? mac登录两个微信以上微信的技巧
2022/07/23 数码科技