Understanding of the MVVM pattern
MVVM has three components, Model, View, and ViewModel.
- A View is the structure, layout, and appearance that the user sees on the screen, also known as UI.
- The ViewModel is a binder that communicates with the View and Model layers.
- Model is data and logic.
Views can’t talk to models directly; they can only talk to The ViewModel. The interaction between the Model and ViewModel is bidirectional. The ViewModel connects the View layer to the Model layer through bidirectional data binding, so changes to the View data are synchronized to the Model. Changes to Model data are immediately reflected in the View.
An aside:
You may not know that Vue is not exactly MVVM mode
The strict MVVM requirement that the View not communicate directly with the Model was violated by Vue providing the $refs attribute in the component to allow the Model to manipulate the View directly.
Vue rendering process
The process is mainly divided into three parts:
- Template compilation.
parse
Parse templates to generate abstract syntax trees (AST);optimize
Mark static nodes, which will be skipped in subsequent page updates;generate
The AST intorender
The function,render
Functions are used to buildVNode
. - Building a VNode (Virtual DOM), used by the build process
createElement
buildVNode
.createElement
It’s also customrender
The first argument received when the function is called. - VNode to real DOM.
patch
The function takes care ofVNode
To convert to the real DOM, the core method iscreateElm
To recursively create a real DOM tree and eventually render it on the page.
Vue life cycle
- beforeCreate:Called before the instance is created and cannot be accessed on the instance because the instance has not yet been created
data
,computed
,method
And so on. - created:Called after the instance has been created, when the data has been observed and can be retrieved and changed, but not yet interacted with the DOM, which can be used if you want to access it
vm.$nextTick
. Data can be changed at this point without triggeringupdated
. - beforeMount:Called before mounting, when the template has been compiled and generated
render
Function, ready to start rendering. Changes can also be made to the data at this point without triggeringupdated
. - mounted:After the mount is complete, the real DOM is mounted and can be accessed to the DOM node
$refs
Property to manipulate the DOM. - BeforeUpdate: Called before updates, which is triggered before reactive data is updated and the virtual DOM is re-rendered. Changes to data at this stage do not cause re-rendering.
- Updated: Called after the update is complete, the component DOM is updated. Care should be taken to avoid changing data during this period, which can lead to an endless loop.
- BeforeDestroy: Called before the instance is destroyed, when the instance can still be used, typically this cycle is used to clear timers and cancel event listening.
- Destroyed: Called after the instance is destroyed, when the instance is no longer accessible. The current instance is removed from the parent, the observation is unloaded, all event listeners are removed, and all child instances are destroyed.
Vue parent and child component lifecycle execution order
Rendering process
- The parent component
beforeCreate
- The parent component
created
- The parent component
beforeMount
- Child components
beforeCreate
- Child components
created
- Child components
beforeMount
- Child components
mounted
- The parent component
mounted
The child component is mounted before the parent because the tree of nodes is created recursively, and the child component is created first before the entire parent node is created.
The update process
- The parent component
beforeUpdate
- Child components
beforeUpdate
- Child components
updated
- The parent component
updated
Destruction of the process
- The parent component
beforeDestroy
- Child components
beforeDestroy
- Child components
destroyed
- The parent component
destroyed
Why is data required to be a function
When a component is defined, data must be declared as a function that returns an initial data object, because the component may be used to create multiple instances. If data were still a pure object, all instances would share references to the same data object! By providing the data function, each time a new instance is created, we can call the data function to return a new copy of the original data.
Vue constructs instances using the same constructor, and data directly using objects results in shared references to instances, i.e. states between components affect each other. Shared references usually occur when components are reused. Using a function to return an object, since it is a different reference, naturally avoids this problem.
Component communication mode
props/emit
$children/$parent
ref
$attrs/$listeners
provide/inject
eventBus
vuex
Name five instructions for Vue
v-if
v-for
v-show
v-html
v-model
Difference between V-if and V-show
V-if causes elements or components within the conditional block to be destroyed and rebuilt appropriately.
V-show elements or components are rendered from the start, with a simple CSS switch.
By contrast, v-if has a higher switching cost, so v-show is used for frequent switching and V-if is used for infrequent switching.
V – model under the said
V-model is the syntax sugar for the attribute value and input events. The internal default is value as a value, and the attribute is updated using $emit to trigger the input event, thereby enabling bidirectional binding. Custom bidirectional binding can be implemented by defining the component’s Model option Settings prop and Event.
Principle of bidirectional binding
Two-way binding is where view changes are reflected in the data, and data changes are reflected in the view, and v-Model is a good example of this. In fact, the main test is still responsive principle, responsive principle includes three main members, Observer is responsible for monitoring data changes, Dep is responsible for dependency collection, Watcher is responsible for data or view update, we often say that the collection of dependencies is to collect Watcher.
The main working process of the responsive principle is as follows:
Observer
useObject.defineProperty
Hijack the data and set it upset
和get
.- Each data will have its own
dep
. Data value triggerget
Function, calldep.depend
Collect dependencies; Data update triggerset
Function, calldep.notify
noticeWatcher
The update. Watcher
Updated notifications are received, they are added to an asynchronous queue, de-processed, and the view is updated once all synchronization operations are complete.
What does the key in Vue do
The key is the unique identifier of each VNode. By using the key, the corresponding VNode can be found faster when the DIFF algorithm is executed, improving the DIFF speed.
Key can ensure that the state between elements is independent, and the state will not be reused after update, avoiding some unexpected results. For example, in the case of input box reuse, the contents of the input box are not refreshed even if the elements are updated, because Vue uses a “reuse in place” policy by default, minimizing creation and destruction.
The official example
The difference between computed and Watch
computed
Rely ondata
Change by change,computed
Has a return value;watch
observationdata
Execute the corresponding function.computed
With caching, repeated values do not perform evaluation functions.computed
Dependency collection is triggered when the page is rendered,watch
Dependency collection is triggered before the page renders.computed
The update requires the help of render Watcher,computed
Update is just settingdirty
, requires page rendering to triggerget
To evaluate
How is computed in Vue cached
The “calculated property Watcher” will have a dirty property, and after the initialization is complete, it will cache the evaluation results and set dirty to false. As long as the dependent properties are not updated, the dirty is always false and the repeated values are not evaluated. Instead, the cache is returned directly. Instead, dependent property updates set the dirty of the calculated property Watcher to true, triggering the evaluation function to update the calculated property again when the page renders the calculated property.
Object.defineProperty(target, key, {
get() {
const watcher = this._computedWatchers && this._computedWatchers[key]
// Calculate the property cache
if (watcher.dirty) {
// Evaluate attributes
watcher.evaluate()
}
return watcher.value
}
})
Copy the code
Why can’t a child component change props directly? What is one-way data flow?
All prop forms a one-way downlink binding between their parent prop: updates to the parent prop flow down to the child, but not the other way around. This prevents accidental changes in the state of the parent component from the child, which can make the data flow of your application difficult to understand.
Child components cannot change props because of the principle of one-way data flow.
One-way data flow only allows data to be passed from parent to child, and data can only be updated by the parent. When data is passed to multiple subcomponents, and subcomponents can update data within themselves, it is subjectively difficult to know which subcomponent updated the data, resulting in unclear data flow, which makes application debugging more difficult.
However, a scenario does exist where a child component updates the parent component’s data, and there are three ways to use it:
- Child components
emit
, the parent component accepts custom events. This method is ultimately modified by the parent, and the child only acts as a notification. - Subcomponent custom bidirectional binding, set the component’s
model
Option to add a custom bidirectional binding for the component. .sync
Property modifier, which is the syntactic sugar of the first method, is added to the pass property and can be called within a child componentThis.$emit('update: attribute name ', value)
Update properties.
How does Vue detect array updates
Vue internally overwrites the array prototype chain. When an array changes, dep.notify is called to notify Watcher of the update, in addition to executing the native array methods. There are 7 ways to trigger an array update:
push
pop
shift
unshift
splice
sort
reverse
Do you know keep-alive? How is it done?
Keep-alive is a built-in component of Vue and is an abstract component that is not rendered as an element on the page. It is used for component caching. When the component is switched, the VNode of the component will be cached. When the component is reactivated, the component VNode of the cache will be taken out for rendering, so as to achieve caching.
The two common attributes include and exclude support string, regular, and array formats to allow components to cache conditionally. There is also the Max attribute, which sets the maximum number of caches.
The two lifecycle Activated and deactivated are triggered when a component is activated and deactivated.
The keep-alive cache mechanism uses LRU(Least Recently Used) algorithm,
Let’s talk about how nextTick works
A deferred callback is performed after the next DOM update. NextTick mainly uses macro and micro tasks. According to the execution environment, try to adopt:
- Promise
- MutationObserver
- setImmediate
- setTimeout
NextTick is mainly used for asynchronous updates to internal Watcher, but externally we can use vue. nextTick and vm.$nextTick. The updated DOM is available in nextTick.
Compare Vue3 with Vue2. X
- use
Proxy
Instead ofObject.defineProperty
- new
Composition API
- Templates allow multiple root nodes
Why Vue3 uses Proxy instead of Object.definedProperty
Object.definedproperty can only detect attribute fetching and setting, not additions and deletions. When the data is initialized, Vue simply observes all the data recursively because it does not know which data will be used, resulting in an unnecessary performance drain.
Proxy hijacks the entire object and detects the addition and deletion of object attributes. Proxy does not listen for deep internal object changes, so Vue 3.0 deals with recursive responses in getters, and only internal objects that are actually accessed become responsive, rather than mindless recursion, greatly improving performance.
How is routing lazy loading implemented
Lazy loading of routes is a means of performance optimization. You can use import() to import routing components when writing code. Lazy loading of routes will be separated into a JS file when packaging. After the project goes online, lazy JS files will not be loaded at the first time. Instead, script labels will be dynamically created to load this JS file when the corresponding route is accessed.
{
path:'users'.name:'users'.component:() = > import(/*webpackChunkName: "users"*/ '@/views/users'),}Copy the code
Vue routing hook function
Global hooks
- beforeEach
Called before route entry
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) = > {
// ...
})
Copy the code
- BeforeResolve (New in 2.5.0)
Called after guard and asynchronous components have been resolved within all components
router.beforeResolve((to, from, next) = > {
// ...
})
Copy the code
- afterEach
Routes are invoked after confirmation
router.afterEach((to, from) = > {
// ...
})
Copy the code
Route exclusive hooks
- beforeEnter
Called before the route enters, beforeEnter is executed after beforeEach
const router = new VueRouter({
routes: [{path: '/foo'.component: Foo,
beforeEnter: (to, from, next) = > {
// ...}}}])Copy the code
Component hooks
- beforeRouteEnter
Called before route validation, component instance has not been created, cannot get component instance this
beforeRouteEnter (to, from, next) {
// ...
// Instances can be accessed via callbacks
next(vm= > {
// VM is the component instance})},Copy the code
- BeforeRouteUpdate (2.2 New)
Called when the route changes and can access the component instance
beforeRouteUpdate (to, from, next) {
// ...
},
Copy the code
- beforeRouteLeave
Called when leaving the corresponding route of the component to access the component instance this
beforeRouteLeave (to, from, next) {
// ...
}
Copy the code
Vue – the principle of the router
Vue-router works by updating the view without re-requesting the page. Vue-router has three modes: hash, history, and Abstract.
Hash pattern
Hash mode Uses hashchange to listen for changes in the hash value of the address bar and load the corresponding page. Every time the hash value changes, history is still left in the browser. You can use the forward and back buttons of the browser to return to the previous page.
The history mode
The History mode is based on the History Api and uses popState to listen for changes in the address bar. Use pushState and replaceState to modify the URL without loading the page. However, when a page is refreshed, a request is still sent from the back end, which requires the cooperation of the back end to redirect resources back to the front end for processing by the front end routing.
abstract
No records related to the browser address are involved. Maintains a history stack that emulates the browser through arrays.
How is VUEX invoked across modules
Cross-module invocation is when the current namespace module calls a global module or another namespace module. Set the third parameter to {root: true} when calling dispatch and commit.
modules: {
foo: {
namespaced: true.actions: {
someAction ({ dispatch, commit, getters, rootGetters }) {
// Call your own action
dispatch('someOtherAction') // -> 'foo/someOtherAction'
// Call the global action
dispatch('someOtherAction'.null, { root: true }) // -> 'someOtherAction'
// Invoke action for other modules
dispatch('user/someOtherAction'.null, { root: true }) // -> 'user/someOtherAction'}, someOtherAction (ctx, payload) { ... }}}}Copy the code
How does VUex persist
The vuEX stored state will be lost after the page is refreshed. Persistence ensures that the state will still exist after the page is refreshed.
- Using local storage, set
state
At the same time set upstorage
, and then initialize after refreshingvuex
- Vuex – persistedstate plug-in
Recommended reading
- Gold nine Silver ten, preliminary intermediate front-end interview review summary “JavaScript chapter”
- Summary of “Browser, HTTP, Front-end security”