像jquery那样快活使用vue

本文介绍了一种函数式调用Vue组件的方法,用于解决页面中频繁出现的对话框、警告等一次性使用的组件问题,避免了组件与原有DOM的耦合,提供了更灵活的组件使用方式。

这个标题有点扯,vue和jquery不是一个东西,至少他们的设计思想和目的相差非常大。

这里准确的表达应该是:函数式调用vue组件

从vue1.0开始,我就有个疑问。

例如model,dialog,toast这样的组件,如果按照传统的组件使用的话,无外乎是全局注册,然后通过data里面的变量来切换显示。但是,这些组件一般是一次性用的,并不想和原有的DOM耦合在一块,特别是一个页面有好几个model的时候,整个template充斥着各种model标签非常的让人头疼。

记得有一次看element源码的时候,了解过一次他的toast的实现,可惜的是,那时候因为个人水平的原因,理解并不是特别深。

最近,又遇到一个页面有太多comfirm或者alert这样组件的场景,那就做下笔记吧,方便后面继续学习。

步骤:

1.首先我们可以写一个vue组件和平时我们普通的子组件没任何区别,有props,有methods

2.写一个js文件,导入vue组件,通过$mount()实例一下他,但是这里并没有给它传入dom节点

3.给已经实例的vue对象添加和props对应的属性进行赋值,

4.把已经实例的vue对象append到body里面

5.完成

使用方式:

import ConfirmDialog from './dialog'
Vue.use(ConfirmDialog)

this.$ConfirmDialog({
          title: '温馨提示',
          content: `为了你能有更好的浏览体验,<br/>建议使用谷歌或者safari浏览器 `,
          confirmTxt: '知道了',
          // confirmLoading: true,
          confirmFn: (done) => {
            done()
          }
        })

 

js代码:

import Vue from 'vue'
import DialogComponent from '@/components/dialogComponent.vue'


const ConfirmDialog = (options = {}) => {
  const DialogComponentConstructor = Vue.extend(DialogComponent)
  const instance = new DialogComponentConstructor({propsData:options}).$mount()
  DialogComponentConstructor.prototype.close = function () {
    const el = instance.$el
    el.parentNode && el.parentNode.removeChild(el)
  }
  //更新与2020/05/29
  // instance.title = options.title
  // instance.content = options.content
  // instance.confirmTxt = options.confirmTxt
  // instance.cancelTxt = options.cancelTxt
  // instance.confirmFn = options.confirmFn
  // instance.confirmLoading = options.confirmLoading
  document.body.appendChild(instance.$el)
}

const install = Vue => {
  Vue.prototype.$ConfirmDialog = ConfirmDialog
}

if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.use(install)
}

export default install

vue组件:

<template>
  <div>
    <div class="dialog-component"
         :class="[show?'show':'']"
         v-if="show">
      <div class="dialog-mask">

      </div>
      <div class="dialog-wrap">
        <div class="dialog-close"
             @click="cancel">X</div>
        <div class="dialog-title"> {{title}}</div>
        <div class="dialog-content"
             v-html="content"></div>
        <div class="dialog-btn">
          <el-button :loading="loading"
                     class="dialog-confirm-btn"
                     size="small"
                     :style="{width:!cancelTxt?'160px':''}"
                     @click="confirm">{{confirmTxt}}</el-button>
          <el-button v-if="cancelTxt"
                     size="small"
                     @click="cancel">{{cancelTxt}}</el-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { Button } from 'element-ui'
import { setTimeout } from 'timers'
import Vue from 'vue'
console.log('Button', Button)
let btn = Button.name
export default {
  name: 'dialogComponent',
  components: { [btn]: Button },
  data () {
    return {
      show: false,
      loading: false
    }
  },
  props: {
    title: {
      default: '温馨提示'
    },
    content: {
      type: String
    },
    confirmTxt: {
      default: '确定'
    },
    cancelTxt: {
      default: '取消'
    },
    confirmFn: {
      type: Function,
      default () {
        return () => { }
      }
    },
    confirmLoading: {
      type: Boolean,
      default: false
    }
  },
  created () {
    this.$nextTick(() => {
      this.show = true
    })
  },
  methods: {
    confirm () {
      if (this.confirmLoading) {
        this.loading = true
      }
      this.confirmFn(this.done, this)
    },
    done () {
      this.show = false
      localStorage.setItem('suggestBowser', 1)
      setTimeout(() => {
        try {
          Vue.prototype.$ConfirmDialog.close()
        } catch (e) { }
      }, 300)
    },
    cancel () {
      this.done()
    }
  }

}
</script>
<style lang="less">
.dialog-component {
  position: fixed;
  width: 100%;
  height: 100%;
  z-index: 6001;
  left: 0;
  top: 0;
  transition: 0.3s;
  opacity: 0;
  &.show {
    opacity: 1;
  }
}
.dialog-wrap {
  min-width: 280px;
  min-height: 174px;
  box-sizing: border-box;
  padding: 17px 17px 20px 17px;
  background: rgba(255, 255, 255, 1);
  border-radius: 6px;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -140px;
  margin-top: -80px;
  z-index: 10;
}
.dialog-mask {
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 5;
  left: 0;
  top: 0;
  background: rgba(0, 0, 0, 0.3);
}
.dialog-title {
  font-size: 16px;
  font-weight: 500;
  color: rgba(95, 162, 248, 1);
  line-height: 22px;
  text-align: center;
}
.dialog-content {
  font-size: 14px;
  font-weight: 400;
  color: rgba(51, 51, 51, 1);
  line-height: 32px;
  padding: 15px 0;
}
.dialog-close {
  position: absolute;
  right: 17px;
  top: 5px;
  width: 20px;
  height: 20px;
  font-size: 12px;
  color: #f0f0ee;
  text-align: center;
  line-height: 20px;
  cursor: pointer;
  text-align: right;
}
.dialog-btn {
  text-align: center;
}
</style>

 

遇到问题:

1.之前全局注册的element组件无法在这个函数式调用的组件里面使用,但是按照传统vue子组件的方式导入却没有问题

2.通过实例修改属性的方式,虽然可以修改props的参数,但是并不能通过props的type属性的检测,不得不放弃required

2.通过实例修改属性的方式,new 实例时候通过propsData传入props(更新2020/05/)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆康永

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值