1. Introduction
- Preface
- Welcome back to the development of the B-side project. This week we will focus on coding the right-side settings part of the editor, completing component property settings, layer settings, and page settings. To avoid getting lost in business complexities, we'll cover several typical features and knowledge points.
- What you will gain:
- Image cropping implementation
- Leveraging Alibaba Cloud OSS image processing
- Re-uploading cropped image data
- Principles of creating Vue3 hooks
- Drag sorting implementation principles
- Analysis process of complex regular expressions
- Image cropping implementation
- Main topics:
- Implementing image cropping with Cropper.js
- Creating LayerList component and encoding InlineEdit component
- Developing a simple drag list solution, then replacing it with Vue Draggable Next
- Completing EditGroup encoding, learning problem analysis through pseudocode
- Building BackgroundProcessor component, learning regex analysis process
- Learning approach:
- First understand the principle, implement manually, then use mature third-party tools
- Use pseudocode or handy third-party tools to help analyze complex data transformations
2. Selecting an Image Cropping Tool
- Experience in finding suitable open-source libraries
- Search using Google or GitHub
- Use English keywords
- Criteria for evaluating open-source libraries
- Star count
- Issue count
- Release activity
- Check its DEMO
3. Using Cropper.js to Get Cropped Image Data
- Method on instance - getCroppedCanvas
- HTMLCanvasElement
- Two useful methods
- toDataURL - returns base64 encoded URL
- toBlob - File inherits Blob. const formData=new FormData(); formData.append(name,value,filename). When value is Blob, filename defaults to 'blob'. When value is File, filename is the file name
4. Layer Property Requirements Analysis
- Locking and hiding/showing layers, and selection
- Add more identifiers to components in editor.ts store
{
...
isLocked: boolean;
isHidden: boolean;
}
-
Toggle values via button clicks, use these in UI logic
-
Click to select sets currentElement
-
Image name editing
- Add more properties - layerName
- Switch between input and label when clicking layer name
- Add button responses - handling esc and enter keys
- Possibly abstract a common hook function - useKeyPress
- Response to clicks outside input area
- Possibly abstract a common hook function - useClickOutside
-
Dragging to change order
- Most challenging requirement, involving complex interaction
- Ultimately just changes the order in the components array in store
- Analysis begins during implementation
5. List Sorting Demonstration and Requirements Analysis
- New learning method
- Implement functionality manually first
- Then use mature third-party solutions
- Learn both principles and library usage
- Start with two DEMOs
- Vue Draggable Next: https://sortablejs.github.io/vue.draggable.next/#/simple
- React Sortable HOC: https://clauderic.github.io/react-sortable-hoc/
- List sorting phases
- Drag start (dragstart)
- Status change of dragged layer
- Float layer appears
- Drag movement (dragmove)
- Float layer follows mouse
- Item swapping occurs: when float layer bottom exceeds half of dragged item, swap happens
- Drop phase (drop)
- Float layer disappears
- Dragged layer status resets
- Data updates
- Drag start (dragstart)
6. Drag Sorting Function Implementation
- Phase One: Dragstart
- Dragged layer status change, conventional approach
- Add mouseDown event, check target element, add specific state
- Add mouseMove event, create floating layer identical to dragged element, set absolute positioning, update position with mouse coordinates
- Using HTML Drag feature
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations
- Browser default drag behavior: supports images, links, and selected text
- Other elements are not draggable by default
- To make draggable, set draggable='true'
- Use dragstart event to monitor drag start and set attributes
- Dragged layer status change, conventional approach
7. Weekly Summary
- Review process and key points
- Image cropping
- Selected Cropper.js as basic library
- Initialize Cropper area and get coordinates via events
- Approach one: Use Alibaba Cloud OSS for image cropping
- Approach two: Use Cropper.js to get image data
- getCroppedCanvas()->toBlob()->re-upload Blob object
- Layer list functionality
- Hide and lock - canvas element attribute design
- InlineEdit component
- Test-driven development
- Add common hooks - useKeyPress//useClickOutside
- Interface testing and optimization
- Drag sort principle
- Four steps of drag sort
- Set draggable attribute (browser handles drag effect)
- Monitor dragstart event (add drag start status)
- Monitor dragover event (complete data interaction at specific times)
- Monitor drop event (restore initial state)
- Use third-party library Vue Draggable Next for sorting
- Four steps of drag sort
- EditGroup property grouping component
- For complex issues, use flowcharts and pseudocode to clarify relationships before implementation
- Page settings panel
- Regex analysis and helpful tool: https://regexr.com/
- Development principles for property modification form components
- Image cropping
Chapter 19: Making Elements Move - Canvas Interaction Features
1. Introduction
- Preface
- For a visual editor, user usability and interaction are crucial, also one of the frontend challenges. These are perfect answers for interview questions like "What challenging work have you done in your projects?" In future job searches, consider highlighting this week's content.
- What you will gain
- Implementing drag-and-drop movement of layers
- Implementing drag-to-resize layers
- Complex shortcut key implementation
- Hotkeys.js
- Plugin concept
- Undo/redo implementation
- Unit tests
- Function throttling
- Many other optimization points
- Right-click menu implementation
- Functional component creation method
- Learning approach
- Use diagrams to help understand element interaction principles
- Don't forget unit testing for Vuex data operations
2. Shortcut Key Operation Requirements
- Element selection prerequisites are all under selected element conditions
- Copy layer - ⌘C/Ctrl+C: Create new data structure of selected element
- Paste layer - ⌘V/Ctrl+V: Add new element to components array
- Delete layer - Backspace/Delete: Delete selected element from components array
- Deselect - ESC: Set currentElement to null
- Element movement
- Move pixels - ↑↓→←: Update selected element props top/left values
- Move + pixels - Shift+↑↓→←: Update selected element props top/left values
- Undo/Redo
- Undo - ⌘Z/Ctrl+Z
- Redo - ⌘⇧Z/Ctrl+Shift+Z
- Useful key response library - HotKeys.js
- Project address: https://github.com/jaywcjlove/hotkeys
- Demo address: https://wangchujiang.com/hotkeys/
3. Undo/Redo - Optimization Points
- Evolution of function development
- Requirement analysis
- Full save
- Save only modified data
- Need what type of data (add/delete/update)
- Basic step one - Save specific data types after operation
- Basic step two - Set data operation pointer, undo moves forward, perform opposite operations on different data
- Basic step three - Add tests to verify basic functionality
- Interface testing - propose improvement suggestions
- Advanced feature - rollback multiple values per operation (move/resize)
- Improve updateComponent mutation to support updating multiple values
- Improve undo to accept arrays for rolling back multiple values
- Advanced feature - Support function debouncing for record addition
- Simple debounce function
- Cache old values initially modified
- Requirement analysis
- Possible optimizations
- Code structure optimization
- Optimize state structure
- Optimize location of helper functions
- Add unit tests
- Add shortcut keys
- Add page settings rollback function
- Look for bugs
- Code structure optimization
- Reflections
- For a simple editor, what are the ideas for implementing undo/redo?
- For a complex editor like VSCode, how would this be implemented?
4. Right-click Menu
- Requirement analysis
- On the editor area, right-click on an element to show a custom menu
- Generated menu has a series of operations
- Click corresponding options to complete operations, custom menu disappears
- Implementation method
- Intercept default right-click event in editor area
- Determine if click was on component element (check if e.target is within EditWrapper)
- Show custom menu (display:block) with operations, positioned at mouse (using e.clientX and e.clientY)
- Click to complete operations - reuse already supported mutations, close custom menu (display:none)
5. Weekly Summary
- Review process and key points
- Element dragging and moving
- Principle: Modify top, left values
- Note: Calculate gap value, mouse offset inside element
- Element dragging to resize
- Principle: Modify width, height (possibly top, left)
- Note: Different positions, calculation varies (relationship between mouse and element positions)
- Shortcut key implementation
- Principle: Trigger corresponding mutations on specific key presses
- hotkeys.js as third-party library
- Plugins concept
- Undo/Redo
- History record requirements and plan design
- Unit test basic operations
- Interface operation to find optimization points
- updateComponents can update multiple properties and values at once
- Function throttling implementation
- Right-click menu
- contextmenu event
- Use render function to mount component to node
- Make it plugin-like
- Element dragging and moving
Chapter 20: Backend Integration - Editor Backend Interface Integration
1. Introduction
- Preface
- This week we officially interact with the backend, making our work data persistently saved in the database. Also tackling common pain points of frontend-backend separation for SPA projects.
- Completed features
- Frontend-backend separation development and interface analysis
- Frontend mock server implementation
- Quick setup
- Custom interfaces and return data
- Using JWT for route protection
- Using AForm for form validation and source code analysis
- Adding general state
- Global loading state
- Fine-grained loading state
- Global error state
- Implementing login process and login state persistence
- Route permission verification
- Editor work operations
- Get work
- Save work
- Click save
- Auto-save
- Unsaved navigation prompt
- Knowledge points
- Vuex action
- JSON server
- Ant Design Vue
- AForm
- AFormItem
- useForm
- axios interceptors
- JWT
- Vue router hooks
- beforeEach
- beforeRouteLeave
- Higher-order functions!!
- Provided test interface
2. Frontend-Backend Separation Development
- Simple description of the process
- Define specifications
- RESTful protocol
- Document it - https://www.yuque.com/docs/share/4c353b03-5973-440b-9041-b7edbef5e6f6?#
- Version it - each upgrade clearly shows changes - https://shopify.dev/concepts/about-apis/versioning/release-notes
- Use tools for real-time viewing and running
- Postman: https://www.postman.com/
- Swagger: https://swagger.io/
- Development phase - frontend
- Use mock server
- Parallel development, independent of backend server, improving efficiency
- Integration phase
- Frontend switches directly to backend APIs for verification
- Define specifications
- Simple explanation of advantages
- Build lean teams
- Improve development efficiency
- Enhance code maintainability
3. Requirements and Interface Analysis
- Two types of interfaces
- Require special permissions (e.g., editor operations)
- No permissions needed (e.g., get popular posters)
- Permission acquisition enterface (user)
- Using phone number + verification code for login
- Get verification code - POST /users/genVeriCode
- Login interface - get token - POST /users/loginByPhoneNumber
- Use token to access permission-restricted interfaces - e.g., get user info - GET /api/users/getUserInfo
- Use authorization Header - add Bearer + token info
- Editor work operations interface, require permissions
- Create work - POST /works
- Query work - GET /works
- Save work - PATCH /works/${id}
- Publish work - POST /works/publish/${id}
4. Mock Server Selection and Setup
- Preface
- Should we use express, koa, egg.js, etc. for mature frameworks?
- Features of a good Mock Server
- Quick setup
- Support standard Restful operations and routing rules
- /templates - get all data
- /templates/${id} - get one piece of data
- Advanced extensions - custom routes, middleware, etc.
- Introducing JSON Server
- Installation
- npm install --save-dev json-server
- Startup
- npx json-server --watch db.json
5. Simple Principle of Token-based Permission Management
- Token is stateless, no server records needed. Each request carries a token, which servers use to verify authenticity.
- Token composition: Through specific encryption algorithms, user login information (e.g., userId) and expiration time are stored in an encrypted string.
- Feel it at the JSON Web Token official site: https://jwt.io/
Chapter 21: Backend Integration - Completing Remaining Features
1. Introduction
- Preface
- Our application's overall structure is complete. The remaining pages involve repetitive work. This week focuses on unique features less common in practice, broadening knowledge and learning several tool principles.
- Completed features
- Complete work publishing workflow
- Screenshot editor area
- Upload screenshot
- Save work and create channel
- Channel window after publish
- Manage channels - create and delete
- Use hook function to integrate publishing workflow - usePublishWork
- Generate QR code for channel links
- Copy text to clipboard functionality
- Hook function evolution process
- Home load more
- Work page pagination
- Download file principle and coding process
- Complete work publishing workflow
- Feature points
- html2canvas
- Basic usage
- Troubleshooting
- qrcode - generate QR codes
- Clipboard.js - copy text to clipboard
- Basic usage
- Principle
- useLoadMore - hook function evolution journey
- Support click load more
- Support infinite scroll
- Support pagination
- Frontend file download principle
- Same-origin files
- Cross-origin files
- FileSaver.js usage and principle
- html2canvas
2. Understanding window.devicePixelRatio
- Device pixels/physical pixels
- Device pixels also known as **physical** pixels, they are the smallest physical parts of a display device. The total number of physical pixels is fixed on the same device.
- Independent pixels/css pixels
- Css pixels are an abstract unit mainly used in browsers to precisely measure (determine) content on web pages.
- Css pixels are called device-independent pixels (device-independent pixels), abbreviated as "DIPs".
- Under standard display density, one css pixel corresponds to one device pixel.
- window.devicePixelRatio
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/devicePixelRatio
- Returns the ratio of physical pixel resolution to CSS pixel resolution of the current display device. Simply put, it tells browsers how many actual screen pixels to use to draw a single CSS pixel.
- Therefore, under standard screens, devicePixelRatio should be **1**
- Exception
- Retina displays use more screen pixels to draw the same objects for clearer images. devicePixelRatio is **2**.
- Although our elements are 375px CSS size, because Apple uses Retina screens, it uses twice the CSS size of device pixels for rendering, hence the final image size is 750px.
- html2canvas handling
- Documentation: https://html2canvas.hertzen.com/configuration/ scale property
3. HTML2Canvas Screenshot Principle
- Purpose: A canvas element with drawn HTML nodes
- Limitation: Canvas cannot add specific HTML nodes, it's just a canvas
- Through canvas.getContext("2d"), we get the 2D rendering context to draw shapes, text, images, and other objects.
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D
- Rectangle - fillRect()
- Text - fillText()
- Image - drawImage()
- Etc...
- SVG to save us
- Scalable Vector Graphics (SVG) is a markup language based on XML for describing 2D vector graphics.
- SVG has a magical element called foreignObject
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/foreignObject
- foreignObject allows including elements from different XML namespaces. In browser contexts, likely XHTML/HTML
- Solution approach
- Create canvas element
- Create SVG file using Blob constructor
- Fill foreignObject with SVG values, then HTML nodes to be copied
- Create image tag, set image.src = URL.createObjectURL(svg)
- After image loads, call canvas.drawImage() to draw picture on canvas
4. Clipboard Copy Mechanism
- Looks simple, but due to different browser implementations and hacks, it's quite messy
- Modern method - Clipboard API
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/API/Clipboard_API
- Still in working draft stage, browser compatibility needs improvement
- Alternative - document.execCommand() method
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
- Not just for copying, provides various functions for editable areas
- Modern method - Clipboard API
- Analysis of document.execCommand('copy') solution
- Manually create editable element like textarea, set its value to copy value
- Insert into page, call select method on textarea to highlight value
- Call document.execCommand('copy')
- Special note: textarea must be invisible using special styles
- Finally remove textarea node
5. B端 Remaining Requirements Analysis
- Preface
- The remaining requirements are not difficult. After solving general issues, remaining tasks are just listing features and sending asynchronous requests
- Homepage
- Display templates list (already done)
- Click load more (can it be abstracted into a Hooks function?)
- Corresponding interface: /api/templates?pageIndex=${page}&pageSize=${size}&title=${title}
- Click search
- Corresponding interface: /api/templates?pageIndex=${page}&pageSize=${size}&title=${title}
- Display latest works - can reuse work detail page
- Work Detail Page
- Click create
- Corresponding interface: POST /api/works/copy/${id}
- Download image
- Click create
- My Works
- Search
- Corresponding interface (my templates): /api/works?pageIndex=${page}&pageSize=${size}&title=${title}&isTemplate=1
- Corresponding interface (my works): /api/works?pageIndex=${page}&pageSize=${size}&title=${title}&isTemplate=0
- Pagination - ant-design-vue pagination component
- Series of operations above
- Delete: DELETE /api/works/${id}
- Copy: POST /api/works/copy/${id}
- Transfer: POST /api/works/transfer/${id}/${cellphone}
- Download image
6. File Download Principle
- Anchor tag
- Creates hyperlinks to other webpages, files, locations within the same page, email addresses, or any other URL
- Special attribute of anchor tag: download
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a
- Indicates browser downloads URL instead of navigating, prompting user to save as local file
- Another special attribute of anchor tag: rel
- Specifies relationship between target and link objects
- noopener is important for web security
- When using target='_blank', new page window has opener property pointing to previous page's window, so the new page gains control over the previous page
- We simulate this process for downloading
- Create anchor tag
- Set href and download attributes
- Trigger anchor click event
- Download attribute only works for same-origin URLs
- Use FileSaver.js for downloading
- Documentation: https://github.com/eligrey/FileSaver.js/
- Use HTTP special response header to trigger browser auto-download
- Documentation: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Disposition
- Content-Disposition - best download method, requires server support, no JavaScript needed, add to HTTP header
- Content-Type: 'application/octet-stream; charset=utf-8'
- Content-Disposition: attachment; filename="filename.jpg";
7. Weekly Summary
- Review process and key points
- html2canvas - DOM node screenshot tool
- Basic usage
- Caveats in use (doesn't support box-shadow, images need cross-origin access)
- html2canvas principle
- Use svg foreignObject tag to insert corresponding DOM elements and create file
- Create image, use corresponding svg file, use canvas.getContext('2d').drawImage() method
- qrcode - generate QR codes
- Basic operation
- Pay attention: watch issues with reactive arrays, how to get new and old values
- clipboard.js - copy content to clipboard
- Basic usage
- clipboard.js principle
- Modern ClipboardAPI - navigator.clipboard.writeText
- Better compatibility - document.execCommand('copy')
- Create textarea node, set invisible position
- Set its value, call select to highlight, then document.execCommand('copy')
- useLoadMore transformation
- Implement basic functionality supporting load more and infinite scroll
- Add previous/next page functions
- Implement pagination selection
- FileSaver.js - browser-side file download method
- Browser download principle
- Same-origin: use anchor tag's download attribute
- Cross-origin: send async request, return Blob, store Blob in URL.createObjectURL(), then click download
- Server-side download principle
- Use content-disposition response header, set value to attachment;filename="filename.jpg"
- FileSaver.js analysis
- Simple and practical
- Source code analysis - add more polyfill code - e.g., using msSaveOrOpenBlob or FileReader methods
- Browser download principle
- html2canvas - DOM node screenshot tool