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 字符串连接性能优化
Dec 20 Javascript
express的中间件bodyParser详解
Dec 04 Javascript
js完美实现@提到好友特效(兼容各大浏览器)
Mar 16 Javascript
基于JavaScript实现百叶窗动画效果不只单纯flas可以实现
Feb 29 Javascript
js 定义对象数组(结合)多维数组方法
Jul 27 Javascript
15个非常实用的JavaScript代码片段
Dec 18 Javascript
underscore之function_动力节点Java学院整理
Jul 11 Javascript
详解使用angular的HttpClient搭配rxjs
Sep 01 Javascript
JavaScript实现简单动态进度条效果
Apr 06 Javascript
vue项目中公用footer组件底部位置的适配问题
May 10 Javascript
详解JavaScript中的数据类型,以及检测数据类型的方法
Sep 17 Javascript
微信小程序实现登录注册功能
Dec 29 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
Laravel使用Queue队列的技巧汇总
2019/09/02 PHP
Javascript 面向对象之重载
2010/05/04 Javascript
jQuery 顺便学习下CSS选择器 奇偶匹配nth-child(even)
2010/05/24 Javascript
JS日期格式化之javascript Date format
2015/10/01 Javascript
JQuery 设置checkbox值二次无效的解决方法
2016/07/22 Javascript
vue.js入门教程之计算属性
2016/09/01 Javascript
bootstarp modal框居中显示的实现代码
2017/02/18 Javascript
AngularJS中的promise用法分析
2017/05/19 Javascript
详细讲解vue2+vuex+axios
2017/05/27 Javascript
在Debian(Raspberry Pi)树莓派上安装NodeJS的教程详解
2017/09/19 NodeJs
解决JSON.stringify()自动将中文转译成unicode的问题
2018/01/05 Javascript
微信小程序scroll-view实现滚动穿透和阻止滚动的方法
2018/08/20 Javascript
JS Html转义和反转义(html编码和解码)的实现与使用方法总结
2020/03/10 Javascript
深入理解 ES6中的 Reflect用法
2020/07/18 Javascript
微信小游戏中three.js离屏画布的示例代码
2020/10/12 Javascript
关于angular 8.1使用过程中的一些记录
2020/11/25 Javascript
[01:35]2018年度CS GO最佳战队-完美盛典
2018/12/17 DOTA
Python+Selenium自动化实现分页(pagination)处理
2017/03/31 Python
Python编程判断这天是这一年第几天的方法示例
2017/04/18 Python
python基于pyDes库实现des加密的方法
2017/04/29 Python
使用python绘制3维正态分布图的方法
2018/12/29 Python
利用Python+阿里云实现DDNS动态域名解析的方法
2019/04/01 Python
Python比较配置文件的方法实例详解
2019/06/06 Python
python如何爬取网站数据并进行数据可视化
2019/07/08 Python
html5拖拽应用记录及注意点
2020/05/27 HTML / CSS
Zatchels官网:英国剑桥包品牌
2021/01/12 全球购物
创建绿色学校先进个人材料
2014/08/20 职场文书
劳模事迹材料范文
2014/12/24 职场文书
初中家长评语大全
2014/12/26 职场文书
一年级数学下册复习计划
2015/01/17 职场文书
灵山大佛导游词
2015/02/04 职场文书
大学生求职简历自我评价
2015/03/02 职场文书
纪录片信仰观后感
2015/06/08 职场文书
2019年“我为祖国点赞”演讲稿(3篇)
2019/09/26 职场文书
曾国藩励志经典名言37句,蕴含哲理
2019/10/14 职场文书
vue实现input输入模糊查询的三种方式
2022/08/14 Vue.js