最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 过年了,基于Vue做一个消息通知组件

    正文概述 掘金(Vam的金豆之路)   2021-02-12   405

    前言

    今天除夕,在这里祝大家新年快乐!!!今天在这个特别的日子里我们做一个消息通知组件,好,我们开始行动起来吧!!!

    项目一览

    效果很简单,就是这种的小卡片似的效果。

    过年了,基于Vue做一个消息通知组件

    源码

    我们先开始写UI页面,可自定义消息内容以及关闭按钮的样式。

    Notification.vue

    <template>
     <transition name="fade" @after-enter="handleAfterEnter">
      <div class="notification" :style="style" v-show="visible">
       <span class="notification__content">
        {{content}}
       </span>
       <span class="notification__btn" @click="handleClose">{{btn}}</span>
      </div>
     </transition>
    </template>
    <script>
    export default {
     name: 'Notification',
     props: {
      content: {
       type: String,
       required: true
      },
      btn: {
       type: String,
       default: 'close'
      }
     }
    }
    </script>
    <style lang="less" scoped>
    .fade-enter-active, .fade-leave-active{
     transition: opacity 1s;
    }
    .fade-enter, .fade-leave-to{
     opacity: 0;
     transform: translateX(100px);
    }
    .notification{
     display: flex;
     background-color: #303030;
     color: rgba(255, 255, 255, 1);
     align-items: center;
     padding: 20px;
     position: fixed;
     min-width: 280px;
     box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0px 6px 10px 0px rgba(0, 0, 0, 0.3);
     flex-wrap: wrap;
     transition: all 0.3s;
     border-radius:10px ;
     &__content{
      padding: 0;
     }
     &__btn{
      color: #ff4081;
      padding-left: 24px;
      margin-left: auto;
      cursor: pointer;
     }
    }
    </style>
    
    

    写完基本的样式组件,我们该赋予其灵魂了。好,我们开始写最重要的逻辑。

    notify.js

    import Vue from "vue";
    import Notification from "./Notification.vue";
    
    const NotificationConstructor = Vue.extend(Notification);
    
    const instances = [];
    let seed = 1;
    // 消除Vue实例
    const removeInstance = (instance) => {
      if (!instance) return;
      const len = instances.length;
      const index = instances.findIndex((ins) => instance.id === ins.id);
    
      instances.splice(index, 1);
    
      if (len <= 1) return;
      const removeHeight = instance.height;
      for (let i = index; i < len - 1; i++) {
        instances[i].verticalOffset =
          parseInt(instances[i].verticalOffset) - removeHeight - 16;
      }
    };
    
    const notify = (options = {}) => {
      if (Vue.prototype.$isServer) return;
      // 获取vue实例
      let instance = new NotificationConstructor({
        propsData: options, // 这里是传进来一组props
        data() {
          return {
            verticalOffset: 0,
            timer: null,
            visible: false,
            height: 0,
          };
        },
        computed: {
          // 配置消息组件的位置
          style() {
            return {
              position: "fixed",
              right: "20px",
              bottom: `${this.verticalOffset}px`,
            };
          }
        },
        mounted() {
          this.createTimer();
          this.$el.addEventListener("mouseenter", () => {
            if (this.timer) {
              this.clearTimer(this.timer);
            }
          });
          this.$el.addEventListener("mouseleave", () => {
            if (this.timer) {
              this.clearTimer(this.timer);
            }
            this.createTimer();
          });
        },
        updated() {
          this.height = this.$el.offsetHeight;
        },
        beforeDestroy() {
          this.clearTimer();
        },
        methods: {
          // 创建计时器
          createTimer() {
            this.timer = setTimeout(() => {
              this.visible = false;
              document.body.removeChild(this.$el);
              removeInstance(this);
              this.$destroy();
            }, options.timeout || 5000);
          },
          // 清除计时器
          clearTimer() {
            if (this.timer) {
              clearTimeout(this.timer);
            }
          },
          // 关闭消息弹窗
          handleClose() {
            this.visible = false;
            document.body.removeChild(this.$el);
            removeInstance(this);
            this.$destroy(true);
          },
          // 过渡js钩子
          handleAfterEnter() {
            this.height = this.$el.offsetHeight;
          },
        },
      });
    
      const id = `notification_${seed++}`; // 动态生成唯一Id
      instance.id = id;
      // 生成vue中的$el
      instance = instance.$mount();
      // 将$el中的内容插入dom节点中去
      document.body.appendChild(instance.$el);
      instance.visible = true;
    
      let verticalOffset = 0;
    
      instances.forEach((item) => {
        verticalOffset += item.$el.offsetHeight + 16;
      });
    
      verticalOffset += 16;
      instance.verticalOffset = verticalOffset;
    
      instances.push(instance);
    
      return instance;
    };
    
    export default notify;
    
    

    当消息组件组高度超过浏览器显示区域的时候,消息组件会依次按顺序消失。

    在这里,我们使用了Vue.extend(),在这里我们简单地介绍下,官网上是这样介绍的。

    <div id="app"></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('#app')
    

    @after-enter="handleAfterEnter",看到这很多小伙伴会有疑问,其实这是Vue过渡组件中 JavaScript 钩子。

    官网的解释这样讲。

    <transition
      v-on:before-enter="beforeEnter"
      v-on:enter="enter"
      v-on:after-enter="afterEnter"
      v-on:enter-cancelled="enterCancelled"
    
      v-on:before-leave="beforeLeave"
      v-on:leave="leave"
      v-on:after-leave="afterLeave"
      v-on:leave-cancelled="leaveCancelled"
    >
      <!-- ... -->
    </transition>
    
    // ...
    methods: {
      // --------
      // 进入中
      // --------
    
      beforeEnter: function (el) {
        // ...
      },
      // 当与 CSS 结合使用时
      // 回调函数 done 是可选的
      enter: function (el, done) {
        // ...
        done()
      },
      afterEnter: function (el) {
        // ...
      },
      enterCancelled: function (el) {
        // ...
      },
    
      // --------
      // 离开时
      // --------
    
      beforeLeave: function (el) {
        // ...
      },
      // 当与 CSS 结合使用时
      // 回调函数 done 是可选的
      leave: function (el, done) {
        // ...
        done()
      },
      afterLeave: function (el) {
        // ...
      },
      // leaveCancelled 只用于 v-show 中
      leaveCancelled: function (el) {
        // ...
      }
    }
    
    1. 这些钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用。
    2. 当只用 JavaScript 过渡的时候,enterleave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
    3. 推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

    整理完UI组件与逻辑文件,下一步做得工作是将它们整合起来,通过Vue命令的方式直接使用。

    index.js

    import Notification from "./Notification.vue";
    import notify from "./notify.js";
    
    export default (Vue) => {
      Vue.component(Notification.name, Notification);
      Vue.prototype.$notify = notify;
    };
    

    下面,我们将使用它。

    main.js中引入index.js文件。

    import Notification from "../src/components/notification/index.js";
    Vue.use(Notification);
    

    然后,你在相应的组件中这样调用它即可。

    this.$notify({
       content: "Hello World", // 消息内容
       btn: "关闭" // 关闭按钮内容
    });
    

    结语

    谢谢大家阅读,希望没有浪费大家的时间。新的一年即将来临,2021年祝大家工作顺利,平平安安。


    起源地下载网 » 过年了,基于Vue做一个消息通知组件

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元