前端时间项目需要个预览功能 我的设计是给预览按钮添加自定义指令然后赋予预览功能 自定义指令就没什么可说的了 但是要在自定义指令里去调用预览组件就难到我了 当然最后也是实现了的 但是代码就丑陋了些 这里也就不现眼了 然后今天有看到大佬发的文章 代码也是美妙的狠 所以就爬下来 原文在最下面有连接

下面实现一个简易的message弹窗组件
Message/index.vue

<template>
  <div class="wrap">
    <template v-for="item in notices">
      <transition name="fade" :key="item._name">
        <div class="message" :class="item.type">
          <div class="content">{{item.content}}</div>
        </div>
      </transition>
    </template>
  </div>
</template>
<script>
// 默认选项
const DefaultOptions = {
  duration: 1500,
  type: "info",
  content: "这是一条提示信息!"
};
let mid = 0;
export default {
  data() {
    return {
      notices: []
    };
  },
  methods: {
    add(notice = {}) {
      // name标识 用于移除弹窗
      let _name = this.getName();
      // 合并选项
      notice = Object.assign(
        {
          _name
        },
        DefaultOptions,
        notice
      );

      this.notices.push(notice);

      setTimeout(() => {
        this.removeNotice(_name);
      }, notice.duration);
    },
    getName() {
      return "msg_" + mid++;
    },
    removeNotice(_name) {
      let index = this.notices.findIndex(item => item._name === _name);
      this.notices.splice(index, 1);
    }
  }
};
</script>
<style lang="scss" scoped>
.wrap {
  position: fixed;
  top: 50px;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  transform: translateX(-50%);
}

.message {
  --borderWidth: 3px;
  min-width: 240px;
  max-width: 500px;
  margin-bottom: 10px;
  border-radius: 3px;
  box-shadow: 0 0 8px #ddd;
  overflow: hidden;
}

.content {
  padding: 8px;
  line-height: 1.3;
}

.message.info {
  border-left: var(--borderWidth) solid #909399;
  background: #f4f4f5;
}

.message.success {
  border-left: var(--borderWidth) solid #67c23a;
  background: #f0f9eb;
}

.message.error {
  border-left: var(--borderWidth) solid #f56c6c;
  background: #fef0f0;
}

.message.warning {
  border-left: var(--borderWidth) solid #e6a23c;
  background: #fdf6ec;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}
</style>

Message/index.js

import Vue from 'vue'
import Index from './index.vue'

let messageInstance = null
let MessageConstructor = Vue.extend(Index) // 构造子类

let init = () => {
    messageInstance = new MessageConstructor() // 实例化组件
    // $mount可以传入选择器字符串,表示挂载到该选择器
    // 如果不传入选择器,将渲染为文档之外的的元素,你可以想象成 document.createElement()在内存中生成dom
    messageInstance.$mount() 
    // messageInstance.$el获取的是dom元素
    document.body.appendChild(messageInstance.$el)
}

/**
 * 单例且惰性
 */
export let caller = (options) => {
    if (!messageInstance) {
        init(options)
    }
    messageInstance.add(options)
}

export default {
    // 返回 install 函数 用于 Vue.use 注册
    install(vue) {
        vue.prototype.$message = caller
    }
}

main.js

import Message from '@/components/Message/index.js'
Vue.use(Message)

两种使用使用方式

      /**
       * 在.js文件里这样用
       */
      import { caller } from "@/components/Message/index.js";
      caller({
        type: "success",
        content: "成功信息提示",
        duration: 3000
      });
      
      /**
       * 在.vue文件里这样用
       */
      this.$message({
        type: "success",
        content: "成功信息提示",
        duration: 3000
      });

细节主要集中在Message/index.js这个文件里
主要是通过Vue.extend这个全局是api和这个vm.$mount实例的api去实现的
原文10个Vue开发技巧助力成为更好的工程师


卡米撒吗
117 声望8 粉丝

« 上一篇
局部打印