1.0.9 • Published 4 years ago

@allo_shuang/modal v1.0.9

Weekly downloads
-
License
ISC
Repository
-
Last release
4 years ago

弹窗组件

一. 背景及用途

  • 当前问题:

    • 工程组织问题:

      • 项目中弹窗文件分布于各个业务代码中,很难实现复用,引用路径复杂。
      • 各弹窗的显隐控制逻辑混杂在业务代码中,各种业务props传递复杂
      • 父组件被隐藏时,弹窗也会被隐藏
    • 前端效率问题:

      针对弹窗这种可能一辈子也不会展示的组件:

      • ElementUI默认底层使用v-show实现,依然会绘制到dom树中
      • 理论上应该使用动态加载,不使用,不加载。减小最后打包的大小
    • 心智成本:

      • 个人风格及经验千差万别
      • 弹窗公共逻辑重复编写,且容易出错。
      • 新人接手旧项目,难以理解起外部逻辑及传入参数。
  • 本组件主要解决的问题:

    • 工程组织问题:
      • 统一项目中所有弹窗文件位置至单一文件夹管理。
      • 弹窗由统一单独的dom元素负责展示,全自动。
    • 前端效率问题:
      • 使用webpack中require.context省去了手动引入大量弹窗文件的工作,同时默认支持动态加载。用不到的弹窗,永不加载。
      • 考虑到扩展性,提供四种优先级的公共参数配置
      • 提供公共样式,loading状态,确定及取消逻辑,确定/取消按钮的显隐控制等
    • 心智成本:
      • 无需手动引用及注册组件,减少代码量。
      • 所有业务相关参数在一个对象中传入,不用定义大量的props。
      • 显隐逻辑自治,无需手动管理相关逻辑。
      • 单一弹窗,单一逻辑。类似于纯函数,所有逻辑由传入的参数控制,便于不同的业务逻辑复用。
      • 默认提供loading状态,处理异步逻辑时,只用关心业务接口。

二. 安装

1.安装库

npm i @allo_shuang/modal@latest -S

2.在src目录下新建文件夹/modal

3.在main.js文件中引用

import Modal from '@allo_shuang/modal'

Vue.use(Modal,{参数放这里...});

实际项目中,在/modal文件夹中创建index.js文件并在文件中引入了组件库,及自定义的样式文件

/modal

------index.js(在这里引入组件库及Vue.use传递统一配置参数,引入样式文件)

------style.scss

这样在main.js文件中只需引入@/modal即可。将配置及样式统一在modal文件夹中管理

###三. 使用

以新建弹窗ExampleModal为例

  1. 在src/modal文件夹中新建文件夹src/modal/ExampleModal并在其中创建index.vue文件。这个组件为弹窗中间部分显示的内容

  2. index.vue内部定义props:

     props: {params: Object},//params对应3中传入的参数
  3. 在任意想要使用弹窗的地方,调用:

    this.$modal.show('ExampleModal', {组件内部需要的参数放这里,对应2的params})

四. 自定义选项

按照优先级,本组件有四个地方可以配置如下参数:

参数名默认值说明
titlenull弹窗标题
width640px宽度
cancelText取消取消按钮文字,设为空字符串''时,按钮隐藏
okText确定确定按钮文字,设为空字符串''时,按钮隐藏
showFootertrue确认/取消按钮所在的footer是否显示
closeOnClickModalfalse同elementUI-Dialog的close-on-click-modal
showClosefalse同elementUI-Dialog的show-close
customClass‘’自定义的类名,用于个性化弹窗样式

参数优先级:

手动传入 > 组件定义 > 全局定义 > 默认值

  1. 唤起弹窗时传入的参数

    this.$modal.show('ExampleModal', {放这里的参数优先级最高})
  2. 子组件内部定义的参数,与data,methods,生命周期等同级定义的参数

    export default {
        title: '我是标题',<-------这里的优先级第二高
        okText:'提交',<-------这里的优先级第二高
        ...
        ...
        data() {return {}},
        methods:{}
    }
  3. 全局定义的参数。Vue.use传入的参数中:

    Vue.use(Modals, {
    title: '我是标题',<-------这里的优先级第三高
    okText:'提交',<-------这里的优先级第三高
    showFooter:false<-------这里的优先级第三高
    ...
    })
  4. 默认值。如表中所列。代码在UniModal.vue中

      const defaultParams = {
        title: null,
        width: '640px',
        cancelText: '取消',
        okText: '确定',
        showFooter: true,
        closeOnClickModal: false,
        showClose: true,
        customClass: ''
      }

五. 内置方法

  • 组件methods中

    • 如果定义了onCancel()方法,则会忽略默认的取消关闭操作
    • onOK()为点击确定按钮时触发的方法,需要自己实现
  • 关闭当前弹窗

    this.$modal.close()
  • loading状态:loading状态下显示loading动画,屏蔽弹窗上所有交互操作,确认/取消按钮均不可点击。

    • 常用于点击确定按钮后,发出网络请求。
    this.$emit('updateLoading', true/false)
  • 内置的确认弹窗:

    • this.$modal.text(params,callback):纯文本内容,无图标

    • this.$modal.success(params,callback):绿色✓图标+文本

    • this.$modal.warning(params,callback):黄色!图标+文本

    • this.$modal.error(params,callback):红色x图标+文本

    • this.$modal.info(params,callback):蓝色i图标+文本

    • 上述五个方法的参数:

      • params:除自定义参数与上述内置参数外,额外增加三个参数:

        • content:文本内容
        • elementIcon:elementUI中Icon的名字,例如:'el-icon-warning',
        • iconColor:图标的颜色
      • callback:点击确认的回调。形如(params, closeModal, setLoading) => {}

        • params:与第一个参数params相同,用于回传自定义参数

        • closeModal:关闭弹窗的方法。closeModal()

        • setLoading:控制弹窗的loading状态

//例如,依据companyId删除信息
this.$modal.warning(
	{title:'警告',content:'确认删除公司信息吗?',width:'200px',companyId:'com-oiie-9839'},
  (params, closeModal, setLoading) => {
    setLoading(true)
    api.deleteCompanyInfo(params.companyId).then(()=>{
        setLoading(false)
        closeModal()
      })          
  })
)

六. 样式

除了手动传入的customClass类名外,默认提供类:modal-inner-class

可以在.modal-inner-class类下定义公共样式,在自定义类名下定义弹窗特异样式。

七. Q & A

  • 文件夹是否只能叫/modal?

    • 不是的,如果使用的是vue-cli创建的项目,可以在.env文件中自定义常量:

      VUE_APP_MODAL_PATH = '自定义路径'

      同时在引入组件库时,使用

      import Modals from '@allo_shuang/modal/cli'

      原理:require.context编译时,第一个参数为字符串,不接受变量及运算...

  • 是否只支持Element-UI?

    • 算是吧。因为默认使用的是el-dialog。理论上使用任何UI组件库都是可以的。这个组件最开始是React+AntD版的,现在使用VUE技术栈,顺便迁移过来的。
  • 为什么看网络请求,发现弹窗对应的js文件请求了两次?

    • 这是因为webpack对动态加载的文件做了prefetch以提高性能。
    • 第一个请求可以在header中看到Purpose: prefetch
    • 第二个请求可以看到size一栏目显示:(prefetch cache)
    • 可以在webpack或者vue.config.js中禁用prefetch。这是另外的话题。
  • 既然使用了Element-UI,为什么不直接使用this.$confirm方法而要提供默认的success等方法?

    • 首先是为了将默认的这些方法统一归到默认dom下进行管理
    • 使其支持普通弹窗接受的任何参数,减少心智负担
    • 提供了loading等高级功能
    • 默认的confirm不太支持高级定制
    • 默认方法也是动态加载的,不使用不加载
  • 为什么生成key要使用random方法?

    • 即使是同名的弹窗,也要使用不同的key来保证单个弹窗的独立性
    • 不排除将来同时打开两个同名的弹窗
  • 代码中的overlay参数是干什么的?

    • 你居然发现了隐藏参数!!!
    • 默认同一时间只有一个弹窗存在。如果打开弹窗时,传入overlay:true,则弹窗会同时最在。所以弹窗在容器中使用栈来保存的。同时closeAll方法也是因为同样的原因而存在。
    • 规划中多弹窗的情况有很多功能及场景,预计在后续版本中放出,所以文档中暂时隐藏该参数。
  • 为什么要自己写一个遮罩?

    • 多个弹窗切换时,如果使用element-ui自带的遮罩,会出现闪屏的现象。所以自己实现一个遮罩在最下方,同时默认遮罩全部隐藏。

八. 相关技术点

  • 如何自定义组件,Vue.use()的使用

  • require.context的使用及与动态加载的结合

  • Object.create(null)

  • 实例化单文件组件及单独挂载:new + Vue.extend + .$mount() + document.body.appendChild

  • Vue挂载全局方法,Vue.prototype.xxx=

  • 使用key属性来强制刷新/更新组件

  • 获取动态加载组件内定义的值与方法:

    component().then(module => {
            if (module && module.default) {
            module.default.xxxxxx
    }})
  • 动态组件的使用

  • Vue-cli项目环境变量的规则:在.env文件中以VUEAPP开头

九. TODO:

  • 增加element-loading-text,element-loading-spinner,element-loading-background的支持
  • 多弹窗展示时的遮盖,显隐,参数传递等
  • 增加默认的样式代码以适配常见场景,例如弹窗中,form的input长度改为100%等
1.0.9

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

0.0.3

4 years ago

0.0.2

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.6

4 years ago

0.0.1

4 years ago