现在发觉睡觉的时间越来越少,项目越来越多,组件越写越停不下来,因为过段时间要做一个技术分享,还有很多赶着急的项目等着我,今天不睡觉也要把这个教程写完分享给大家,如果大家想参加我的技术分享请用微信打开我的分享会,欢迎大家收听
http://gitbook.cn/m/mazi/activity/58df0deb840f63972c0de7e4?bogot=gmwIS8&from=groupmessage
https://juejin.im/post/58e65fb944d904006d3543de
接下来还是按着我们约定的来
2.代码运行vue-cli 2.1版本
3.组件代码都在components文件夹里
4.主代码逻辑都在 App.vue文件夹里
我什么都不要我只要
赞
学之前我给大家补几个知识点,用菊花想也知道如果我们用toast组件肯定是插入一个toast节点,那我们原本用jQuery如何实现,那就是定义好一个基本的toast dom节构,然后插入到根节点里,那其实vue-toast也是这么实现的
学之前我们先补两个知识点。这个两个知识点学会了你就学会了,先看一个官方给的一个例子,我也是看这个东西才明白一些东西的
使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({template: '<p>{
{firstName}} {
{lastName}} aka {
{alias}}</p>',data: function () {return {firstName: 'Walter',lastName: 'White',alias: 'Heisenberg'}}
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')
//结果如下:<p>Walter White aka Heisenberg</p>
如果我们想创建一个实例,就是所谓的dom结构,我们是在vue实列上创建一个’子类’,可以包含,所有的选项对象,那我们就要那到vue.extend(),并挂到已经现在的一个dom节点上,那就是#mount-point节点
//在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {// DOM 更新了
})
这个知识点,其实vue讲起来是数据驱动,本质上还是在改变dom,但是我们在改变数据的时候。dom会从新渲染,在dom从新渲染的时候,你想拿到你想得到的dom或者改变dom ,比方说remove dom,为了确保一定能执行正确的操作,因此vue有一个更新dom的事件队列,等到这个队列完成,你再进行dom操作
index.html
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>y</title><meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"><script>(function(doc, win) {var docEl = doc.documentElement,resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',recalc = function() {var clientWidth = docEl.clientWidth;if (!clientWidth) return;if (clientWidth >= 640) {docEl.style.fontSize = '100px';} else {docEl.style.fontSize = 100 * (clientWidth / 640) + 'px';}};if (!doc.addEventListener) return;win.addEventListener(resizeEvt, recalc, false);doc.addEventListener('DOMContentLoaded', recalc, false);})(document, window);</script>
</head><body><div id="app"></div><!-- built files will be auto injected -->
</body></html>
还是跟上期的spinner组件一样,先把html的适配给做一下
components/toast/toast.vue
<template><transition name='fade'><div v-show='visible' :class='position' class='toast'><i>{
{message}}</i></div></transition>
</template><script>export default {data() {return {visible: false,message : '',position : ''};}}
</script><style>
.toast {position: fixed;left:50%;transform:translate(-50%,-50%) scale(1);word-wrap:break-word;padding:10px;text-align: center;z-index:9999;font-size:.3rem;max-width:80%;color: #fff;border-radius: 5px;background: rgba(0,0,0,0.7);overflow: hidden;
}
.toast.middle{top:50%;
}
.toast.top{top:10%;
}
.toast.bottom{top:90%;
}
.fade-enter-active, .fade-leave-active {transition: transform .5s
}
.fade-enter, .fade-leave-active {transform:translate(-50%,-50%) scale(0);
}
</style>
我们在toast.vue先设计一个你想要的toast组件的样子,我们在data里声明了三个数据
一.visible 对toast的显示和隐藏
二.message 显示的文字
三.positon 我们写在动态class里,根据不同的数据改变不同的位置
components/toast/toast.js
import Vue from 'vue'
const ToastConstructor = Vue.extend(require('./toast.vue'))
let removeDom = event => {event.target.parentNode.removeChild(event.target);};
ToastConstructor.prototype.close = function() {this.visible = false;this.$el.addEventListener('transitionend', removeDom);
};
const Toast = (options = {}) => {var instance = new ToastConstructor().$mount(document.createElement('div'))let duration = options.duration || 2500;instance.message = typeof options === 'string' ? options : options.messageinstance.position = options.position || 'middle'document.body.appendChild(instance.$el);instance.visible = true;Vue.nextTick(() => {instance.timer = setTimeout(function() {instance.close();}, duration);})return instance
}export default Toast
首先我们要先import vue 因为我们Vue.extend()依赖于vue
const ToastConstructor = Vue.extend(require('./toast.vue'))
这段代码就像我前面讲的一样,我们用vue.extend()创建toast子实列
那问题来了,我们缺少一个挂载点,怎么办,不要急,看后面
在Toast函数里,我们用了es6语法(options = {}),我们把options先用了一个默认参数,默认参数是一个对象,用来传不同的方式,显示 不同toast的样式
var instance = new ToastConstructor().$mount(document.createElement('div'))
当我们执行Toast()的时候,我们肯定就要开始执行Toast函数了,如果执行下去我们一行一行看
这里我们就用到前面我所说的,如何去把子实列挂载的问题,我们先把这子实列new出来,然后用$mount方法去挂到我们自己创建的dom节点上,那就解决了挂载的问题,
此时的instance就是toast组件的实列了,我们再看看官方的一个说法,如何拿到实列上的数据,如何改变实例上的数据,两者是否同步更新
ar data = { a: 1 }
var vm = new Vue({data: data
})
vm.a === data.a // -> true
// 设置属性也会影响到原始数据
vm.a = 2
data.a // -> 2
// ... 反之亦然
data.a = 3
vm.a // -> 3
这个官方例子,已经很明确的告诉了我们,通过实例改变数据,此时实例内部数据会同时改变
那OK我们接下去看
let duration = options.duration || 2500;
当我们如果没有设置显示时长,那我们则使用默认2500,这个时长,我们没有必要放到data数据里,因为这个不关于toast任何显示操作
instance.message = typeof options === 'string' ? options : options.message
我们此时要显示toast组件上提示文字的时候,我们传数据有两种形式,第一就是直接Toast(‘aaaa’),那此时我们传的参数就不是一个对象,而是一个字符串,所以我们进行判断,当我们参数是一个字符串则直接使用options这个参数当作message
还有一种可能是传参是一个对象,Toast({message:’aaaa’})此时我们就要用options.message了
instance.position = options.position || 'middle'
这个很好理解,当我们传对象的时候,里面有postion这个属性的时候这用传的属性,不然用默认的
document.body.appendChild(instance.$el);</code> 所有的我们要toast所显示的参数我们都配置好了,接下来我们就要把这个toast整个节点给添加到body里面,那我们会奇怪,$el是什么鬼东西,如果我们console.log(instance.$el)你会发现,是一整个toast的dom结构,那就对了,我们需要的就是这个东西添加到body里
然后我们让visible = true 别人都说这个是多此一举,因为我要做transition动画。所以这个必须要做一个显示隐藏操作,
Vue.nextTick(() => {instance.timer = setTimeout(function() {instance.close();}, duration);
})
接下来很简单,我们等一个时间等待操作,当多少时间后我们再进行删除这个toast组件
ToastConstructor.prototype.close = function() {this.visible = false;this.$el.addEventListener('transitionend', removeDom);
};
我们还是在子实列的原型上写了一个close方法,可以拿到实列上的属性,我们对$el进行transitionend
动画结束监听,当动画结束时的,我们才进行删除节点,调用的是removeDom方法
最后return instance,可以对实列再进行操作
最后我们在App.vue
<template><div><button @click='a'>点击1</button><button @click='b'>点击2</button> </div>
</template><script>
import Toast from './components/zk-toast/toast.js'
export default {methods : {a () {Toast('只是一个文字弹出')},b() {Toast({message : "有位置的设定和时间设定",position: 'top',duration : 1000})}}
}
</script><style>
</style>
你们就可以点击查看效果了
一套啪啪啪拳已经打完收工,在这个原理上,我们可以再去创建一个些messagebox这种组件,其实本质就上就是类似的东西,每天都在梦想而奋斗,晚安大家!