Skip to content

七.特殊窗口(对话框)

前言 --> 弹框组件特点

  • 下拉菜单组件应该由两部分组成:
    • 选中项的文本
    • 待选菜单(默认隐藏)
  • 它的主要功能包括:
    • 鼠标经过下拉菜单组件,显示待选菜单
    • 鼠标滑出下拉菜单组件,隐藏待选菜单
    • 鼠标点击待选菜单中的条目,选中项文本更新,组件派发 change 事件

🏷️ 问题一:多个弹框,有层级问题,需要全局调整层级

1.目录结构

sh
├── dialog                      
   ├── dialog.vue       
   └── index.js

1.使用场景

平时我们开发时我们写的组件基本上都是通过#app 实现挂载在页面的。

js
import Vue from "vue";
import App from "./app.vue";
new Vue({
  el: "#app",
  render: (h) => h(App),
});

这样的组建使用方式,有几个特点:

  • 所有的内容,都是在#app节点内渲染的
  • 组件的模板,是事先定义好的
  • 由于组件的特性,注册的组件只能在当前位置渲染

如果在一些特殊的场景下就比较局限了:

  • 组件的模板是通过调用接口从服务端获取的,需要动态渲染组件
  • 实现类似原生window.alert()的提示框组件,它的位置是在<body>下,而非<div id="app">,并且不会通过常规的组件自定义标签的形式使用,而是像 JS 调用函数一样使用。

一般来说,在我们访问页面时,组件就已经渲染好了,对于第一个场景,组件的渲染是异步的,甚至预先不知道模板是什么。对于第二个场景,通过操作 dom 很容易实现。对于这两种场景,在 vue 中我们可以通过 Vue.extend 和 vm.$mount 来实现

2.用法

创建一个 vue 实例,都会有一个选项el,来指定实例的根节点,如果不写el选项,那组件就处于未挂载状态。Vue.extend的作用,就是基于 Vue 构造器,创建一个子类,它的参数和new Vue的基本一致,但data要和组件一样,是个函数,再配合$mount,就可以让组件渲染,并且挂载到任意指定的节点上。

创建一个构造器,解决异步获取 template 模板的问题

js
import Vue from "vue";
const AlertComponent = Vue.extend({
  template: "<div>{{message}}</div>",
  data() {
    return {
      message: "hello",
    };
  },
});

手动渲染组件,并且挂载到 body 下

js
const component = new AlertComponent().$mount();
document.body.appendChild(component.$el);

当然,除了 body,你还可以挂载到其他节点上

$mount也有一些快捷的挂载方式,以下两种都是可以的

js
// 在$mount里写参数来指定挂载的节点
new AlertComponent().$mount("#app");
// 不用$mount,直接在创建实例是指定el选项
new AlertComponent({ el: "#app" });

除了用 extend 外,也可以直接创建 Vue 实例,并且用一个 Render 函数来渲染一个.vue 文件:

js
import Vue from "vue";
import Notification from "./notification.vue";

const props = {};

const Instance = new Vue({
  render(h) {
    return h(Notification, {
      props: props,
    });
  },
});
const component = Instance.$mount();
document.body.appendChild(component.$el);

这样既可以使用.vue 来写复杂的组件,还可以根据需要传入适当的 props。渲染后,如果想操作 Render 的Notfication实例,也是很简单的:

js
const notification = Instance.$children[0];

因为 Instance 下只 render 了 Notification 一个子组件,所以可以额用$children[0]访问到

需要注意的是,我们使用$mount手动渲染组件,如果要销毁,也要用$destory来手动销毁实例,必要时,也可以用removeChild把节点从 DOM 中移除

使用场景

我们在写 Vue.js 时,不论是用 CDN 的方式还是在 Webpack 里用 npm 引入 Vue.js,都会有一个根节点,并且创建一个根实例,比如:

vue
<body>
  <div id="app"></div>
</body>
<script>
const app = new Vue({
  el: "#app",
});
</script>

Webpack 也类似,一般在入口文件 main.js 里,最后会创建一个实列:

js
import Vue from "vue";
import App from "./app.vue";

new Vue({
  el: "#app",
  render: (h) => App,
});

因为用 Webpack 基本都是前端路由的,它的 html 里一般都只有一个根节点<div id="app"></div>,其余都是通过 JavaScript 完成,也就是许多的 Vue.js 组件(每个页面也是一个)。

有了初始化的实例,之后所有的页面,都由 vue-router 帮我们管理,组件也都是用import导入后局部注册(也有在 main.js 全局注册的),不管哪种方式,组件(或页面)的创建过程我们是无需关心的,只是写好.vue文件并导入即可。这样的组件使用方式,有几个特点:

  • 1.所有的内容,都是在#app节点内渲染的;
  • 2.组件的模板,是事先定义好的
  • 3.由于组件的特性,注册的组件只能在当前位置渲染
<template>
    <vue-button>按钮</vue-button>
</template>