最近要做一个与颜色选择器有关功能:当用户在颜色面板里预选颜色时,需要同时更新当前画布的颜色;如果取消选择,则将画布背景重置为初始颜色;如果确定了颜色,则更新当前画布颜色。比较容易想到的方法是,用两个变量分别记录初始值 originValue 与当前值 value :如果只是选择,那就用去更新 value ;如果取消选择,重置为 originValue ;如果选中,将 originValue 更新为 value 。不过,除了颜色,还有背景图,也需要用到这个类似的功能。既然多个地方用到了,那就写的优雅一点,封装一个类来实现吧。

与上述逻辑相同,需要两个变量用来记录 originValuevalue ,而且根据不同的操作,可以划分为三种更新方式:

  • change :更新 value
  • update :将 originValue 改为 value
  • reset :将 value 改为 originValue

在实例化时,需要传入一个初始值,用以构造函数内部初始化。

大体思路有了,先来实现一个简单的版本。我给它起了一个高大上的名字:PseudoUpdate(伪更新)

// PseudoUpdate 1.0
class PseudoUpdate {
  constructor(value) {
    this.originValue = value
    this.value = value
  }

  change(value) {
    this.value = value
  }

  update(value) {
    this.originValue = value
  }

  reset() {
    this.value = this.originValue
  }
}

用法也很简单。

const color = new PseudoUpdate("red")

// 当预选颜色时
function handleChange(newColor) {
  color.change(newColor)
}

// 当确定颜色时
function handleUpdate(newColor) {
  color.update(newColor)
}

// 当取消选择时
function handleReset() {
  color.reset()
}

ViewDesign 中的 ColorPicker 刚好提供了三个 event

两者搭配使用就是:

<color-picker
  v-model="color.value"
  @on-change="handleUpdate"
  @on-active-change="handleChange"
  @on-open-change="isOpen => !isOpen && handleReset()"
/>

而实际开发的时候,color 不一定是当前组件中的,有可能是从其他组件中传过来的,这时候,如果需要更新其他组件中的 color ,就需要监听 color.value 的值,然后通知其他组件去更新。

再或者,可以在类的构造函数中,再传入一个 callback 函数,当内部的 value 发生变化时,去执行这个 callback 方法。

// PseudoUpdate 2.0
class PseudoUpdate {
  constructor(value, callback) {
    this.originValue = value
    this.value = value
    this.callback = callback
  }

  change(value) {
    this.value = value
    this.callback(value)
  }

  update(value) {
    this.originValue = value
  }

  reset() {
    this.value = this.originValue
    this.callback(value)
  }
}

如果在 callback 内部使用到了 this ,这里需要额外谨慎!

两者其实差别不大,相比之下,第二种方法更清晰一点,只需要定义一个 callback 方法,其余的交给 PseudoUpdate 内部去做就可以了,无需关心其他问题。