惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
O
OpenAI News
N
News and Events Feed by Topic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Webroot Blog
Webroot Blog
Google Online Security Blog
Google Online Security Blog
云风的 BLOG
云风的 BLOG
N
News | PayPal Newsroom
H
Hacker News: Front Page
博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Heimdal Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Schneier on Security
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Y
Y Combinator Blog
Cyberwarzone
Cyberwarzone
Microsoft Security Blog
Microsoft Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
GbyAI
GbyAI
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
人人都是产品经理
人人都是产品经理
P
Palo Alto Networks Blog
M
MIT News - Artificial intelligence
G
GRAHAM CLULEY
C
Check Point Blog
Apple Machine Learning Research
Apple Machine Learning Research
Last Week in AI
Last Week in AI
T
Troy Hunt's Blog
L
Lohrmann on Cybersecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
量子位
博客园 - 聂微东
S
Securelist
博客园 - 三生石上(FineUI控件)
F
Full Disclosure
G
Google Developers Blog
L
LINUX DO - 热门话题
P
Proofpoint News Feed
AI
AI
PCI Perspectives
PCI Perspectives

小蘿蔔丁

About 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。 小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。
小蘿蔔丁的自留地: 喜欢码字,数码控,美剧迷,热爱开源技术,前端搬砖,专注科技互联网。
2020-01-02 · via 小蘿蔔丁

doctor-strange-time-stone

现代浏览器的功能越来越强大,前端需要处理的业务逻辑也越来越复杂,提供良好的交互是我们一直追求的事,而我们在做的可视化报表工具,有一个重要的提升用户体验的功能,撤销 & 重做,这个功能给用户以安全感和保障,用户不会担心所做的操作以及交互会消失掉,不可追溯。

为了实现这个功能,我调研了一些实现方式,有基于 Immutable 数据结构的,有基于 数据结构去管理的,我们的实际项目使用 Vuex 作为全局状态管理工具。而真正适合我们实际项目的其实是基于 Vuex 的 store 实例 API 的实现方式,将所有通过 Vuex 存储的状态,在触发 actions/mutations 时存为历史记录,当我们想用的时候就可随意“穿梭”。

鉴于此我结合 stateshot 开发了一个可以 “时间旅行” 的 Vuex 插件。

本文将介绍一种基于 Vuex API 实现的 “时间旅行” 插件,以动态网格布局为例子,使用 stateshot.js 实现的 撤销 & 重做 功能,大致效果如下图:

vuex-stateshot-gif

时间旅行

Why

time-stone

Time Gem,强大的时间宝石,拥有操控时间的能力。

When

deadpool

后悔,人类很神奇的感觉,当我做了一件事之后后悔了,想如果没做该多好,想要回到当初。

How

infinity-war

那么我们需要一颗拥有时间旅行强大功能的“时间宝石”,让我们去创造它

实现“时间宝石“

vuex-stateshot 的实现借助了 Vuex 的一些 API,以及 stateshot.js 用来记录历史状态,以及进行撤销 & 重做。

202001_vuex-stateshot

当我们触发一个 actions/mutations,可以通过订阅的方式,触发一次 snapshot,记录下历史状态快照,这样就方便我们进行撤销 & 重做。

下面让我们认识一下这些 API,subscribesubscribeActionregisterModulecreateNamespacedHelpers

Vuex API

Vuex.Store 实例方法以及辅助函数中提供了一些可能平时用不到的 API,这些 API 在开发 Vuex 插件很好用。

store.subscribe

订阅 store 的 mutation。handler 会在每个 mutation 完成后调用,接收 mutation 和经过 mutation 后的状态作为参数:

store.subscribe((mutation, state) => {  console.log(mutation.type)  console.log(mutation.payload)})

store.subscribeAction

3.1.0 起,subscribeAction 提供了常用于开发 Vuex 插件的用法,可以指定订阅处理函数的被调用时机应该在一个 action 分发之前(before)还是之后(after) (默认行为是之前):

store.subscribeAction({  before: (action, state) => {    console.log(`before action ${action.type}`)  },  after: (action, state) => {    console.log(`after action ${action.type}`)  }})

store.registerModule

在 store 创建之后,你可以使用 store.registerModule 方法注册模块:

// 注册模块 `myModule`store.registerModule('myModule', {  // ...})// 注册嵌套模块 `nested/myModule`store.registerModule(['nested', 'myModule'], {  // ...})

模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。

createNamespacedHelpers

通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:

import { createNamespacedHelpers } from 'vuex'const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')export default {  computed: {    // 在 `some/nested/module` 中查找    ...mapState({      a: (state) => state.a,      b: (state) => state.b    })  },  methods: {    // 在 `some/nested/module` 中查找    ...mapActions(['foo', 'bar'])  }}

使用

vuex-stateshot 插件的使用方式是无侵入的,可插拔的,插件通过 registerModule API 动态创建了名为 vuexstateshot 的命名空间,来存储一些时间旅行需要用到的状态、方法。

安装

可以通过如下命令安装:

npm i vuex-stateshot -Soryarn add vuex-stateshot -S

创建插件

在创建插件(createPlugin)的时候可以指定有哪些模块(__MODULE__NAME__)以及模块下的哪些 actions/mutations 需要订阅,可选择性地传入 stateshot 的 History Options API

一个栗子 🌰

import { createPlugin } from 'vuex-stateshot'const subscribes = {  // The special root module key  rootModule: {    // The actions you want snapshot    actions: [],    // The mutations you want snapshot    mutations: []  },  // The custom module name  __MODULE__NAME__: {    // The actions you want snapshot    actions: [],    // The mutations you want snapshot    mutations: []  }}const options = {  maxLength: 20}const store = new Vuex.Store({  state: {},  ...,  plugins: [createPlugin(subscribes, options)]})

组件内部使用

在组件内部,可以通过 createNamespacedHelpers API,指定插件的命名空间 vuexstateshot 来映射组件绑定辅助函数

import { createNamespacedHelpers } from 'vuex'const { mapGetters, mapActions } = createNamespacedHelpers('vuexstateshot')export default {  ...,  computed: {    ...mapGetters([ 'undoCount', 'redoCount', 'hasUndo', 'hasRedo' ])  },  methods: {    ...mapActions(['undo', 'redo', 'reset'])  }}

Undo/Redo 方法

通过组件绑定辅助函数 mapActions,我们可以得到 undo/redo 方法,用来管理状态。

方法名描述回调
undo如果有可撤销的历史记录,则可以得到上一个记录的状态() => prevState
redo当执行过 undo 后,可以通过 redo 获取到最近一次 undo 过的历史记录() => nextState
reset清除历史记录-

历史记录状态

通过组件绑定辅助函数 mapGetters,我们可以得到 hasUndohasRedoundoCountredoCount 等状态,用来逻辑处理。

当触发一次状态同步, 此时 undoCount = 1/ hasUndo = true; 这是使用插件的一个开端; 当你调用一次 undo 后, 会有一次 redo 记录

状态描述类型初始值
undoCount可以撤销的历史记录计数.Number0
redoCount可以重做的历史记录技术Number0
hasUndo是否可以撤销Booleanfalse
hasRedo是否可以重做Booleanfalse

任意门

travel-door

当需求复杂时,可能我想撤销的不是一次 actions/mutations,而是需要撤销若干个 actions/mutations,对于这种需求,vuexstateshot 提供了自定义时机同步历史记录的方法,让多次复杂的操作“一键还原”。

Methods

名称描述回调
syncState自定义方法同步历史记录快照-
unsubscribeAction停止订阅 Actions-
subscribeAction重新订阅 Actions,通常搭配 unsubscribeAction 使用-
unsubscribe停止订阅 Mutations-
subscribe重新订阅 Mutations,通常搭配 unsubscribe 使用-

一个场景

假设我们订阅了 changeThemechangeColorchangeLang 三个 Actions,每个 Action 触发的时候,都会记录一次历史记录快照,可实际场景的需求是,需要这些状态全部改变后才同步历史记录快照,以便撤销时还原多个状态。

import { mapActions } from 'vuex'export default {  name: 'xxx',  ...  methods: {    ...mapActions([      'changeTheme',      'changeColor',      'changeLang'    ]),    handleChange () {      // 停止订阅 Actions      this.$stateshot.unsubscribeAction()      // 多次触发已订阅的 Actions      this.changeTheme('dark')      this.changeColor('#fa4')      this.changeTheme('zh')      // 重新订阅 Actions      this.$stateshot.subscribeAction()      // 同步历史记录快照      this.$stateshot.syncState()    }  }}

Tips: vuex-stateshot 同时提供了可以停止订阅 Actions/Mutations 的方法

在线 Demo

结语

在可视化工具项目中,我们已经在使用 vuex-stateshot 来管理历史状态了。性能表现良好,完美达成了“时间旅行”的需求。为用户提供了操作交互上的安全保障

感谢 @doodlewind 提供了出色的工具 stateshot 以及 Vuex 3.1.0+ 提供的 subscribeAction API,让操作变得有序可依。

vuex-stateshot 插件特性 ✨:

  • 无侵入、可插拔的插件调用
  • 严谨的逻辑业务状态
  • 稳定的撤销 & 重做方法
  • 任意时机同步快照的方法
  • 100% 测试场景覆盖率

资源