Technology base
Use vue3+ts(x) as the base
sum
- Technology serves business needs
- Technology selection is scenario-specific
- Technology needs to iterate as the business changes
Matters needing attention and specifications
Project engineering specification
-
Use ls-lint to verify the name of the component. The component name must start with uppercase. Change config and ignorecase = False in the.git file to prevent file case problems
-
You can use git-cz to make git commit
<type>(<scope>): <subject><BLANK LINE><body><BLANK LINE><footer>
Copy the code
- Code in projects uses gitHooks for prettier and ESLint to ensure consistency across IDE code styles (vsCode with prettier-ESLint) Automatic formatting), project depend on @ commitlint, eslint, prettier, lint – staged, stylelint, @ ls – lint/ls – lint and various es project, ts, suggested the pre configuration file reference ant – pro initialization program
{
"gitHooks": {
"pre-commit": "npx @ls-lint/ls-lint && lint-staged"."commit-msg": "commitlint -e $GIT_PARAMS"
},
"lint-staged": {
"*.ts? (x)": [
"npm run lint-staged:js"."prettier --parser=typescript --write"."git add"]."*.{js,jsx}": ["vue-cli-service lint --fix"."prettier --write"."git add"]."*.{vue,css,scss}": ["stylelint --fix"."prettier --write"."git add"]}}Copy the code
Code specification
-
Code method comments and file comments (you can use koroFileHeader in VScode)
-
Enums Enumeration directory (farewell to magic numbers), Composables API directory (Data, events, public methods), Types Interface directory (Interface unified management and public), API (Request collection, API capability Encapsulation – Adding Exceptions and Loading)
-
Project components are automatically registered and business components are loaded on demand
// Make a distinction between a common component and a project built-in component. Common components are loaded on demand, and built-in components are automatically registered.
// Component type Label type Component Function type Component
const context = require.context('./components'.true./\.tsx$/)
const componentMap = new Map()
context.keys().forEach(k= > {
const componentConfig = context(k).default
if (componentMap.has(componentConfig.name)) {
console.warn('componentName has used')}else {
app.component(componentConfig.name, componentConfig)
componentMap.set(componentConfig.name, componentConfig.name)
}
})
app.mount('#app')
// Function mount
app.config.globalProperties = {
$message: Message,
}
Copy the code
-
Use MITT for component communication
-
Business component directory definition, component file, style.module. SCSS file, sub-component file Components folder (optional), composite API method Component Function method extract file (optional)
-
UI component behavior controls, such as modal boxes and prompt boxes, are loaded into the body using function mode calls, otherwise the Z-index of the UI is affected by the z-index of the parent node
TSX practice in VUE3
Ins and outs
why ts
. All the features of TS are well suited for this scenario during long-term maintenance and iteration on large projects
Why TSX (JSX and Template syntax)
Template Language Features
-
Template syntax is more convenient and easy to use v-if, V-for
-
Vue3 itself has been optimized for template compilation by marking blocks and method caching. Examples of diff’s optimization can be seen in the link vue3 template. Because of the template language, its tag fixability can easily identify code blocks and vue variables to mark and method caching. Reducing object creation This is the basis for improving the efficiency of diFF algorithms and is simpler than variable recognition blocks in JSX. Compilation optimization and other scenarios such as nested nodes and so on. Watch the video on performance improvement in particular.
-
Disadvantages: There is not enough support for THE TS type in the template language. Of course, the official plug-in can solve this problem by turning the template into TS and sending ts back to the template
<! -- Performance compilation, sample template -->
<div>
<span>Hello World!</span>
<span>Hello World!</span>
<span>{{mes}}</span>
<span @click="handlClick">click</span>
</div>
Copy the code
// For example, you can go to the website for an interview
import {
createVNode as _createVNode,
toDisplayString as _toDisplayString,
openBlock as _openBlock,
createBlock as _createBlock,
} from 'vue'
const _hoisted_1 = /*#__PURE__*/ _createVNode(
'span'.null.'Hello World! ',
-1 /* HOISTED */.)const _hoisted_2 = /*#__PURE__*/ _createVNode(
'span'.null.'Hello World! ',
-1 /* HOISTED */.)export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (
_openBlock(),
_createBlock('div'.null, [
_hoisted_1,
_hoisted_2,
_createVNode('span'.null, _toDisplayString(_ctx.mes), 1 /* TEXT */),
_createVNode(
'span',
{
onClick:
_cache[1] ||
(_cache[1] = (. args) = >_ctx.handlClick && _ctx.handlClick(... args)), },'click',),]))}// Check the console for the AST
Copy the code
JSX syntax features
- Why use JSX is a question not only for me, but also for the react-Hook open source authors
- Official presentation of consistency of UI and logic
- In JSX, you can not only v-show, but also add more styles, colors and so on
- Understanding consistent map traversal is obviously a little easier to understand than v-for in js’s own logic
- Disadvantage: When using JSX in React, it is easy to cause the parent component to render and the child component to render repeatedly. When the component hierarchy is deep, the render function will be triggered repeatedly when the data changes. Hooks such as useMemo and useCallback are also provided to implement manual caching
Technology selection for JSX reasons
- JSX has a comparative advantage in terms of syntax checking, functional programming, and unit testing
- The flexibility itself is really common and useful in large projects, and atomization and reuse work well in projects like Ant-Design-Vue
- Consistency, front-end ecology now the most people laugh at the point is the frame dialect, a frame a dialect, this is not a very good thing. Why does VUe3 introduce an API that is similar to react-Hook, and open source authors also pay attention to such a scene of front-end ecological co-construction, which is also good for team personal development. If the TSX of VuE3 is converted to React-hook, the cost of recognition is very low, and vice versa
Vue3 has officially begun
The core module
- Response model
- Compilation model
- Rendering model
The key changes
- Performance improvement, compilation and rendering performance optimization,proxy can hijack the property to directly get the property
- Tree-shaking support, vUE package modules are introduced on demand
- Composition API, composition API improves reuse
- Fragments do not need to write roots, which Angular and React have long had
- Better TS support, more and more demands for large projects
- Render API
The key API – setup
-
The reason why we use the new option is because we can do vuE3 without using SETUP, When Hook was proposed in React, the official explanation was the same, and it was not recommended to change all previous classes into hooks, in the case that the project has matured. Whether it’s hook or setup, if you use a new writing method, you can actually reduce a lot of code in large projects, make methods common, and reduce lifecycle operations
-
React compares code volume and method ease of use
// The new method has more advantages in the amount of code and logical cutting
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
// Equivalent to componentDidMount and componentDidUpdate:
useEffect(() = > {
// Update the page title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<>
Count: {count}
<button onClick={()= > setCount(initialCount)}>Reset</button>
<button onClick={()= > setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={()= > setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
Copy the code
// The old class is redundant in bind this and the lifecycle
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
// This binding is necessary in order to use 'this' in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState(state= > ({
count: state.count+1
}));
}
componentDidMount(){}componentWillUnmount(){}render() {
return (
<div>
<h1 onClick={this.handleClick}>Hello, world!</h1>
</div>); }}Copy the code
- vue3-setup
Setup is the first place in VUe3, you can’t use data or any other option in this hook function and that’s why it’s intentional, that’s why you can’t use this inside of it and that’s exactly why you use this. To get the data attribute, data has not yet been executed. If you need to use the mount method, you can use the following example to get this in setup, using this.&message({}).
watchEffect
- WatchEffect has no intermediate state. It listens for all property changes and executes immediately. The complex writing in VUE2 can be implemented with less code in the current API
// VUE2 needs to define three code blocks to listen for attribute ID changes
export default {
props: ["id"]
methods: {handleChange(){
console.log("xxx")}}watch: {id:'handleChange'}}Copy the code
// Vue3 requires a small amount of code
export default defineComponent({
setup(props) {
watchEffect(() = >{
console.log(props.id)
})
},
})
Copy the code
watch
- Watch has an intermediate state, does not trigger a callback if the final state does not change, is lazy, can accept multiple values, and can get oldValue, but the accepted argument must be either responsive or an execution function
export default defineComponent({
setup() {
// Listen for a getter
const state = reactive({ count: 0 })
watch(
() = > state.count,
(count, prevCount) = > {
/ *... * /})// Listen directly to a ref
const count = ref(0)
watch(count, (count, prevCount) = > {
/ *... * /})}})Copy the code
ref
- Reactive objects are recommended
reactive
- It is not suitable for return in composite API. The reasons are described below
toRefs
- ToRefs are useful when returning a reactive object from a composite function, which can be converted back to reactive, but also loses its meaning when used in combination with multiple composite apis, as described below
function useFeatureX() {
const state = reactive({
foo: 1.bar: 2
})
// Logical running state
// Convert to ref when returned
return toRefs(state)
}
export default {
setup() {
// Can destroy the structure without losing responsiveness
const { foo, bar } = useFeatureX()
return {
foo,
bar
}
}
}
Copy the code
The core question is why and how to use composite apis
The biggest question is why Use Composition API
- Method reuse allows code logic to be shared in large projects, reducing object creation
- Problem of code block distribution: When there are many lines of code, data, properties, computing properties and watch are all distributed in different areas. It is obvious that the same data has to be operated, but the development experience is not good
- Vue2 implements common methods such as mixins,extend, prototype mount, and component registration. However, the variable naming and development experience are not good, just like the previous approach to vuE2. There are also solutions such as naming rules, V-slots, etc., which are not very convenient.
// Implementation of VUe2
export default {
mixins:[minxA,minB],
render() {
const {x,y} = this
// We don't know where x and y come from, and we have a name conflict problem
return <>{x}{y}</>}},Copy the code
// Implementation of vue3
export default {
setup(){
const {x} = UseX()
// This will resolve the name conflict problem
const {x:y} = UseY()
return{
x,
y
}
},
render() {
const {x,y} = this
// Where x and y come from
return <>{x}{y}</>}},Copy the code
- Use standard
The business component merges the associated composite API, declares it in a new file export method, or currently outside the component function
Global and module shared methods are extracted under the Composables directory
// The example code is messy. A,b, and C are mixed up and the deconstructing is not clear
export default defineComponent({
setup(){
const a = ref(null)
const b = ref(null)
const changeA = () = >{}const c = ref(null)
const changeB = () = >{}const changeC = () = >{
}
watchEffect(() = >{
console.log(a.value)
})
return{
dom
}
},
})
Copy the code
// Good specification example code is clear
/ * * *@name: UseA
* @msg: a Related operations */
function UseA(){
const a = ref(null)
const changeA = () = >{
}
watchEffect(() = >{
changeA()
})
return{
a
}
}
/ * * *@name: UseB
* @msg: b Related operations */
function UseB(){
const b= ref(null)
const changeB = () = >{
}
watchEffect(() = >{
changeB()
})
return{
b
}
}
export default defineComponent({
setup(){
// Clear structure
const {a} = UseA()
const {b} = UseB()
return{
a,
b
}
},
})
Copy the code
Examples from vuE3
- Access to the dom
export default defineComponent({
setup(){
const dom = ref(null)
// Must return the dom
return{
dom
}
},
render() {
return<> ref <div ref="dom"> <div> </>},})Copy the code
- V – if instructions
export default defineComponent({
render() {
// Ternary operation
const comp = flag ? CompA : CompB
return <>{comp}</>}})Copy the code
- V – for instructions
export default defineComponent({
render() {
return (
<>
<ul>
{menuList.map(item => (
<li
onClick={()= > {
close(item)
}}
>
<span>{item.name}</span>
</li>
))}
</ul>
</>)}})Copy the code
- V – show commands
export default defineComponent({
render() {
const style = flag? "display:block":"display:none"
return (
<div style={style}>
</div>)}})Copy the code
- ClassModule, style Scope implements style isolation
// The key is that the file suffix is module.scss
import styles from './index.module.scss'
export default defineComponent({
render() {
return (
// Use styles objects to get references
<div style={style['yxt']} >
</div>)}})Copy the code
- classNames
/ / more than one class
import classNames from 'classnames'
import styles from './index.module.scss'
export default defineComponent({
render() {
// Use the classNames method to merge styles
const content = classNames(
styles['item'],
styles['item-isActive'],)return (
<div class ={content}>
</div>)}})Copy the code
- The dynamic of the class
// Render different classes according to variables
import classNames from 'classnames'
import styles from './index.module.scss'
export default defineComponent({
render() {
// Use a function variable to control the style, which can also be associated with data in setup
let pptClass = () = >{
if(flag){
return styles['item']}else{
return styles['item-isActive']}}return (
<div class={pptClass()}>
</div>)}})Copy the code
- event
export default defineComponent({
render() {
// Both event and map loop arguments can be passed
const handleClick = (The event, arg?) = >{}
return (
<div onClick={(event)= > {handleClick()}}>
</div>)}})Copy the code
- Function component
Extend (); // Extend ()
import { createApp } from 'vue'
import message from './Message'
// Id increments
let count = 0
export enum Types {
SUCCESS = 'success',
ERROR = 'error',
WARNING = 'warning',}// We just need to mount Message or call it by referring to the Message method separately
export const Message = (options: Options) = > {
const div = document.createElement('div')
const id = `yxt-message-${count + 1}`
div.setAttribute('id', id)
document.body.appendChild(div)
const instance = createApp(message, {
type: options.type,
content: options.content,
id: id,
})
// Mount to body
document.body.appendChild(instance.mount(` #${id}`).$el as HTMLElement)
count++
}
Copy the code
- Use of slots with rendering
// Reference component
export default defineComponent({
render() {
const defaults = () = > {
return <div>{pptNote}</div>
}
return (
<>
<div class={styles.pptDetail}>
<yxt-tabs>
<yxt-tab-pane
title="Note"
scopedSlots={defaults}
></yxt-tab-pane>
</yxt-tabs>
</div>
</>)}})// Subcomponent rendering
export default defineComponent({
render() {
if (this.$props.scopedSlots) {
return this.$props.scopedSlots()
} else {
return <></>}}},Copy the code
- Get this in setup
import { ComponentInternalInstance, getCurrentInstance } from 'vue'
/ * * *@name: UseThis
* @msgGet this property in setup to make it easier to call */ with $xx
export function UseThis() {
const { proxy } = getCurrentInstance() as ComponentInternalInstance
return {
proxy: proxy as any,}}Copy the code
The principle of
- The logical UI is controlled by JS
- Parent and child components pass props, render, and dynamically bind (first priority)
- Event communication uses MITT
- Method reuse using the Composition API (as long as there are two or more repeating methods)
Data address
- Vue3 official document [vue3] (www.vue3js.cn/docs/zh/api…
- Vue3 especially big teaching video [vue3] (www.bilibili.com/video/BV1rC…
- Vue3 Beta official live full version [vue3] (www.bilibili.com/video/BV1Tg…
- Vue3 especially big share video [vue3] (www.bilibili.com/video/BV1qC…
- The react video/react (www.youtube.com/watch?v=dpw…