Open yanyue404 opened 6 months ago
docs: https://vant-contrib.gitee.io/vant/v2/#/zh-CN/dialog repo: https://github.com/youzan/vant/blob/2.x/src/dialog/index.js
Dialog 是一个函数,调用后会直接在页面中弹出相应的模态框。
import { Dialog } from 'vant'; // 基础提示 Dialog({ message: '提示' }); // 消息提示:用于提示一些消息,只包含一个确认按钮。 Dialog.alert({ title: '标题', message: '弹窗内容', }).then(() => { // on close }); // 消息确认: 用于确认消息,包含取消和确认按钮。 Dialog.confirm({ title: '标题', message: '弹窗内容', }) .then(() => { // on confirm }) .catch(() => { // on cancel });
window.alert()
<body>
<div id="app">
创建一个 Vue 实例时,都会有一个选项 el,来指定实例的根节点,如果不写 el 选项,那组件就处于未挂载状态。Vue.extend 的作用,就是基于 Vue 构造器,创建一个“子类”,它的参数跟 new Vue 的基本一样,但 data 要跟组件一样,是个函数,再配合 $mount ,就可以让组件渲染,并且挂载到任意指定的节点上,比如 body。
el
Vue.extend
new Vue
data
$mount
比如上文的场景,就可以这样写:
import Vue from 'vue'; const AlertComponent = Vue.extend({ template: '<div>{{ message }}</div>', data () { return { message: 'Hello, Aresn' }; }, });
这一步,我们创建了一个构造器,这个过程就可以解决异步获取 template 模板的问题,下面要手动渲染组件,并把它挂载到 body 下:
const component = new AlertComponent().$mount();
这一步,我们调用了 $mount 方法对组件进行了手动渲染,但它仅仅是被渲染好了,并没有挂载到节点上,也就显示不了组件。此时的 component 已经是一个标准的 Vue 组件实例,因此它的 $el 属性也可以被访问:
component
$el
document.body.appendChild(component.$el);
当然,除了 body,你还可以挂载到其它节点上。
$mount 也有一些快捷的挂载方式,以下两种都是可以的:
// 在 $mount 里写参数来指定挂载的节点 new AlertComponent().$mount('#app'); // 不用 $mount,直接在创建实例时指定 el 选项 new AlertComponent({ el: '#app' });
实现同样的效果,除了用 extend 外,也可以直接创建 Vue 实例,并且用一个 Render 函数来渲染一个 .vue 文件:
import Vue from 'vue'; import Notification from './notification.vue'; const props = {}; // 这里可以传入一些组件的 props 选项 const Instance = new Vue({ render (h) { return h(Notification, { props: props }); } }); const component = Instance.$mount(); document.body.appendChild(component.$el);
这样既可以使用 .vue 来写复杂的组件(毕竟在 template 里堆字符串很痛苦),还可以根据需要传入适当的 props。渲染后,如果想操作 Render 的 Notification 实例,也是很简单的:
Notification
const notification = Instance.$children[0];
因为 Instance 下只 Render 了 Notification 一个子组件,所以可以用 $children[0] 访问到。
$children[0]
如果你还不理解这样做的目的,没有关系,后面小节的两个实战你会感受到它的用武之地。
需要注意的是,我们是用 $mount 手动渲染的组件,如果要销毁,也要用 $destroy 来手动销毁实例,必要时,也可以用 removeChild 把节点从 DOM 中移除。
$destroy
removeChild
import vue from 'vue' import vueComponent from './index.vue' // 组件构造器,构造出一个 vue组件实例 const CreateConstructor = vue.extend(vueComponent) let instance function showConfirm(options = {}) { return new Promise((resolve, reject) => { instance = new CreateConstructor({ el: document.createElement('div'), data() { return { show: true } }, methods: { onCancel: (e) => { instance.reject() // 返回修改 instance.show = false } } }) instance.$on('confirm', () => { instance.show = false instance.resolve() }) Object.assign(instance, options, { resolve, reject }) // 添加节点 document.body.insertBefore(instance.$el, document.body.children[0]) }) } export default showConfirm
// 使用 showConfirm() .then(() => { alert('confirm') }) .catch(() => { alert('cancel') })
// 不适用于创建后直接修改 props 的情况, 会报修改 props wraning export function mount(component, opt, el) { if (!component) { console.warn('亲,请传入正确的组件'); } if (!el) { el = document.createElement('div'); document.body.appendChild(el); } return new Vue({ el, render(h) { return h(component, opt); }, }); } // 使用 Vue.extend 的方式可以更好复用实例,从实例修改 props export function mountComponent(component, option, apply) { const root = document.createElement('div'); const getInstance = () => { const CreateConstructor = Vue.extend(component); // * option.data(Function) 修改 data // * option.propsData(Object) 修改 props // * option.methods (Object) 修改 methods return new CreateConstructor({ el: root, ...option }); }; const instance = getInstance(); // 可以直接扩展实例,或按返回值自行扩展 //eg: instance.$on (承接组件内部的 $emit)、instance.$slots (自定义插槽的内容) apply(instance); // 添加节点 document.body.appendChild(root); return { instance, unmount() { instance.$el.remove(); }, }; } export function destory(vm) { vm.$el.remove(); vm.$destroy(); }
注意:vue 组件需要使用 export default { setup : {}} 模式才可获取到 instance 实例上的属性和方法
export default { setup : {}}
instance
// form vant@3.0.7 export function mountComponent(RootComponent, props = {}) { var app = createApp(RootComponent, props); var root = document.createElement('div'); document.body.appendChild(root); return { instance: app.mount(root), unmount() { app.unmount(); document.body.removeChild(root); } }; }
函数调用
Dialog 是一个函数,调用后会直接在页面中弹出相应的模态框。
使用场景
window.alert()
的提示框组件,它的位置是在<body>
下,而非<div id="app">
,并且不会通过常规的组件自定义标签的形式使用,而是像 JS 调用函数一样使用。从熟悉 Vue 的构造器——extend 与手动挂载——$mount 开始
创建一个 Vue 实例时,都会有一个选项
el
,来指定实例的根节点,如果不写el
选项,那组件就处于未挂载状态。Vue.extend
的作用,就是基于 Vue 构造器,创建一个“子类”,它的参数跟new Vue
的基本一样,但data
要跟组件一样,是个函数,再配合$mount
,就可以让组件渲染,并且挂载到任意指定的节点上,比如 body。比如上文的场景,就可以这样写:
这一步,我们创建了一个构造器,这个过程就可以解决异步获取 template 模板的问题,下面要手动渲染组件,并把它挂载到 body 下:
这一步,我们调用了
$mount
方法对组件进行了手动渲染,但它仅仅是被渲染好了,并没有挂载到节点上,也就显示不了组件。此时的component
已经是一个标准的 Vue 组件实例,因此它的$el
属性也可以被访问:当然,除了 body,你还可以挂载到其它节点上。
$mount
也有一些快捷的挂载方式,以下两种都是可以的:实现同样的效果,除了用 extend 外,也可以直接创建 Vue 实例,并且用一个 Render 函数来渲染一个 .vue 文件:
这样既可以使用 .vue 来写复杂的组件(毕竟在 template 里堆字符串很痛苦),还可以根据需要传入适当的 props。渲染后,如果想操作 Render 的
Notification
实例,也是很简单的:因为 Instance 下只 Render 了 Notification 一个子组件,所以可以用
$children[0]
访问到。需要注意的是,我们是用
$mount
手动渲染的组件,如果要销毁,也要用$destroy
来手动销毁实例,必要时,也可以用removeChild
把节点从 DOM 中移除。来个例子
支持 Vue2
支持 Vue3
其他