美文网首页
VEditDialog小组件是如何实现保存和取消的

VEditDialog小组件是如何实现保存和取消的

作者: 且须文雅 | 来源:发表于2023-05-24 08:50 被阅读0次

最近在使用Vuetify中VDataTable组件附带的VEditDialog小组件时,发现我在Dialog里的Input组件绑定了v-model,但是VEditDialog组件点取消时它能恢复原值,点击保存能保留修改后的值。
这看似挺简单的一个功能,但Vuetify却特意做了一个这样的小组件,我们就来看看它时怎么实现这个小功能的吧。
首先看到创建组件的第一行:
export default mixins(Returnable, Themeable)
它混入了ReturnableThemeable两个模块,其中Themeable模块比较清楚,它是用于跟随框架主题切换和设置的通用模块。
然后再看VEditDialog的代码:

export default mixins(Returnable, Themeable).extend({
  name: 'v-edit-dialog',

  props: {
    cancelText: {
      default: 'Cancel',
    },
    large: Boolean,
    eager: Boolean,
    persistent: Boolean,
    saveText: {
      default: 'Save',
    },
    transition: {
      type: String,
      default: 'slide-x-reverse-transition',
    },
  },

  data () {
    return {
      isActive: false,
    }
  },

  watch: {
    isActive (val) {
      if (val) {
        this.$emit('open')
        setTimeout(this.focus, 50) // Give DOM time to paint
      } else {
        this.$emit('close')
      }
    },
  },

  methods: {
    cancel () {
      this.isActive = false
      this.$emit('cancel')
    },
    focus () {
      const input = (this.$refs.content as Element).querySelector('input')
      input && input.focus()
    },
    genButton (fn: Function, text: VNodeChildren): VNode {
      return this.$createElement(VBtn, {
        props: {
          text: true,
          color: 'primary',
          light: true,
        },
        on: { click: fn },
      }, text)
    },
    genActions (): VNode {
      return this.$createElement('div', {
        class: 'v-small-dialog__actions',
      }, [
        this.genButton(this.cancel, this.cancelText),
        this.genButton(() => {
          this.save(this.returnValue)
          this.$emit('save')
        }, this.saveText),
      ])
    },
    genContent (): VNode {
      return this.$createElement('div', {
        staticClass: 'v-small-dialog__content',
        on: {
          keydown: (e: KeyboardEvent) => {
            e.keyCode === keyCodes.esc && this.cancel()
            if (e.keyCode === keyCodes.enter) {
              this.save(this.returnValue)
              this.$emit('save')
            }
          },
        },
        ref: 'content',
      }, [this.$slots.input])
    },
  },

  render (h): VNode {
    return h(VMenu, {
      staticClass: 'v-small-dialog',
      class: this.themeClasses,
      props: {
        contentClass: 'v-small-dialog__menu-content',
        transition: this.transition,
        origin: 'top right',
        right: true,
        value: this.isActive,
        closeOnClick: !this.persistent,
        closeOnContentClick: false,
        eager: this.eager,
        light: this.light,
        dark: this.dark,
      },
      on: {
        input: (val: boolean) => (this.isActive = val),
      },
      scopedSlots: {
        activator: ({ on }) => {
          return h('div', {
            staticClass: 'v-small-dialog__activator',
            on,
          }, [
            h('span', {
              staticClass: 'v-small-dialog__activator__content',
            }, this.$slots.default),
          ])
        },
      },
    }, [
      this.genContent(),
      this.large ? this.genActions() : null,
    ])
  },
})

看它的操作逻辑:

  1. 开启对话框时自动找到对话框中的input并聚焦
  2. 取消则设置isActivefalse,上面有监听isActive,变为true时则打抛出“open”事件,操作打开对话框,延迟50毫秒自动聚焦输入框,如果为false则抛出“close”事件关闭对话框

但是呢,却没看到它的保存方法,可能时再Returnable模块里写的,过去看看:

export default Vue.extend({
  name: 'returnable',

  props: {
    returnValue: null as any,
  },

  data: () => ({
    isActive: false,
    originalValue: null as any,
  }),

  watch: {
    isActive (val) {
      if (val) {
        this.originalValue = this.returnValue
      } else {
        this.$emit('update:return-value', this.originalValue)
      }
    },
  },

  methods: {
    save (value: any) {
      this.originalValue = value
      setTimeout(() => {
        this.isActive = false
      })
    },
  },
})

Retrunable模块代码比较少,写的是一个Vue子类,对isActive进行监听,为真时,用originalValue属性将returnValue的值保存,当为假时,把originalValue的值更新到returnValue
下面就是“保存”方法了,它就是简单的把传入的值保存到originalValue,然后将isActive设为假,然后就有了上一段的动作。

到这里,我们就知道为什么我在input上已经对值进行了v-model双向绑定了,却还是有保存和取消的效果,都是这个模块在做这个事。

现在就可以知道,它这个模块名命名为Returnable的意思了,意思是有可退回的能力
这一点我觉得很值得我们学习,Vuetify把所有可以抽象的能力都抽象出来一个子类中,除了这个类,还有上面说的Themeable,就是拥有主题继承及设置能力,还有Colorable,拥有设置颜色的能力,等等等等。可以说,Vuetify的代码让我是受益匪浅。

相关文章

网友评论

      本文标题:VEditDialog小组件是如何实现保存和取消的

      本文链接:https://www.haomeiwen.com/subject/gmlxedtx.html