Vue之函数式弹窗组件的封装原理

简介: Vue之函数式弹窗组件的封装原理

vue的封装组件大家都知道,通过props,event,slot 即可实现一个特殊的弹框组件。代码如下:

<template>
  <div>
    <Alert v-if="show">这是一条提示信息</Alert>
    <button @click="show = true">显示</button>
  </div>
</template>
<script>import Alert from '../component/alert.vue';
  export default {
    components: { Alert },
    data () {
      return {
        show: false
      }
    }
  }
  </script>

但是这种弹框通常都有以下缺点:


1. 每个使用的地方都必须要先引用注册。


2. 需要预先将封装好的 组件放置在模板中。


3. 需要额外的data来控制 弹框 的显示状态。


4. 弹框的位置,是当前组件位置,并非在body下。并且有可能会被其它组件遮挡。


基于以上问题,所以说,普通的组件封装是对使用者来说不是很友好,如果我们在类似于全局封装的函数中(例如:axios 响应中)引入,则当前这种就比较不好的了。那么如何能实现一个优雅的组件呢?


其实对比原生的 window.alert("这是一个弹框")


我们就可以知道,一个优雅的组件莫过于,能用JavaScript随时随地调用的组件。


类似于:


它可以在任何位置进行使用,无需单独引入,并且接收两个参数。


content: 提示内容


duration: 持续时间,默认1.5秒


最终样子如下:


this.$alert.info({
      content: '我是一个弹窗',
      duration: 3
});


下来我们就一起看看如何实现这个全局弹框组件。


一:我们可以通过最终调用值发现,this.$alert。 很明显指的就是vue的实例。也就是说我们声明完成的一个alert则会是一个js文件,并且我们将它挂载在了 vue.prototype之上。


由此我们可以断定。这个vue文件的main.js中是这样写的


// ... 其余代码省略
import alert from '@/components/alert.js'
Vue.prototype.$alert = alert
new Vue({
    ...其余代码,
    render: h => h(App)
}).$mount('#app')


而我们在调用 this,$alert 的时候初始化了一个info方法,那么这个方法一定是存在于 alert这个js文件中。并且是一个初始化弹窗方法, 接收两个参数,一个是弹窗内容,一个是弹窗显示时间。

// alert.js
... 省略代码
const notice = ({
    content = '',
    duration = 1.5 
}) =>{
    // 传递给弹窗的实际组件方法中
    // 此处暂不编写。
}
export default {
    info(options){
        return notice(options)    
    }
}

到目前为止,我们根据最后弹窗的使用方法,简单的推断出了 alert.js这个文件。但是有这个文件可不够,我们还是需要一个页面。也就是说,我们也还是需要一个dom 展示页面的,不然我们的弹窗样式无法定义。


所以我们基于 alert.js的同级目录,新增一个页面,alert.vue 用来展示 弹框的样式


<template>
  <div class="alert">
    <div class="alert-main" v-for="item in notices" :key="item.name">
      <div class="alert-content">{{ item.content }}</div>
    </div>
  </div>
</template>
<script>export default {
    data () {
      return {
        notices: []
      }
    }
  }
  </script>
<style>.alert{
    position: fixed;
    width: 100%;
    top: 16px;
    left: 0;
    text-align: center;
    pointer-events: none;
  }
  .alert-content{
    display: inline-block;
    padding: 8px 16px;
    background: #fff;
    border-radius: 3px;
    box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
    margin-bottom: 8px;
  }
  </style>

因为我们通过已知的业务,通知可以是多条的,并且每一条都可以有不同的展示时间,所以在弹窗展示这里,我们用notices 数组来保存一个个的单内容。


细心的朋友会发现,这个页面与以往的组件页面不一致,那是因为,我们本次的组件是需要JavaScript来调用的,而非传递数据改变其状态调用。所以我们不需要props 以及 event事件。


接下来,只要给数组 notices 增加数据,这个提示组件就能显示内容了,我们先假设,最终会通过 JS 调用 Alert 的一个方法 add,并将 content 和 duration 传入进来:


所以我们修改 alert.vue这个页面的内容


<script>
  let seed = 0;
  function getUuid() {
    return 'alert_' + (seed++);
  }
  export default {
    data () {
      return {
        notices: []
      }
    },
    methods: {
      add (notice) {
        const name = getUuid();
        let _notice = Object.assign({
          name: name
        }, notice);
        this.notices.push(_notice);
        // 定时移除,单位:秒
        const duration = notice.duration;
        setTimeout(() => {
          this.remove(name);
        }, duration * 1000);
      },
      remove (name) {
        const notices = this.notices;
        for (let i = 0; i < notices.length; i++) {
          if (notices[i].name === name) {
            this.notices.splice(i, 1);
            break;
          }
        }
      }
    }
  }
  </script>

add方法为,我们每一条传递进来的提示数据,我们通过添加一个name字段,来表示这条数据是唯一的值。在每一次add的时候都push到notices 的数组中,并且根据传递进来的时间,利用 setTimeout 设置其展示时间。


同时,当传递进来的时间到期后,我们通过remove 方法将其从 notices 的数组中进行移除。


所以在这一步,我们就必须将当前的弹窗进行实例化,因为我们不是常规使用组件方法,所以这是哈哈我们使用Vue.extend 或者 newVue 实例化后,利用$mount 挂载到body下。

// notification.js
import alert from './alert.vue';
import Vue from 'vue';
alert.newInstance = properties => {
  const props = properties || {};
  const Instance = new Vue({
    data: props,
    render (h) {
      return h(alert, {
        props: props
      });
    }
  });
  const component = Instance.$mount();
  document.body.appendChild(component.$el);
  const alerts = Instance.$children[0];
  return {
    add (noticeProps) {
      alerts.add(noticeProps);
    },
    remove (name) {
      alerts.remove(name);
    }
  }
};
export default alert;

notification.js 并不是最终的文件,它只是对 alert.vue 添加了一个方法  newInstance,这个方法就是实例化后的 alert 方法。我们通过实例化alert后,获取到alerts。它就是组件alert的组件实例,在newInstance里,我们使用闭包暴漏了两个方法,一个add,一个 remove。


最后我们就可以补全我们最开始预留的代码 alert.js

/ alert.js
import Notification from './notification.js';
let messageInstance;
function getMessageInstance () {
  messageInstance = messageInstance || Notification.newInstance();
  return messageInstance;
}
function notice({ duration = 1.5, content = '' }) {
  let instance = getMessageInstance();
  instance.add({
    content: content,
    duration: duration
  });
}
export default {
  info (options) {
    return notice(options);
  }
}

这就是我们本期所说的,vue之函数式弹窗组件的生成。

目录
相关文章
|
25天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
1天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
25天前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
27天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
28天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
32 1
vue学习第一章
|
28天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
|
28天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
|
28天前
|
JavaScript 前端开发 算法
vue学习第7章(循环)
欢迎来到瑞雨溪的博客,一名热爱JavaScript和Vue的大一学生。本文介绍了Vue中的v-for指令,包括遍历数组和对象、使用key以及数组的响应式方法等内容,并附有综合练习实例。关注我,将持续更新更多优质文章!🎉🎉🎉
24 1
vue学习第7章(循环)
|
28天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
29 1
vue学习第九章(v-model)
|
28天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
39 1
vue学习第十章(组件开发)
下一篇
DataWorks