Implementation scheme of front-end snapshot

November 16, 2023 818hotness 0likes 0comments

introduction

snapshot is translated as a snapshot, which is used to directly obtain the status of the page at a certain runtime. The snapshot before and after the operation is stored, so that the page state can be redone and undone easily.

this article mainly introduces the principle of snapshot tool implementation and its use in the project.

Design

to implement the history, redo and undo of page state, you need to support the following properties and methods

Properties

  • History: stores the history of the page state, including the page initialization state to the previous page state
  • undo record: stores each redone operation record, which is used to recover after undo
  • current record: temporarily stores the current page state, which is mainly used to store it in the history after the next operation
  • Last time to insert data: the insertion interval is too small and additional processing is required
 // History
 recordList: string[] = []
 ​
 // cancel the record, which is used to redo
 redoList: string[] = []
 ​
 // the current record is temporarily stored in the currentRecord variable, and then stored in recordList when the user modifies it.
 currentRecord = ''
 ​
 // time when the data was last inserted
 time = 0

method

Storage history push

when the user acts, the history is updated. The following points need to be considered.

  • when the current operation time is less than 100 ms from the last insertion time, the current record is replaced and the add is canceled
  • if the current record has a value, the last operation was manually inserted, the previously cached current record was pushed into recordList , and the redo record needs to be emptied
  • Save the current state to the current record
  • set the maximum history capacity. When exceeded, delete the first inserted data
 push(record: PageData) {
   const nowTime = Date.now()
   // prevent adding repetitive time. When the adding interval is less than 100ms, replace the current record and cancel the add.
   if (this.time + 100 > nowTime) {
     try {
       // convert json to string storage
       this.currentRecord = JSON.stringify(record)
     } catch (error) {
       return false
     }
 ​
     return false
   }
 ​
   this.time = nowTime
 ​
   // determine whether the currentRecord record already exists, and store it in recordList.
   if (this.currentRecord) {
     this.recordList.push(this.currentRecord)
     // after adding records, the redo records should be emptied.
     this.redoList.splice(0, this.redoList.length)
   }
 ​
   // Save the current record
   this.currentRecord = JSON.stringify(record)
 ​
   // store a maximum of 30 records. If more than that, delete the previous records.
   if (this.recordList.length > 30) {
     this.recordList.unshift()
   }
   return true
 }

undo operation undo

when the user relies on the history list stored in push after the user's operation, and returns the page state to the previous state, you should pay attention to the following points:

  • when no history is available, return
  • directly.

  • retrieve the last stored data from the history
  • if the current record exists, it needs to be stored in the redo record list
  • the current record needs to be cleared to prevent repeated additions, because after undo, the push storage history method
  • will also be executed.

 undo() {
   // if there is no record, return false
   if (this.recordList.length === 0) {
     return null
   }
 ​
   const record = this.recordList.pop()
 ​
   // add the current record to the redo record
   if (this.currentRecord) {
     this.redoList.push(this.currentRecord)
   }
 ​
   // discard the current record to prevent repeated additions
   this.currentRecord = ''
   return JSON.parse(record as string) as PageData
 }

redo redo

when a user acts, relies on the redoList list to return the page state to the state before undo, you should pay attention to the following points:

  • when the redo record is not available, return
  • directly

  • retrieve the last stored data from the redo record
  • if the current record has a value, you need to put it in the history list
  • the current record needs to be cleared to prevent repeated additions, because after redoing, the push storage history method
  • will also be executed.

 redo() {
   //return false if there is no redo record
   if (this.redoList.length === 0) {
     return null
   }
 ​
   const record = this.redoList.pop()
   // add to the redo record
   if (this.currentRecord) {
     this.recordList.push(this.currentRecord)
   }
 ​
   // discard the current record to prevent repeated additions
   this.currentRecord = ''
   return JSON.parse(record as string) as PageData
 }

process demonstration

suppose the data list is [1, 2, 3, 4] , and the current attribute values are:

 recordList = [1, 2, 3]
 redoList = []
 currentRecord = 4

1, add 5 manually, the push method will be executed, and the attribute value will be

after execution.

 recordList = [1, 2, 3, 4]
 redoList = []
 currentRecord = 5

2. Perform undo once,then undo willbe executed first, and the attribute values after execution are respectively

 recordList = [1, 2, 3]
 redoList = [5]
 currentRecord = ''

Then executepush, put 4push in, and the attribute values after execution are respectively

 recordList = [1, 2, 3]
 redoList = [5]
 currentRecord = 4

3. If the second undo is executed, undo will be executed first, and the attribute value will be

after execution.

 recordList = [1, 2]
 redoList = [5, 4]
 currentRecord = ''

then execute push , insert 3 push , and the attribute value is

after execution.

 recordList = [1, 2]
 redoList = [5, 4]
 currentRecord = 3

4. If a redo is performed once, redo will be executed first, and the attribute value will be

after execution.

 recordList = [1, 2, 3]
 redoList = [5]
 currentRecord = ''

then execute push , enter 4 push , and the attribute value is

after execution.

 recordList = [1, 2, 3]
 redoList = [5]
 currentRecord = 4

5. Manually add 6,the push method will be executed, and the attribute values after execution are respectively

 recordList = [1, 2, 3, 4]
 redoList = []
 currentRecord = 6

complete code

 export default class Snapshot {
     //History
     recordList: string[] = []
 ​
     // cancel the record, which is used to redo
     redoList: string[] = []
 ​
     //The current record is temporarily stored in the currentRecord variable. When the user modifies it, it is stored in recordList.
     currentRecord = ''
 ​
     // time when the data was last inserted
     time = 0
 ​
     push(record: PageData) {
         const nowTime = Date.now()
         // prevent adding repetitive time. When the adding interval is less than 100ms, replace the current record and cancel the add.
         if (this.time + 100 > nowTime) {
             try {
                 // convert json to string storage
                 this.currentRecord = JSON.stringify(record)
             } catch (error) {
                 return false
             }
 ​
             return false
         }
 ​
         this.time = nowTime
 ​
         // determine whether the currentRecord record already exists, and store it in recordList.
         if (this.currentRecord) {
             this.recordList.push(this.currentRecord)
             // after adding records, the redo records should be emptied.
             this.redoList.splice(0, this.redoList.length)
         }
 ​
         try {
             // convert json to string storage
             this.currentRecord = JSON.stringify(record)
         } catch (error) {
             return
         }
 ​
         // store a maximum of 30 records. If more than that, delete the previous records.
         if (this.recordList.length > 30) {
             this.recordList.unshift()
         }
         return true
     }
 ​
     undo() {
         // if there is no record, return false
         if (this.recordList.length === 0) {
             return null
         }
 ​
         const record = this.recordList.pop()
 ​
         // add the current record to the redo record
         if (this.currentRecord) {
             this.redoList.push(this.currentRecord)
         }
 ​
         // discard the current record to prevent repeated additions
         this.currentRecord = ''
         return JSON.parse(record as string) as PageData
     }
 ​
     redo() {
         // if no record is redone, return false
         if (this.redoList.length === 0) {
             return null
         }
 ​
         const record = this.redoList.pop()
         // add to the redo record
         if (this.currentRecord) {
             this.recordList.push(this.currentRecord)
         }
 ​
         // discard the current record to prevent repeated additions
         this.currentRecord = ''
         return JSON.parse(record as string) as PageData
     }
 }
InterServer Web Hosting and VPS

Aaron

Hello, my name is Aaron and I am a freelance front-end developer

Comments