Toast
写一个普通的vue组件大家应该都很熟悉,定义、注册、使用一顿行云流水的操作就出来了。今天来整一个可自定义的toast组件试试?
toast组件需要具备的功能:
1、一次注册满"世界"用2、可自定义内容
直接开始撸起来
创建vue组件
首先在lib目录下创建toast文件,并且新建toast.vue和index.js
toast大小、尺寸、位置应该由调用方自行修改,因为我们这边在toast外层绑定一些style属性
<!-- toast.vue -->
<template>
<div class="wrap"
v-if="show"
:class="{'icon-center': type===1, 'fadein': show, 'fadeout': !show}"
:style="{left,top,bottom,right,width,fontSize}">
<!--
toast默认显示为水平垂直居中,即left,top,bottom,right,width,fontSize需要存在默认值,
后面在index.js里设置.
-->
<!-- code code code -->
</div>
</template>
icon图标,我们有些项目可能是在成功、失败、警告等情况下调用,这时候就需要使用下icon,这边也支持一下这功能
<!--
toast.vue
这里引用了一个svg图标,来标识成功信息提示。
hasIcon是一个计算属性,根据error的值来决定是否要显示icon
error: -1(不显示)、0(成功)、1(错误)....
-->
<div class="toast-icon"
v-if="hasIcon">
<svg t="1568117267444"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1990"
width="32"
height="32"
v-if="error===0">
<path d="M512 85.333333c235.648 0 426.666667 191.018667 426.666667 426.666667s-191.018667 426.666667-426.666667 426.666667S85.333333 747.648 85.333333 512 276.352 85.333333 512 85.333333z m-74.965333 550.4L346.453333 545.152a42.666667 42.666667 0 1 0-60.330666 60.330667l120.704 120.704a42.666667 42.666667 0 0 0 60.330666 0l301.653334-301.696a42.666667 42.666667 0 1 0-60.288-60.330667l-271.530667 271.488z"
fill="#52C41A"
p-id="1991"></path>
</svg>
</div>
<script>
export default {
computed: {
hasIcon() {
return [0, 1, 2].includes(this.error);
}
}
};
</script>
剩下的就是toast文字部分了,看起来很简单,但是这里的水还是有点深的,传递一个纯文本那是相当滴轻松直接...
<div class="tips-text">
<div v-if="text">{{ text }}</div>
</div>
夸夸夸一行代码搞定,以为万事大吉。过两天产品改个需求,说提示框文字能不能改个颜色、下划线什么的,诶,简单,老子十秒钟给你解决
<div class="tips-text">
<div v-if="text" v-html="text"></div>
</div>
这么一来我们这个toast支持html标签,完美,产品你有什么需求尽管改。自信过后产品说toast要能够支持点击跳转(。。。。。。。。。。。掏出二维码,扫码改需求)。那我们再优化一下
<div class="tips-text">
<div v-html="text" v-if="text"></div>
<!-- toast-template作为一个用户自定义节点 -->
<div id="toast-template"></div>
<!-- assist多行提示内容 -->
<div class="assist"
v-show="type === 2">{{ assist }}</div>
</div>
<script>
//index.js
// custom字段为用户传入的vue组件对象包含data、methods等等
let hvue = Vue.extend(custom);
// 挂载模板
let components = new hvue().$mount().$el;
this.$nextTick(() => {
// 插入到toast-template节点里面
document.getElementById('toast-template').appendChild(components);
})
</script>
这么一来这个toast组件就可以支持任何vue能干事情,高度可自定义
配置参数
function showToast({
text, // 提示文本
duration = 1500, // toast几秒后关闭时长
error = -1, // icon类型,默认不显示,0-成功。。。。
container = 'body', // toast相对容器。toast是绝对定位,需要一个相对容器,默认body
left = '50%', // 距离相对容器左边距
right = 'auto', // 距离相对容器右边距
top = '50%', // 距离相对容器上边距
bottom = 'auto', // 距离相对容器下边距
type = 1, // 是否多行提示,默认单行,type=2为多行,第二行文字小一号
width = 'auto', // toast宽度
assist = '', // 多行提示第二行文本内容
fontSize = '12px',
custom = '' // vue组件对象
} = {}) {
// 实例化
const toastDom = new ToatConatructor({
el: document.createElement('div'),
data() {
return {
show: true,
text,
error,
left,
bottom,
right,
top,
width,
type,
assist,
fontSize,
custom
};
},
mounted() {
// 自定义模板
if (custom) {
let hvue = Vue.extend(custom);
// 挂载模板
let components = new hvue().$mount().$el;
this.$nextTick(() => {
document.getElementById('toast-template').appendChild(components);
})
}
}
});
// 插入节点
createDom(container, toastDom)
// 过了duration后消失
setTimeout(() => {
toastDom.show = false;
// 优化,销毁节点
deleteDom(container, toastDom);
}, duration);
}
创建和销毁节点
/**
* 创建节点
* @param {*} container 支持传入父容器class、id以及节点
* @param {*} toastDom 需要插入的节点
*/
function createDom(container, toastDom) {
if (typeof container == 'string') {
document.querySelector(container) && document.querySelector(container).appendChild(toastDom.$el);
} else {
container.appendChild(toastDom.$el);
}
}
/**
* 销毁节点
* @param {*} container
* @param {*} toastDom
*/
function deleteDom(container, toastDom) {
if (typeof container == 'string') {
document.querySelector(container) && document.querySelector(container).removeChild(toastDom.$el);
} else {
container.removeChild(toastDom.$el);
}
}
注册组件
import Vue from 'vue';
import toastComponent from './toast.vue';
const ToatConatructor = vue.extend(toastComponent);
/**
* 全局挂载节点
*/
function registryToast() {
Vue.prototype.$toast = showToast;
}
export default registryToast;
使用
首先在main.js里面引入toast
import toast from '@/lib/toast' // 路径按照自己的来,我这里放在lib目录下
Vue.use(toast)
剩下就是调用,调用,调用
<template>
<div class="home">
<div @click="error"
style="color: #fff;">唤起Toast</div>
</div>
</template>
<script>
export default {
name: 'home',
methods: {
error() {
this.$toast({
container: '.home',
text: 'aaaaa',
error: 0
});
}
}
};
</script>
到这里toast已经撸完了,最后贴一波完整代码吧
<template>
<div class="wrap"
v-if="show"
:class="{'icon-center': type===1, 'fadein': show, 'fadeout': !show}"
:style="{left,top,bottom,right,width,fontSize}">
<div class="toast-icon"
v-if="hasIcon">
<svg t="1568117267444"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1990"
width="32"
height="32"
v-if="error===0">
<path d="M512 85.333333c235.648 0 426.666667 191.018667 426.666667 426.666667s-191.018667 426.666667-426.666667 426.666667S85.333333 747.648 85.333333 512 276.352 85.333333 512 85.333333z m-74.965333 550.4L346.453333 545.152a42.666667 42.666667 0 1 0-60.330666 60.330667l120.704 120.704a42.666667 42.666667 0 0 0 60.330666 0l301.653334-301.696a42.666667 42.666667 0 1 0-60.288-60.330667l-271.530667 271.488z"
fill="#52C41A"
p-id="1991"></path>
</svg>
</div>
<div class="tips-text">
<div v-html="text"
v-if="text"></div>
<div id="toast-template"></div>
<div class="assist"
v-show="type === 2">{{ assist }}</div>
</div>
</div>
</template>
<script>
export default {
computed: {
hasIcon() {
return [0, 1, 2].includes(this.error);
}
}
};
</script>
<style scoped>
.wrap {
position: absolute;
background-color: #fff;
padding: 10px 15px;
border-radius: 3px;
color: #000;
transform: translate(-50%, -50%);
box-shadow: 1px 1px 2px 2px rgba(204, 204, 204, 0.2);
font-size: 12px;
display: flex;
z-index: 10019;
justify-content: center;
box-shadow: 1px 1px 1px #ddd;
transform: translate(-50%, -50%);
}
.toast-icon {
color: #fff;
border-radius: 50%;
width: 1.5em;
height: 1.5em;
line-height: 1.45em;
text-align: center;
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
margin: 0 0.85em 0 0;
}
.icon-center {
align-items: center;
}
.tips-text {
font-size: 1em;
color: #3a4f66;
}
.assist {
font-size: 0.8em;
margin: 0.3em 0 0 0;
color: #8997a4;
}
.fadein {
animation: animate_in 0.25s;
}
.fadeout {
animation: animate_out 0.25s;
opacity: 0;
}
@keyframes animate_in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes animate_out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
index.js
import toastComponent from './toast.vue';
import Vue from 'vue';
const ToatConatructor = Vue.extend(toastComponent);
function showToast({
text,
duration = 30000,
error = -1,
container = 'body',
left = '50%',
right = 'auto',
top = '50%',
bottom = 'auto',
type = 1,
width = 'auto',
assist = '',
fontSize = '12px',
custom = ''
} = {}) {
// 实例化
const toastDom = new ToatConatructor({
el: document.createElement('div'),
data() {
return {
show: true,
text,
error,
left,
bottom,
right,
top,
width,
type,
assist,
fontSize,
custom
};
},
mounted() {
// 自定义模板
if (custom) {
let hvue = Vue.extend(custom);
// 挂载模板
let components = new hvue().$mount().$el;
this.$nextTick(() => {
document.getElementById('toast-template').appendChild(components);
})
}
}
});
// 插入节点
createDom(container, toastDom)
// 过了duration后消失
setTimeout(() => {
toastDom.show = false;
// 优化,销毁节点
deleteDom(container, toastDom);
}, duration);
}
/**
* 创建节点
* @param {*} container 支持传入父容器class、id以及节点
* @param {*} toastDom 需要插入的节点
*/
function createDom(container, toastDom) {
// console.warn(container, toastDom, toastDom.$el, document.querySelector(container));
if (typeof container == 'string') {
document.querySelector(container) && document.querySelector(container).appendChild(toastDom.$el);
} else {
container.appendChild(toastDom.$el);
}
}
/**
* 销毁节点
* @param {*} container
* @param {*} toastDom
*/
function deleteDom(container, toastDom) {
if (typeof container == 'string') {
document.querySelector(container) && document.querySelector(container).removeChild(toastDom.$el);
} else {
container.removeChild(toastDom.$el);
}
}
/**
* 全局挂载节点
*/
function registryToast() {
Vue.prototype.$toast = showToast;
}
export default registryToast;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。