我对Vue.js和Vuetify相当陌生(使用AngularJS已有数年,但我们公司已改用Vue.js)。我要完成的工作是,当用户单击“登录”按钮时,它会进行一些检查(即用户名不能为空),并启动Vuetify对话框来提醒用户。我知道Vuetify具有一些内置的验证功能,但是正在寻找更强大的功能来等待响应(例如,当我需要等待诸如可以使用您的历史记录/位置之类的信息时)。
基本上想做的事
if (!userName){
userName = await mbox('You must Enter your Username');
return
}
OR
var mProceed = await mbox('Can we use your location for awesome stuff?');
其中mbox(一个简单的消息框弹出框)是一个返回诺言,以编程方式加载vue组件,将其添加到dom并等待响应的函数。
即
async function mbox (mText) {
// load dialog component here and set message passed in
// How Do I load the template / wait for it?
return dialogResult
}
Vue组件看起来像(将按钮标题和文本作为变量传递给我的mbox函数)
<template>
<v-layout row justify-center>
<v-dialog
v-model="dialog"
max-width="290"
>
<v-card>
<v-card-title class="headline">Use Google's location service?</v-card-title>
<v-card-text>
Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="green darken-1"
flat="flat"
@click="dialog = false"
>
Disagree
</v-btn>
<v-btn
color="green darken-1"
flat="flat"
@click="dialog = false"
>
Agree
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-layout>
</template>
我可以很好地编辑模板/为vue组件添加脚本,但我不确定如何通过返回promise并等待响应的方法调用它?
答案 0 :(得分:1)
我的解决方案。
Page.vue
<template>
<v-container>
<v-layout text-center wrap>
<v-flex xs12>
<v-btn v-on:click="open_dlg">Dlg Wrapper</v-btn>
<dlg-wrapper ref="dlg">
<dlg-frame title="Dialog" message="Message"></dlg-frame>
</dlg-wrapper>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import DlgWrapper from "@/components/DlgWrapper";
import DlgFrame from "@/components/DlgFrame";
export default {
data: () => {
return {};
},
methods: {
open_dlg: function(event) {
this.$refs.dlg.open().then(result => {
console.log("Result:", result);
});
}
},
components: {
DlgWrapper,
DlgFrame
}
};
</script>
DlgWrapper.vue
<template>
<div>
<v-dialog
v-model="dialog"
persistent
:width="options.width"
v-bind:style="{ zIndex: options.zIndex }"
>
<slot></slot>
</v-dialog>
</div>
</template>
<script>
export default {
name: "dlg-wrapper",
data: () => ({
dialog: false,
options: {
width: 400,
zIndex: 200
},
resolve: null,
reject: null
}),
methods: {
open(options) {
this.dialog = true;
this.options = Object.assign(this.options, options);
return new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
},
agree() {
this.resolve(true);
this.dialog = false;
},
cancel() {
this.resolve(false);
this.dialog = false;
}
},
provide: function() {
return { agree: this.agree, cancel: this.cancel };
}
};
</script>
DlgFrame.vue
<template>
<v-card dark>
<v-card-title v-show="!!title">{{ title }}</v-card-title>
<v-card-text v-show="!!message">{{ message }}</v-card-text>
<v-card-actions>
<v-btn @click="agree">OK</v-btn>
<v-btn @click="cancel">NO</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "dlg-frame",
props: ["title", "message"],
data: () => ({}),
inject: ["agree", "cancel"],
methods: {}
};
</script>
祝你好运!
答案 1 :(得分:0)
最终以这种方式解决了这个问题:
我有一个称为mbox(返回承诺)的方法,该方法创建我的组件的一个实例,将其添加到DOM,然后监视该组件上的属性以了解用户选择了哪个选项。用户选择选项后,兑现承诺
我的mbox方法:
import MBOX from './components/mbox.vue';
import _Vue from 'vue';
export default {
mbox(mText, mTitle, mBtnCap1, mBtnCap2, mBtnCap3){
return new Promise(async (resolve, reject) => {
if (!mTitle){
mTitle = 'My Title';
}
if (!mBtnCap1){
mBtnCap1 = 'OK';
}
// I'm combining a bunch of stuff to make this work.
// First, create the vue component
var mboxInstance = _Vue.extend(MBOX); // mbox component, imported at top of Sublib
var oComponent = new mboxInstance({
propsData: {
msg: mText,
title: mTitle,
btnCap1: mBtnCap1,
btnCap2: mBtnCap2,
btnCap3: mBtnCap3,
retval: 0
}
}).$mount();
// now add it to the DOM
var oEl = document.getElementById('app').appendChild(oComponent.$el);
// NOTE: couldn't get it to work without adding a 'button' to activate it
// progrmatically click it and make the button invisible
// document.getElementById('mbox_btn_launch').click();
var oLuanchBtn = document.getElementById('mbox_btn_launch');
oLuanchBtn.style.visibility = 'hidden';
oLuanchBtn.click();
// Add a listener so we can get the value and return it
oComponent.$watch('retval', function(newVal, oldVal){
// this is triggered when they chose an option
// Delete the component / element now that I'm done
oEl.remove();
resolve(Number(newVal));
})
}); // promise
}, // mbox
}
还有我的MBOX组件:
<template>
<v-dialog max-width="290" persistent v-if="showMbox">
<template v-slot:activator="{on}">
<v-btn id="mbox_btn_launch" v-on="on">
Test
</v-btn>
</template>
<v-card>
<v-card-title>{{title}}</v-card-title>
<v-card-text>{{msg}}</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn v-if="btnCap1" @click="btnClicked('1')">{{btnCap1}}</v-btn>
<v-btn v-if="btnCap2" @click="btnClicked('2')">{{btnCap2}}</v-btn>
<v-btn v-if="btnCap3" @click="btnClicked('3')">{{btnCap3}}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: 'mbox',
data: () => ({
showMbox: true
}),
props: [
// these can be passed in, the 'data' stuff can't
'msg',
'title',
'btnCap1',
'btnCap2',
'btnCap3',
'retval' // watches this so we know when they clicked something
],
created(){
this.showMbox = true;
},
methods: {
btnClicked: function(mBtnClicked){
// mBtnClicked = Char. Has to be a character in order for it to pass it in. Not sure why, numerics didn't work
mBtnClicked = Number(mBtnClicked);
this.retval = mBtnClicked; // watcher in Sublib will detect this value has changed
this.showMbox = false;
} // btnClicked
} // methods
} // export default
</script>
<style scoped>
</style>
然后我可以这样称呼它:
var mChoice = await mbox('What do you want to do?', 'Title', 'Option 1', 'Option 2');
或简单的“验证”提示:
if (!userName){
mbox('You must enter a username');
return;
}
答案 2 :(得分:0)
//exit page
beforeRouteLeave (to, from, next){
if(!this.redirect.hasConfirmed){
let originalJson = JSON.stringify(this.original);
let modifiedJson = JSON.stringify(this.configs);
if(originalJson.localeCompare(modifiedJson) != 0){
this.redirect.path = to.fullPath;
this.dialogs.save.show = true;
}else{
next();
}
}else{
this.redirect.hasConfirmed = false;
next();
}
}
methods: {
//close track dialog
closeDialog(params){
this.dialogs.save.show = false;
if(params.action == 'submit'){
this.save();
this.redirect.hasConfirmed = true;
this.$router.push({path: this.redirect.path});
}else if(params.action == 'ignore'){
this.redirect.hasConfirmed = true;
this.$router.push({path: this.redirect.path});
}else if(params.action == 'cancel'){
return;
}
}
答案 3 :(得分:0)
如果您要使用 Composition API
插件路线...我使用 provide/inject
+ 一个 useDialog
可组合。
只需使用对话框提供程序组件包装您的模板组件:
<template>
<v-app>
<v-main>
<v-container>
<DialogProvider>
<Nuxt />
</DialogProvider>
</v-container>
</v-main>
</v-app>
</template>
<script lang="ts">
import { defineComponent } from '@nuxtjs/composition-api';
import DialogProvider from '~/components/DialogProvider.vue';
export default defineComponent({
components: {
DialogProvider,
}
});
</script>
然后每当你想显示一个确认对话框时,就这样调用它:
<script lang="ts">
import { defineComponent } from '@nuxtjs/composition-api';
import { useDialog } from '~/composables';
export default defineComponent({
setup() {
const createConfirmDialog = useDialog();
const handleDelete = async () => {
try {
const shouldProceed = await createConfirmDialog(
'Confirm',
'Delete this post?',
{ width: 300 }
);
if (shouldProceed) {
// delete post
}
} catch (_e) {}
};
return {
handleDelete
};
},
});
</script>
完整代码在这里:https://gist.github.com/wobsoriano/1e63708d7771c34f835c0f6e3c5e731a