手写一个Vue版Toast组件

3,865 阅读3分钟

前言

目前,前端生态圈中各大厂高大尚的UI库比比皆是。但是作为一名业务中都是接触移动端开发、H5开发的搬砖者,面对产品各种高端霸气上档次的需求,996是在所不辞的。

所以该如何减少自己的工作压力?

  1. 工作中养成对自己代码复盘的习惯,各式各样常用到的设计都可以抽离出来作为公共使用的插件或者组件。这样在后续遇到同样问题时,Ctrl+C、Ctrl+V复制粘贴使用是能快速完成问题的,但是不利于代码的可阅读性。正所谓一时抽离一时爽,后续使用一直爽。
  2. 也可以选择忽悠产品改需求,也可以选择阅读UI库源码改动源码来适配需求。正所谓条条大路通罗马,我更倾向拥有自己一套逻辑思维的设计,自行改动的时候也更加快速。

我的第N个Vue组件,Toast

1.组件设计

对外暴露方法 info success errer warning close

API

参数 说明 类型 可选值 默认值
context 提示的内容 String
duration 关闭时间 Number 3000
icon 可自定义的icon String
mask 是否开启遮罩层 Boolean false/true false
clear Toast关闭回调 Function

2.实现

1.对外暴露调用方法
//index.js

const type = ["success", "errer", "warning"]
const fnc = {
    name: 'G-Toast',
    info: (options = {}) => {
        
    },
    close: () => {
        if (install) {
            
        }
    }
}
type.forEach(element => {
    fnc[element] = (options = {}) => {
        
    }
});

export default fnc
2.视图实现
<!--index.vue-->

<template>
  <div class="g7-Toast">
    <template v-if="mask">
      <transition name="fade">
        <div v-show="value" class="g7-Toast-mask"></div>
      </transition>
    </template>
    <transition name="fade">
      <div v-show="value" :class="['g7-Toast-body',type]">
        <div class="g7-Toast-iconfont" v-show="type">
          <Icon :icon="iconfont" :size="26" color="#fff" />
        </div>
        <div class="g7-Toast-context">{{context}}</div>
      </div>
    </transition>
  </div>
</template>

<script>
import Icon from "../Icon";
export default {
  components: { Icon },
  props: {
    type: {
      type: String,
      validator: function(value) {
        return ["success", "errer", "warning", "loading"].includes(value);
      }
    },
    value: {
      type: Boolean
    },
    context: {
      type: String
    },
    icon: {
      type: String
    },
    mask: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    iconfont() {
      if (this.icon) {
        return this.icon;
      }
      const icon = {
        success: "iconzhengque",
        errer: "iconcuowu",
        warning: "iconinfo",
        loading: ""
      };
      return icon[this.type];
    }
  }
};
</script>
3.创建实例Vue,渲染视图
//index.js

import Vue from "vue";
import Toast from "./index.vue";

let install;

function newInstall(options) {
    install = new Vue({
        data() {
            return options;
        },
        render(h) {
            return h(Toast, {
                props: {
                    value: this.value,
                    context: this.context,
                    type: this.type,
                    icon: this.icon,
                    mask: this.mask
                }
            })
        }
    })
    if (window) {
        document.body.appendChild(install.$mount().$el)
    }
}

小提示:配置jsx在render函数中写渲染函数会更爽

4.增加调用视图方法
// index.js

let timer;

function init(options, type) {
    const params = {
        value: undefined,
        context: undefined,
        type: undefined,
        duration: 3000,
        icon: undefined,
        mask: undefined,
        clear: () => { }
    }
    if (!install) {
        newInstall(params)
    }
    Object.assign(install, params, options, { value: true, context: options.context ? options.context : options, type: type })
    if (install.duration > 0) {
        clearTimeout(timer);
        timer = setTimeout(function () {
            Object.assign(install, { value: false })
            install.clear()
        }, install.duration);
    }
}
5.最后更新代码对外暴露调用方法
//index.js

const type = ["success", "errer", "warning"]
const fnc = {
    name: 'G-Toast',
    info: (options = {}) => {
        init(options)
    },
    close: () => {
        if (install) {
            Object.assign(install, { value: false })
            install.clear()
        }
    }
}
type.forEach(element => {
    fnc[element] = (options = {}) => {
        init(options, element)
    }
});

export default fnc

效果图

总结

本人水平有限,搬砖不易,不足之处请多指教!
各种各样的业务组件经过内部业务的打磨后,会慢慢整理共享给各位大佬......