这个标题有点扯,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/)
本文介绍了一种函数式调用Vue组件的方法,用于解决页面中频繁出现的对话框、警告等一次性使用的组件问题,避免了组件与原有DOM的耦合,提供了更灵活的组件使用方式。
2655

被折叠的 条评论
为什么被折叠?



