There are too many similarities to the basics of VUE2 no longer documented
1. Componentized development
1. Father to Son:
App.vue
<son msg="hello world"></son>
Copy the code
son.vue
export default {
// props: ['msg']
props: {
msg: {
type: String,
default: "default"
}
}
}
Copy the code
2. The father
App.vue
< span style =" box-sizing: border-box; color: RGB (50, 50, 50); line-height: 21px; font-size: 13px! Important; white-space: inherit! Important;" { add() { this.counter++ } }, } </script>Copy the code
Son.vue
<template>
<button @click="increment">+1</button>
</template>
<script>
export default {
emits: ['add', 'sub'],
methods: {
increment() {
this.$emit('add')
}
}
}
</script>
Copy the code
3. The dojo.provide and inject
Used to pass data between the root component and its descendants
App.vue
<template> <father></father> <button @click="addName">+name</button> </template> <script> export default { provide() { Return {name: 'yogln', MSG: this.msg, names: computed(() => this.names) // Use computed to do the response}}, data() {return {MSG: 'hello world', names: ['abc', 'cba', 'nba'] } }, methods: { addName() { this.names.push('why') } }, } </script>Copy the code
Son.vue
<script>
export default {
inject: ["name", "msg", "names"]
}
</script>
Copy the code
4. Event bus
Since Vue cancelled events such as $on and $off, the third-party library MITT can only be relied on for communication between non-parent and child components. Install dependencies
npm i mitt
Copy the code
Encapsulation mitt. Js
import mitt from 'mitt'
export default mitt()
Copy the code
Usage:
The sender:
<script> import emitter from './utils/eventBus' export default { methods: {btnClick() {emitter.log (' btnClick ') emitter.emit(' yogln ', 'yogln ')}},} </script>Copy the code
The receiving party:
<script>
import emitter from './utils/eventBus'
export default {
created() {
emitter.on('yogln', msg => {
console.log(msg)
})
emitter.on('*', (type, msg) => {
console.log(type, msg)
})
},
}
</script>
Copy the code
5. Use of a named slot
NavBar.vue
<div class="nav-bar">
<div class="left">
<slot name="left"></slot>
</div>
<div class="center">
<slot name="center"></slot>
</div>
<div class="right">
<slot name="right"></slot>
</div>
</div>
Copy the code
App.vue
<div> <nav-bar> <template v-slot:center> <button> button </button> </template> <template #right> <span> </span> </nav-bar> </div>Copy the code
Note: V-slot: can be shortened to #
The dynamic slot
We can use v-slot:[dynamicSlotName] to dynamically bind a name
< the template v - slot = [name] >... < / template >Copy the code
6. Use of scope slots
Render scope
In Vue there is the concept of rendering scope:
- Everything in the parent template is compiled at the parent scope;
- Everything in a subtemplate is compiled in the subscope;
Case study:
App.vue
<show :names="names">
<template #="slotProps">
<button>{{slotProps.item}}</button>
</template>
</show>
Copy the code
Show.vue
<template v-for="(item, index) in names" :key="item">
<slot :item="item" :index="index"></slot>
</template>
Copy the code
Mixed use of scoped and named slots
App.vue
<template>
<show :names="names">
<template #yogln="slotProps">
<button>{{slotProps.item}}</button>
</template>
</show>
</template>
Copy the code
Show.vue
<template>
<template v-for="(item, index) in names" :key="item">
<slot name="yogln" :item="item" :index="index"></slot>
</template>
</template>
Copy the code
Abbreviation for exclusive default slot
App.vue
<template>
<show :names="names" #="slotProps">
<button>{{slotProps.item}}</button>
</show>
</template>
Copy the code
Pay attention to
If we have a default slot and a named slot, write with the full template, and always use the full
based syntax for all slots whenever multiple slots are present:
7. Dynamic components
Dynamic components are implemented using a component with a special attribute is. Note that currentTab is a component
<component :is="currentTab"></component>
Copy the code
Dynamic components pass parameters just as they pass parameters
<component :is="currentTab" :age="18"></component>
Copy the code
Notice the age is added here:
Represents a Number type of 18, not add:
Is a string
8.keep-alive
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
Copy the code
Keep-alive has several properties:
- The include – string | RegExp | Array. Only components with matching names are cached;
- Exclude – string | RegExp | Array. Any component with a matching name will not be cached;
- Max – number | string. The maximum number of component instances that can be cached. Once this number is reached, none of the recently accessed instances in the cached component will be destroyed.
Include and exclude Prop allow components to conditionally cache:
- Both can be represented as comma-separated strings, regular expressions, or arrays;
- The match first checks the name option of the component itself
9. Use of asynchronous components
Referring to a resource through the Import() function subcontracts the package
import("./utils/math.js").then(res= > res.sum(20.30))
import("./utils/math.js").then({sum})
Copy the code
Subcontracting without routing packaging
<script> import { defineAsyncComponent } from 'vue' const AsyncAbout = defineAsyncComponent(() => import('./About.vue')) export default { components: { AsyncAbout } } </script>Copy the code
Another way to write:
<script> const AsyncAbout = defineAsyncComponent({ loader: () => import('./About.vue') // loadingCompoent: When Loading / / load components according to Loading components / / errorCompoent: error displayed when the component / / delay: 2000 / / loadingComponent shows delay before the event}) < / script >Copy the code
Use of suspense and asynchronous components
<suspense>
<template #default>
<async-about></async-about>
</template>
<template #fallback>
<loading></loading>
</template>
</suspense>
Copy the code
The suspense component is currently in its experimental phase
10.$refs
,$parent
,$root
,$el
<home ref="homeRef"></home>
Copy the code
This calls the data and methods of the component
$parent refers to the parent component
$root References the root component
This.$refs.homeref.$el gets all tags in the component
Note: this.$children has been removed from vue3
11. Component life cycle
Component usesleep-alive
There are also two life cycles:activited
anddeactivited
12. V-model of the component
The basic use
App.vue
<my-input v-model="message"></my-input :="message" @update:modelValue="message =" $event"></my-inputCopy the code
MyInput.vue
<template>
<h2>modelValue: {{modelValue}}</h2>
<input :value="modelValue" @input="inputChange">
</template>
<script>
export default {
props: {
modelValue: {
type: String
}
},
emits: ["update:modelValue"],
methods: {
inputChange(event) {
this.$emit("update:modelValue", event.target.value)
}
},
}
</script>
Copy the code
Note: modelValue is modifiable by passingv-model:title="title"
Bind input by calculating properties
<input :value="value" @input="inputChange">
Copy the code
computed: {
value: {
set(value) {
this.$emit("update:modelValue", value)
},
get() {
return this.modelValue
}
}
}
Copy the code
Different parameters are passed through an input component
App.vue
<template>
<my-input v-model="message" v-model:title="title"></my-input>
<h2>modelValue: {{message}}</h2>
<h2>title: {{title}}</h2>
</template>
<script>
import MyInput from './MyInput2.vue'
export default {
components: {
MyInput
},
data() {
return {
message: 'message',
title: 'title'
}
},
}
</script>
Copy the code
Myinput.vue
<template>
<input v-model="value">
<input v-model="titleValue">
</template>
<script>
export default {
props: {
modelValue: String,
title: String
},
emits: ["update:modelValue", "update:title"],
computed: {
value: {
set(value) {
this.$emit("update:modelValue", value)
},
get() {
return this.modelValue
}
},
titleValue: {
set(titleValue) {
this.$emit("update:title", titleValue)
},
get() {
return this.title
}
}
}
}
</script>
Copy the code
Second, the animation
1. Basic use of animation
<template> <div> <button @click="isShow = ! < span style =" box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 13px! Important; word-break: inherit! Important;" <style scoped> .yogln-enter-from, .yogln-leave-to { opacity: 0; ·}. Yogln-enter -to,. Yogln-leave -from {opacity: 1; } .yogln-enter-active, .yogln-leave-active { transition: opacity 1s ease; } </style>Copy the code
When inserting or removing elements contained in the Transition component, Vue will do the following:
- Automatically sniffs if CSS transitions or animations are applied to the target element, and if so, adds/removes CSS class names when appropriate;
- If the Transition component provides JavaScript hook functions, these hook functions will be called at the appropriate time;
- If no JavaScript hooks are found and no CSS transitions/animations are detected, DOM inserts and deletes are performed immediately;
We can see that there are many classes mentioned above, and Vue is actually an animation that helps us toggle between these classes:
- V-enter -from: Defines the start state of entering the transition. It takes effect before the element is inserted and is removed in the next frame after the element is inserted.
- V-enter -active: indicates the status when the transition takes effect. Applied throughout the transition phase, before the element is inserted, and removed after the transition/motion is complete. This class can be used to define the process time, delay, and curve functions for entering the transition.
- V-enter -to: Defines the end state of the enter transition. The next frame takes effect after the element is inserted (at the same time v-enter-from is removed), and after the transition/animation is complete.
- V-leave-from: Defines the start state of the leave transition. It takes effect as soon as the exit transition is triggered, and the next frame is removed.
- V-leave-active: Defines the status when the leave transition takes effect. Applied throughout the exit transition phase, effective as soon as the exit transition is triggered and removed after the transition/animation is complete. This class can be used to define the process time, delay and curve functions for leaving the transition.
- V-leave-to: The end of the transition. The next frame takes effect after the leave transition is triggered (at the same time v-leave-From is deleted) and is removed after the transition/animation is complete.
When to add a class and the naming convention
The naming rules for class names are as follows:
- If we’re using a transition without a name, then all classes are prefixed with V – by default;
- If we add a name attribute, for example, then all classes will start with why-;
2. Basic use of CSS animation
<template>
<div>
<div class=""><button @click="isShow = ! isShow">Show/Hide</button></div>
<transition name="yogln">
<h2 class="title" v-if="isShow">Hello world</h2>
</transition>
</div>
</template>
<style scoped>
.title {
width: 200px;
margin: 0 auto;
}
.yogln-enter-active {
animation: bounce 1s;
}
.yogln-leave-active {
animation: bounce 1s reverse;
}
@keyframes bounce {
0% {
transform: scale(0);
}
50% {
transform: scale(1.2);
}
100% {
transform: scale(1); }}</style>
Copy the code
Note:h2
The label is a block-level element that occupies a single row and can have unexpected effects if the width is not changed
3. Use transitions with animations
The type attribute
The transition animation and the transform can be used together, but some problems can arise if the time of the two is inconsistent. Such as:
.yogln-enter-active..yogln-leave-active {
transition: opacity 2s ease;
}
.yogln-enter-active {
animation: bounce 1s;
}
.yogln-leave-active {
animation: bounce 1s reverse;
}
Copy the code
The animation will end but the transition will not. You can specify the transition type property to specify the execution time of the animation property
<transition name="yogln" type="animation">
<h2 class="title" v-if="isShow">Hello world</h2>
</transition>
Copy the code
Duration properties
Duration specifies the duration of the animation
<transition name="yogln" type="animation" :duration="1000">
<h2 class="title" v-if="isShow">Hello world</h2>
</transition>
Copy the code
Duration can also be written as an object
<transition name="yogln"
type="animation"
:duration="{enter: 800,leave: 1000}">
<h2 class="title" v-if="isShow">Hello world</h2>
</transition>
Copy the code
Mode attribute
When toggling between two tabs or two components, the default effect is ugly, we can use the mode property, which has two values
- In-out: Specifies that the component to be displayed is in and the component that is not displayed is out
- Out-in: Specifies that the component to be displayed is out before the component to be displayed is in
<transition name="yogln" type="animation" mode="out-in"> <h2 class="title" v-if="isShow">Hello world</h2> <h2 < span style =" box-sizing: border-box! Important; word-wrap: break-word! Important;"Copy the code
Appear properties
When we want to animate the page the first time we load it, we can add the appear property
<transition name="yogln" type="animation" mode="out-in" appear> <h2 class="title" v-if="isShow">Hello world</h2> <h2 < span style =" box-sizing: border-box! Important; word-wrap: break-word! Important;"Copy the code
4. Transition of components
The use of animation effects for components is similar
<transition name="yogln" type="animation" mode="out-in" appear>
<component :is="isShow ? 'home' : 'about'"></component>
</transition>
Copy the code
Use animate. CSS for third-party libraries
Install the animate. CSS
npm i animate.css
Copy the code
Import animate. CSS in main.js:
import "animate.css"
Copy the code
Animation website
Use method 1:
Use the KeyFrames animations defined in the Animate library directly
<template> <button @click="isShow = ! < span style =" box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 13px! Important; word-break: inherit! Important;" <style scoped> .yogln-enter-active { animation: flip 1s; } .yogln-leave-active { animation: flip 1s reverse; } </style>Copy the code
Use mode two:
Use the classes provided to us directly by the Animate library
<transition enter-active-class="animate__animated animate__bounceInUp"
leave-active-class="animate__animated animate__zoomOutDown">
<h2 class="title" v-if="isShow">Hello World</h2>
</transition>
Copy the code
6. Use GSAP for third-party libraries
Gsap animation effects
The installation
npm i gsap
Copy the code
Before using the animation, let’s take a look at the JavaScript hooks that the Transition component provides to help us listen to the stage of the animation execution.
When we use JavaScript to perform transition animations, the done callbacks need to be made, otherwise they will be called synchronously and the transition will complete immediately.
Adding: CSS =”false” will also allow Vue to skip CSS detection. In addition to slightly better performance, this avoids CSS rules during the transition.
<transition name="yogln" @enter="enter" @leave="leave">
<h2 class="title" v-if="isShow">Hello World</h2>
</transition>
<script>
import gsap from 'gsap'
export default {
data() {
return {
isShow: true,
}
},
methods: {
enter(el, done) {
gsap.from(el, {
scale: 0,
x: 200,
onComplete: done
})
},
leave(el, done) {
gsap.to(el, {
scale: 0,
x: 200,
onComplete: done
})
},
},
}
</script>
Copy the code
Gsap implements digital transformation
<template> <input type=" step "="100" v-model="counter"> {{showNumber.toFixed(0)}}</h2> </template> <script> import gsap from 'gsap' export default { data() { return { counter: 0, showNumber: 0 } }, watch: { counter(newValue) { gsap.to(this, { duration: 1, showNumber: newValue, }) }, }, } </script>Copy the code
7. Motion animation for list transitions
A list can be transformed using the transition-group component
Use the list transition animation to achieve the transformation of numbers
<template> <div> < button@click ="addNum"> Add number </button> < button@click ="delNum"> Delete number </button> <button @click="shuffle"> </button> <span v-for="item in numbers" :key="item" class="item">{{item}}</span> </transition-group> </div> </template> <script> import _ from 'loadsh' export default { data() { return { numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9], currNum: 10, } }, methods: { addNum() { this.numbers.splice(this.randomIndex(), 0, this.currNum++) }, delNum() { this.numbers.splice(this.randomIndex(), 1) }, randomIndex() { return Math.floor(Math.random() * this.numbers.length) }, shuffle() { this.numbers = _.shuffle(this.numbers) } }, } </script> <style scoped> .item { margin: 0 10px; display: inline-block; } .yogln-enter-from, .yogln-leave-to { opacity: 0; transform: translateY(30px); } .yogln-enter-active, .yogln-leave-active { transition: all 1s ease; } .yogln-leave-active { position: absolute; } .yogln-move { transition: transform 1s ease; } </style>Copy the code
.yogln-move is the transition effect of the numbers on the right when inserting or removing elements
List animation to achieve alternate animation
<template> <div> <input type="text" v-model="keyword" @input="input"> <transition-group tag="ul" name="yogln" :css="false" @before-enter="beforeEnter" @enter="enter" @leave="leave"> <li v-for="name, index in showNames" :key="name" :data-index="index">{{name}}</li> </transition-group> </div> </template> <script> import gsap from 'gsap' export default { data() { return { names: ['abc', 'cba', 'nba', 'why', 'lilei', 'hmm', 'kobe', 'james'], keyword: '' } }, computed: { showNames() { return this.names.filter(item => item.indexOf(this.keyword) ! == -1) } }, methods: { beforeEnter(el) { el.style.opacity = 0 el.style.height = 0 }, enter(el, done) { gsap.to(el, { height: Index * 0.3, onComplete: done,})}, leave(el, done) {gsap. To (el, {height: 0, opacity: 0, delay: el.dataset. Index * 0.3, onComplete: done,})},},} </script>Copy the code
Notice a little trick here, through:data-index="index"
, passed in the methoddataset.index
Gets the index value passed in
Third, Composition API
1.mixin
Basic use of mixins
<script>
import demomixin from './mixin/demomixin'
export default {
mixin: [demomixin]
}
</script>
Copy the code
Merge rules for mixins
What does Vue do if the options in the Mixin object conflict with the options in the component object?
There are different cases to deal with;
- Case 1: If it is the return value object of the data function
- Return value objects are merged by default;
- If the properties of the data return value object conflict, the component’s own data is retained;
- Case 2: How to lifecycle hook functions
- Lifecycle hook functions are merged into arrays and are called;
- Case 3: Options with object values such as Methods, Components, and Directives are combined into the same object.
- For example, if both options have methods, and both define methods, they all work;
- But if the objects have the same key, then the component object’s key-value pair is taken
Global Mixin
If there are certain options in a component that all components need to have, then we can use global mixins
-
Global mixins can be registered using the application method Mixin.
-
Once registered, the globally mixed option will affect every component;
const app = createApp(App)
app.mixin({
created() {
console.log("created");
},
})
app.mount('#app')
Copy the code
2. Extends (understand)
Extends is similar to mixins but less flexible than mixins, so it’s rarely used
<script>
import BasePage from './BasePage.vue'
export default {
extends: BasePage
}
</script>
Copy the code
3. Parameters to the setup() function
Let’s first look at the arguments to a setup function, which has two main arguments:
- The first argument: props
- The second argument: context
Props: props: props: props: props: props: props: props: props: props: props
- For the props type, we use the props option as before.
- It is still possible to use the props attribute in a template, such as message.
- If we want to use props in a setup function, we can’t get them using this (I’ll see why later);
- Because props are passed directly as arguments to the setup function, we can use them directly as arguments.
The other argument is the context, which we also call a SetupContext, which contains three properties:
- Attrs: all attributes that are not props;
- Slots: the slot passed from the parent component (this will work when returned as a render function, more on that later);
- Emit: emit events when we need to emit events internally (we cannot access this, so we cannot emit events through this.$emit)
4. the return value of the setup() function
Since setup is a function, it can also have a return value. What does it do with the return value?
The return value from setup can be used in the template; That is, we can replace the data option with the return value of setup;
We can even return an execution function instead of the method defined in methods
<script>
export default {
setup(props, ctx) {
const name = 'yogln'
const counter = 100
const increment = () => {
counter++
}
return {
name,
increment
}
},
}
</script>
Copy the code
Setup cannot use this
Setup cannot use this
Setup cannot use this
5. The setup() function performs the corresponding refresh
reactive API
<template>
<div>
<h2>{{state.name}}</h2>
<h2>{{state.counter}}</h2>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup(props, ctx) {
const state = reactive({
name: 'yogln',
counter: 100,
})
const increment = () => {
state.counter++
}
return {
state,
increment,
}
},
}
</script>
Copy the code
So what is the reason for this? Why is this going to be responsive?
This is because when we use the reactive function to process our data, the data will be collected when it is used again. When the data changes, all the collected dependencies are used for responsive operations (such as updating the interface); In fact, we wrote the data option internally and gave it to the reactive function to program it as a reactive object
ref API
The reactive API is limited to the types we pass in. It requires that we pass in an object or array type:
- If we pass in a primitive data type (String, Number, Boolean) a warning is issued
At this time Vue3 provides us with another API: ref API
- Ref returns a mutable responsive object that maintains its internal value as a reference to the responsive. This is where the ref name comes from.
- Its internal values are maintained in the value property of the REF
<template>
<div>
<h2>{{counter}}</h2>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup(props, ctx) {
let counter = ref(100)
const increment = () => {
counter.value++
}
return {
counter,
increment
}
},
}
</script>
Copy the code
There are two caveats:
- When importing ref values into the template, Vue automatically helps us unpack them, so we don’t need to use ref. Value in the template.
- But inside the setup function, it’s still a ref reference, so when we operate on it, we still need to use the ref.value approach
Unpacking in a template is a shallow level of unpacking. If our code is like this: if we put the ref in a reactive property, it will automatically unpack it when it is used in the template
Shallow unpacking of ref
<template> <div> Home Page <h2>{{message}}</h2> <! <h2> Current count: {{counter}}</h2> <! <h2> Current count: {{info.counter. Value}}</h2> <! Reactive object (s); reactive object (s); {{reactiveInfo.counter}}</h2> <button @click="increment">+1</button> </div> </template> <script> import { ref, reactive } from 'vue'; export default { setup() { let counter = ref(100); Const reactiveInfo = reactive({counter}) const increment = () => {counter. Value++; console.log(counter.value); } return { counter, info, reactiveInfo, increment } } } </script>Copy the code
6.readonly
Readonly returns the read-only Proxy of the native object (that is, it is still a Proxy, and this is a Proxy whose set method has been hijacked and cannot be modified)
The common readonly method in development takes three types of arguments:
- Type 1: plain object;
- Type 2: Reactive returns an object.
- Object of type three: ref
Objects returned by readonly are not allowed to be modified;
However, the original object processed by readonly is allowed to be modified; For example, const info = readonly(obj), the info object is not allowed to be modified; When obj is modified, the info object returned by readonly is also modified; But we can’t modify the info object returned by readonly; In essence, the setter method for the object returned by readonly has been hijacked
<script>
import {readonly} from 'vue'
export default {
setup(props, ctx) {
const info = {
name: "yogln"
}
const readInfo = readonly(info)
readInfo.name = "why"
}
}
</script>
Copy the code
7. Reactive judgment API
isProxy
- Check whether the object is a proxy created by reactive or readonly.
isReactive
- Check whether an object is a reactive proxy created by reactive:
- It will also return true if the delegate was built by readonly but wrapped around another delegate created by reactive.
isReadonly
- Check whether the object is a read-only agent created by readonly.
toRaw
- Return the original object of the reactive or readonly proxy. (It is not recommended to keep persistent references to the original object. Use with caution).
shallowReactive
- Create a responsive proxy that tracks the responsiveness of its own property, but does not perform deep responsive transformations of nested objects (deep versus native).
shallowReadonly
- Create a proxy that makes its own property read-only, but does not perform deep read-only transformations of nested objects (deep is still readable and writable)
8.refAPI
toRefs
If we use ES6’s deconstructing syntax to deconstruct the value of the object returned by reactive, then the data will no longer be reactive, either by modifying the variable of the structure or by modifying the state object returned by reactive.
Vue provides a toRefs function that converts the properties of the object returned by reactive toRefs. So we’re going to struct it again and the name and the age themselves are going to be ref
This creates a link between state.name and ref.value, and any change causes another change
< span style =" box-sizing: border-box; color: RGB (255, 255, 255); line-height: 22px; font-size: 12px! Important;" toRefs } from 'vue' export default { setup(props) { const state = reactive({ name: 'yogln', age: 18 }) let { name, age} = toRefs(state) const changeAge = () => { age.value++ } return { name, age, changeAge } }, } </script>Copy the code
toRef
const { name } = state
let age = toRef(state, 'age')
const changeAge = () = > {
age.value++
}
Copy the code
unref
If we want to get the value in a ref reference, we can also do this by using the unref method:
Returns the internal value if the argument is a ref, otherwise returns the argument itself;
This is val = isRef(val), right? Val.value: Syntax sugar function for val;
isRef
Determines if the value is a ref object.
shallowRef
Create a shallow ref object;
triggerRef
Manually triggers side effects associated with shallowRef
customRef
Create a custom ref and display control over its dependency tracking and update trigger:
- You need a factory function that takes the track and trigger functions as arguments;
- And it should return an object with get and set;
The use of custom Ref, to achieve the text box anti – shaking effect
app.vue
<template>
<div>
<input type="text" v-model="message">
<h2>{{message}}</h2>
</div>
</template>
<script>
import useDebounceRef from './hook/useDebounceRef'
export default {
setup(props) {
const message = useDebounceRef('Hello World')
return {
message
}
},
}
</script>
Copy the code
useDebounceRef.js
import {customRef} from 'vue'
export default function(value) {
let timer = null
return customRef((track, trigger) = > {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timer)
timer = setTimeout(() = > {
value = newValue
trigger()
}, 1000); }}})}Copy the code
9.computed
- Method one: receive a getter function and return the value for the getter, returning an invariant ref object.
- Mode two: receive an object with get and set and return a variable (read/write) REF object
<template> <h2>{{fullName}}</h2> < button@click ="changeName"> button </button> </template> <script> import {computed, ref } from 'vue' export default { setup(props) { const firstName = ref('Kobe') const lastName = ref('Bright') const fullName = computed({ get: () => { return firstName.value + ' ' + lastName.value }, set: (newValue) => { const names = newValue.split(' ') firstName.value = names[0] lastName.value = names[1] } }) const changeName = () => { fullName.value = 'coder yogln' } return { fullName, changeName, } }, } </script>Copy the code
10.watchEffect
WatchEffect Basic use
Functions passed in watchEffect are executed immediately, and dependencies are collected during execution; The function passed in watchEffect is executed again when the collected dependencies change;
< the template > < div > < h2 > {{name}}, {{age}} < / h2 > < button @ click = "changeName" > button < / button > < / div > < / template > < script > import { ref, watchEffect } from 'vue' export default { setup(props) { const name = ref('yogln') const age = ref(18) watchEffect(() =>{ console.log("name", name.value, "age", age.value) }) const changeName = () => { name.value = 'why' } return { name, age, changeName } } } </script>Copy the code
WathEffect stop listening
const stop = watchEffect(() = >{
console.log("name", name.value, "age", age.value)
})
stop() // Stop listening after execution
Copy the code
WatchEffect Cancels side effects
watchEffect((onInvalidate) = > {
onInvalidate(() = > {
// Code that removes side effects, such as canceling the last network request
console.log('onInvalidate')})console.log('name', name.value, 'age', age.value)
})
Copy the code
When watchEffect is executed
We want to get the element reference in setup and print the value
<template> <h2 ref="title">Hello World</h2> </template> <script> import { ref, watchEffect } from 'vue' export default { setup(props) { const title = ref(null) watchEffect(() => { Console. log(title.value)}, {// flush: 'pre' // default flush: 'post' // mount}) return {title}}} </script>Copy the code
To get an element or component from setup, all we need to do is define a ref object that binds to the element or component’s REF attribute.
When flush: pre is set to the default value, we see that the print is printed twice:
- This is because the setup function executes the passed side function immediately upon execution, and the DOM is not mounted at this time, so it prints null.
- When the DOM is mounted, the title ref object is assigned a new value, and the side effect function is executed again, printing out the corresponding element;
- The Flush option also accepts sync, which forces the effect to always fire synchronously. However, this is inefficient and should be rarely needed.
11.watch
Basic use of Watch
- Pass in a getter function
< span style =" box-sizing: border-box; color: RGB (255, 255, 255); line-height: 22px; font-size: 12px! Important;" watch, ref } from 'vue' export default { setup(props) { const info = reactive({ name: 'yogln', }) // 1. Pass a getter function watch(() => info.name, (newValue, oldValue) => {console.log('newValue:', newValue, 'oldValue:', oldValue) // newValue: kobe oldValue: yogln }) return { info, changeName, } }, } </script>Copy the code
- We pass in a reactive object: reactive, and the object that is returned is reactive
watch(info, (newValue, oldValue) = > {
console.log('newValue:', newValue, 'oldValue:', oldValue)
// newValue: Proxy {name: "kobe"} oldValue: Proxy {name: "kobe"}
})
Copy the code
- Pass in a responsible object: the ref object is the value itself
const name = ref('yogln')
const changeName = () = > {
name.value = 'kobe'
}
watch(name, (newValue, oldValue) = > {
console.log('newValue:', newValue, 'oldValue:', oldValue)
// newValue: kobe oldValue: yogln
})
Copy the code
Watch listens to multiple data sources
Listening to multiple data sources can wrap incoming listening objects in an array
watch([name, () = > ({ ...info })], (newValue, oldValue) = > {
console.log('newValue:', newValue, 'oldValue:', oldValue)
/ / newValue: (2) [" kobe, "{...}] 0:" kobe "1: name:" yogln __proto__ : Objectlength: 2 __proto__ : Array (0) oldValue: (2) [" yogln, "{...}]
})
Copy the code
Watch deep listening
When listening to Reactive objects and the object passed in does not pass Reactive objects… {deep: true}
However, after deconstruction, you need to manually set to enable deep listening
const info = reactive({
name: 'yogln'.friends: {
name: 'why'}})const name = ref('yogln')
watch([name, () = > ({ ...info })], (newValue, oldValue) = > {
console.log('newValue:', newValue, 'oldValue:', old
vbbValue)
// newValue: kobe oldValue: yogln
}, {
deep: true.immediate: true // Enable the initial execution
})
Copy the code
12. Lifecycle hooks
How to use lifecycle functions in the Setup function you can register lifecycle hooks using the onX function that is directly imported;
<script>
import { onMounted, onUpdated } from 'vue'
export default {
setup(props) {
onMounted(() => {
console.log("onMounted")
})
onUpdated(() => {
console.log("onUpdated")
})
}
}
</script>
Copy the code
In the setup function, the beforecreate and Created lifecycles have no corresponding hooks and are used directly in the setup function, which executes before the lifecycle
13. Dojo.provide and Inject
Vue provides both provide and inject functions for using setup between descendant components
app.vue
<template>
<home></home>
</template>
<script>
import { ref, provide, readonly } from 'vue'
import Home from './Home.vue'
export default {
components: { Home },
setup(props) {
const name = ref('yogln')
const age = ref(18)
provide('name', readonly(name))
provide('age', readonly(age))
},
}
</script>
Copy the code
Use readOnly to wrap data to ensure a single data stream and prevent the child component from manipulating the data obtained by the parent component.
home.vue
<template> <h2>name</h2> <h2>age</h2> </template> <script> import {inject} from 'vue' export default { setup(props) { Const age = inject("age", 0) const age = inject("age", 0) return {name, age}}} </script>Copy the code
14. com positionAPI practice
The data in the counter case and the title case is extracted
<template>
<div>
<h2>{{counter}}</h2>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue'
import useCounter from './hook/useCounter'
import useTitle from './hook/useTitle'
export default {
setup(props) {
const { counter, increment } = useCounter()
const titleRef = useTitle('yogln')
setTimeout(() => {
titleRef.value = "why"
}, 3000);
return {
counter,
increment,
}
},
}
</script>
Copy the code
/hook/useCounter
import { ref } from 'vue'
export default function () {
const counter = ref(0)
const increment = () = > {
counter.value++
}
return {
counter,
increment
}
}
Copy the code
/hook/useTitle
import { watch, ref } from 'vue'
export default function (title = "Default title") {
const titleRef = ref(title)
watch(titleRef, newValue= > {
document.title = newValue
}, {
immediate: true
})
return titleRef
}
Copy the code
Title 3s revisedyogln
Instead ofwhy
Listen for scroll and mouse slide events
App.vue
<template>
<div>
<p class="content"></p>
<div class="scroll">
<div>scrollX: {{scrollX}}</div>
<div>scrollY: {{scrollY}}</div>
</div>
<div class="mouse">
<div>mouseX: {{mouseX}}</div>
<div>mouseY: {{mouseY}}</div>
</div>
</div>
</template>
<script>
import useScroll from './hook/useScroll'
import useMouse from './hook/useMouse'
export default {
setup(props) {
const { scrollX, scrollY} = useScroll()
const { mouseX, mouseY} = useMouse()
return {
scrollX,
scrollY,
mouseX,
mouseY
}
},
}
</script>
<style scoped>
.content {
width: 3000px;
height: 5000px;
}
.scroll {
position: fixed;
right: 50px;
bottom: 30px;
}
.mouse {
position: fixed;
right: 50px;
bottom: 90px;
}
</style>
Copy the code
useScroll.js
import { ref } from 'vue'
export default function () {
const scrollX = ref(0)
const scrollY = ref(0)
window.addEventListener('scroll'.() = > {
scrollX.value = window.scrollX
scrollY.value = window.scrollY
})
return {
scrollX,
scrollY
}
}
Copy the code
useMouse.js
import { ref } from 'vue'
export default function () {
const mouseX = ref(0)
const mouseY = ref(0)
window.addEventListener('mousemove'.(event) = > {
mouseX.value = event.pageX
mouseY.value = event.pageY
})
return {
mouseX,
mouseY
}
}
Copy the code
15. Setup top-level writing (experimental)
App.vue
<template> <div> <h2>counter:{{counter}}</h2> <button @click="increment">+</button> <home message=" hey hey hey "></home> </div> </template> <script setup> import { ref } from 'vue' import Home from './Home.vue' const counter = ref(0) const increment = () => { counter.value++ } </script>Copy the code
Home.vue
<template>
<div>
<h2>{{message}}</h2>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
message: {
type: String,
default: '哈哈哈'
}
})
</script>
Copy the code
Other Components
1. Basic use of render function
The render function needs to return the vNode, and the h function can do that for us.
<script>
import { h } from 'vue'
export default {
render() {
return h('h2', {class: 'title'}, 'Hello Render')
}
}
</script>
Copy the code
2. The render function implements the counter case
<script> import { h, ref } from 'vue' export default { setup(props) { const counter = ref(0) const increment = () => { counter.value++ } Return {counter, increment}}, render() {return h('div', null, [h('h2', null, 'current count: ${this.counter}`), h('button', { onClick: () => { this.increment() } }, "+1") ]) } } </script>Copy the code
3. Use of the render function component
App.vue
<script> import { h } from 'vue' import home from './Home.vue' export default { render() { return h('div', null, H2 / h (' ', null, "App component"), h (home, null, {default: props = > h (' span, ` App to: ${props. The name} `)})])}} < / script >Copy the code
Home.vue
<script> import { h } from 'vue' export default { render() { return h('div', {class: 'home'}, [ h('h2', null, "Hello World"), this.$slots.default ? this.$slots.default({name: 'yogln'}) : H ('h2', null, 'I am the default ')])}} </script>Copy the code
4. The use of JSX
<script> import { ref } from 'vue' export default { setup(props) { const counter = ref(0) const increment = () => { counter.value++ } const decrement = () => { counter.value-- } return { counter, increment, decrement } }, Render () {return (<div> <h2>) current count: {this.counter}</h2> <button onClick={this.increment}>+1</button> <button onClick={this.decrement}>-1</button> </div> ) }, } </script>Copy the code
5. Customize instructions
Custom instruction implementation
Similar to v-show, V-for, and V-Model, Vue allows us to define custom directives, which are often used in situations where you need to perform low-level operations on DOM elements
There are two types of custom instructions:
- Custom local directive: passed in component
directives
Option that can only be used in the current component - Custom global directives: app’s
directive
Method, which can be used in any component;
For example, let’s take a very simple example: when an element is mounted, you can customize the focus
-
Implementation 1: If we use the default implementation;
<template> <input type="text" ref="inputRef"> </template> <script> import { ref, onMounted } from 'vue' export default { setup(props) { const inputRef = ref(null) onMounted(() => { inputRef.value.focus() }) return { inputRef } } } </script> Copy the code
-
Implementation method two: customize a local v-focus instruction;
<template> <input type="text" v-focus> </template> <script> export default { directives: { focus: { mounted(el) { el.focus() }, } } } </script> Copy the code
-
Implementation mode three: customize a V-Focus global instruction;
const app = createApp(App)
app.directive('focus', {
mounted(el) {
el.focus()
}
})
app.mount('#app')
Copy the code
The life cycle of a custom instruction
An object defined by a directive, Vue provides the following hook functions:
- Created: called before the attribute or event listener of the bound element is applied;
- BeforeMount: called when a directive is first bound to an element and before the parent component is mounted;
- Mounted: called after the parent component of the bound element is mounted.
- BeforeUpdate: called before updating the VNode containing components;
- Updated: called after the VNode that contains the component and its child components have been updated;
- BeforeUnmount: called before the parent component of the bound element is unmounted;
- Unmounted: called only once when the directive is unbound from the element and the parent component has been unmounted.
Custom instruction parameters and modifiers
<template> <div> <button v-yogln:info.aaa.bbb="{name: </ directives > </template> <script> export default {directives: {yogln'}"> { created(el, bindings, vNode,preNode) { console.log("created") console.log(el, bindings, vNode,preNode) console.log(bindings) }, mounted() { console.log("mounted") }, } } } </script>Copy the code
Custom instruction conversion timestamp
Dayjs library for converting timestamps
npm i dayjs
Copy the code
App.vue
<template>
<h2 v-format-time="'YY/MM/DD HH:mm:ss'">{{time}}</h2>
<h2 v-format-time>{{time}}</h2>
</template>
<script>
import { ref } from 'vue'
export default {
setup(props) {
const time = ref(1624882233)
return {
time
}
}
}
</script>
Copy the code
directive/format-time.js
import dayjs from 'dayjs';
export default function(app) {
app.directive('format-time', {
created(el, bindings) {
// Get the time text
let textContent = el.textContent
// Get the date format passed in
let formatString = bindings.value
if(! formatString) { formatString ='YYYY-MM-DD HH:mm:ss'
}
if(textContent.length == 10) {
textContent = textContent * 1000
}
el.textContent = dayjs(textContent).format(formatString)
},
})
}
Copy the code
directive/index.js
import formatTime from './format-time';
export default function registerTime(app) {
formatTime(app)
}
Copy the code
Convert a timestamp with or without an incoming format
6. Know the Teleport
We want the component not to be mounted in the component tree, perhaps to be moved to another location outside the Vue app:
For example, move to the body element, or we have other elements outside of the div#app; This is done by teleport
The Teleport is a built-in component provided by Vue, similar to the React Portals.
- Teleport means teleportation over a long distance;
- It has two properties:
- To: Specifies the target element to which to move its contents, using a selector;
- Disabled: Indicates whether to disable the teleport function
Add a tag to index.html
<div id="yogln"></div>
Copy the code
< span style = "box-sizing: border-box; color: RGB (50, 50, 50); font-size: 13px! Important; word-break: inherit! Important;"Copy the code
The h2 and Button components are now mounted on yogln instead of the original app.
7. Use of plug-ins
Usually when we add some functionality to Vue globally, we use the plug-in mode, which can be written in two ways:
- Object type: An object, but must contain one
install
This function is executed when the plug-in is installed. - Function types: a function that is automatically executed when the plug-in is installed;
There are no limits to what plug-ins can do, such as the following:
- Add global methods or properties by adding them to config.globalProperties.
- Add global resources: directives/filters/transitions, etc.
- Add some component options through global mixins;
- A library that provides its own API and one or more of the functions mentioned above;
How the object plug-in is used
export default {
install(app) {
console.log(app);
app.config.globalProperties.$name = "yogln"}}Copy the code
In the main. In js
import pluginObject from './components/plugin/plugin-object';
app.use(pluginObject)
Copy the code
Use the defined $name globally
import getCurrentInstance from 'vue';
created() {
console.log(this.$name)
},
setup(props) {
const instance = getCurrentInstance()
console.log(instance.appContext.config.globalProperties.$name)
}
Copy the code
Method plug-in usage
export default function(app) {
console.log(app);
}
Copy the code
Use it in the same way as objects