1. Talk about your understanding of how MVVM works
- Traditional MVC means that user actions request a server-side route, which calls the corresponding controller to process it, and the controller gets the data, returns the results to the front end, and the page is re-rendered.
- MVVM: Traditional front-end rendering data to the page manually, MVVM does not require users to manually manipulate DOM elements, binding data to the viewModel layer, it will automatically render data to the page, view changes will notify the viewModel layer, update data, The viewModel layer is the bridge to our MVVM pattern
2. Please explain the principle of responsive data
To understand:
- Core point: Object.defineProperty(Define reactive, defineProperty.get method to get data, collect dependent watcher, call defineProperty.set method to check if data has changed when data is updated)
- By default, when vUE initializes data, it redefines all attributes in data using Object.defineProperty. (defineProperty can be defined when data is fetched and set.) When the page retrieves the corresponding attribute, Dependency collection (collecting the watcher for the current component) is performed, and dependencies are notified to update if properties change.
Source SRC/core/instance/state of js initData methods, increase observe methods for each attribute, observe method can judge, whether the data tested, no detection, new observe ()
3. How does vUE detect array changes
- Using function hijacking method, overwrite the array method
- Vue rewrites the prototype chain of the array in Data, pointing to the array prototype method defined by itself, so that when the array API is called, the dependency update can be notified. If the array contains reference types, the reference types in the array will be monitored again.
4. Which has a higher priority: V-if or v-for
Conclusion:
- V – for the priority in the v – if be parsed (compiler to find the answer in the source position/codegen/index. The js, print rendering function can see reason)
- If it happens at the same time, each render will loop before judging the condition, which will loop anyway, wasting performance (filter content that doesn’t need to be rendered using computed attributes first)
- To avoid this, nest the template in the outer layer, do a V-if judgment in this layer, and then do a V-for loop inside
5. Comparison of listener and compute properties
Characteristics and differences
Computed is mainly used for synchronous data processing, while the Watch option is mainly used for event distribution and can be asynchronous. Both achieve the same effect, but their usage scenarios differ based on their characteristics
- computed Has cache properties that only change the associated data when the dependent data changes, suitable for computing or formatting data scenarios, (synchronous processing of data)
- watchListen to data, associated, but not dependent, as long as a data change, you can process some data or send events, and synchronous/asynchronous execution
Application scenarios
-
Computed attributes: Shopping cart prices are calculated, loan interest is calculated
-
Watch listener: 1. It is mainly applicable to scenarios related to events and interactions. Data changes are conditional, and it is suitable for one data to start multiple events at the same time
Abstract concept
Events such as pop-up prompts are interactive for Watch, data computation and string processing for computed
6. Handwriting vueplugins to achieve loading effect
7, vuex
Vuex is a state management mode developed specifically for vuue.js applications. It uses centralized storage to manage the state of all components of the application and rules to ensure that the state changes in a predictable way
The state self-management application consists of the following parts
- State, the data source that drives the application
- View to declaratively map state to the view
- Actions, in response to changes in state caused by user input on the view
When should I use Vuex?
Vuex helps us manage shared state and comes with more concepts and frameworks. This requires a trade-off between short-term and long-term benefits.
Using Vuex can be tedious and redundant if you don’t plan to develop large, single-page applications. That’s true — if your application is simple, you’d better not use Vuex. A simple Store pattern is all you need. However, if you need to build a medium to large single-page application, and you’re probably thinking about how to better manage state outside of components, Vuex would be a natural choice.
state
Single state tree
Vuex uses a single state tree — yes, it contains all the application-level state in a single object. At this point it exists as a “unique data source (SSOT)”. This also means that each app will contain only one Store instance. A single state tree allows us to directly locate any particular state fragment and easily take a snapshot of the entire current application state during debugging.
Get the VUEX state in the VUE component
Vuex provides a mechanism to “inject” state from the root component into each child component through the Store option (call vue.use (Vuex))
Const app = new Vue({el: '#app', // Provide the store object to the 'Store' option, which can inject instances of store into all child stores, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` })Copy the code
By registering the Store option in the root instance, the store instance is injected into all the children of the root component, which can be accessed through this.$store.
MapState helper function
When a component needs to fetch multiple states, it can be repetitive and redundant to declare all those states as computed properties. To solve this problem, we can use the mapState helper function to help us generate computed properties
MapState import {mapState} from 'Vuex' export default {//... Computed: mapState({// Arrow function makes code more concise count: State => state.count, // Pass string argument 'count' equal to 'state => state.count' countAlias: CountPlusLocalState (state) {return state.count + this.localcount}})}Copy the code
We can also pass mapState an array of strings when the name of the computed property of the map is the same as the name of the child node of State
Computed: mapState([// map this.count to store.state.count 'count'])Copy the code
Object expansion operator
The mapState function returns an object. How do we mix it with local computed properties? Typically, we need to use a utility function to merge multiple objects into one so that we can pass the final object to the computed property. But since we have the object expansion operator, we can greatly simplify writing:
computed: { localComputed () { /* ... */}, // Use the object expansion operator to blend this object into an external object... mapState({ 'count', 'goodList', 'totalNumber' }) }Copy the code
Getter
Sometimes we need to derive some state from the state in the store, such as filtering and counting lists:
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
Copy the code
If more than one component needs this property, we can either copy the function or extract a shared function and import it in multiple places — neither approach is ideal.
Vuex allows us to define “getters” (you can think of them as computed properties of the store) in the store. Just like evaluating properties, the return value of a getter is cached based on its dependency and is recalculated only if its dependency value changes
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
Copy the code
Note that getters are cached as part of Vue’s responsive system when accessed through properties.
Access by method
You can also pass parameters to a getter by asking the getter to return a function. It’s useful when you’re querying an array in a store.
getters: { // ... getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } store.getters.getTodoById(2) // -> { id: 2, text: '... ', done: false }Copy the code
Note that the getter is called every time it is accessed through a method, without caching the result.
MapGetters helper function
The mapGetters helper function simply maps the getters in the store to local computed properties:
import { mapGetters } from 'vuex' export default { // ... Computed: {// Mix getters into a computed object using the object expansion operator... mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ] )}}Copy the code
If you want to give a getter property another name, use object form:
MapGetters ({/ / the ` enclosing doneCount ` mapping for ` enclosing $store. The getters. DoneTodosCount ` doneCount: 'doneTodosCount})Copy the code
Mutation [mju ː ˈ ta ɪ ʃ n]
The only way to change the state in Vuex’s store is to commit mutation. Mutations in Vuex are very similar to events: each mutation has a string event type (type) and a callback function (handler). This callback is where we actually make the state change, and it takes state as the first argument:
Const store = new Vuex. Store ({state: {count: 1}, mutations: {increment (state) {/ / the status state. Count++}}})Copy the code
You cannot call a mutation handler directly. This option is more like event registration: “This function is called when a mutation of type INCREMENT is triggered.” To wake up a mutation handler, you need to call the store.mit method with the corresponding type:
store.commit('increment')
Copy the code
Payload submission
You can pass an additional parameter, payload, to store.mit:
mutations: {
increment (state, n) {
state.count += n
}
}
Copy the code
store.commit('increment', 10)
Copy the code
In most cases, the payload should be an object, which can contain multiple fields and the mutation recorded will be more readable:
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
Copy the code
store.commit('increment', {
amount: 10
})
Copy the code
Another way to commit mutation is to use an object containing the type attribute directly:
store.commit({
type: 'increment',
amount: 10
})
Copy the code
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
Copy the code
The Mutation complies with the Vue response rules
Since the state in Vuex’s Store is responsive, the Vue component that monitors the state updates automatically when we change the state. This also means that mutation in Vuex requires the same precautions as mutation in Vue:
1. It is best to initialize all the required properties in your store in advance.
2. When you need to add new properties to an object, you should
- Use vue.set (obj, ‘newProp’, 123), or
Replace an old object with a new one. For example, with the object expansion operator we can write:
state.obj = { ... state.obj, newProp: 123 }Copy the code
Replace Mutation event types with constants
Substituting constants for mutation event types is a common pattern in various Flux implementations. This allows tools like Linter to work, and keeping these constants in a separate file allows your code collaborators to see what mutations are included in the entire app:
export const SOME_MUTATION = 'SOME_MUTATION'
Copy the code
// store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... Mutations: {// we can use ES2015 style computing attribute naming to use a constant as the function name [SOME_MUTATION] (state) {// mutate state}}})Copy the code
Whether or not you use constants is up to you — this can be very helpful on large projects that require multiple people to work together
Mutation must be a synchronization function, executed synchronously
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
Copy the code
Now imagine that we are debugging an app and looking at the mutation log in devtool. Each mutation is recorded, and DevTools needs to capture a snapshot of the previous state and the next state. However, the callback in the asynchronous function in mutation in the example above made this impossible: Because the callback had not yet been called when mutation was triggered, DevTools did not know when the callback was actually called — essentially any state change made in the callback was untraceable.
You can use this. codestore.com MIT (‘ XXX ‘) to commit Mutation in a component, Or use the mapMutations helper function to map methods in a component to a store.mit call (requiring store injection at the root node)
export default { // ... methods: { ... Apply mutations ([' increments ', // map 'this.increment()' to 'this.store.com MIT (' increments ')' 'incrementBy' // Map 'this.incrementBy(amount)' to 'this.incrementBy(amount)'),... Apply mutations ({add: 'increment' // map 'this.add()' to 'this.store.com MIT ('increment')'})}}Copy the code
Note that if you use mapMutations to pass in the method, you need to pass in an object
Action Internally performs asynchronous operations
Actions are similar to Mutation, except that:
- The Action commits Mutation rather than a direct state change
- Actions can contain any asynchronous operation
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Copy the code
The Action function accepts a context object with the same methods and properties as the store instance, so you can submit a mutation by calling context.mit. Or get state and getters via context.state and context.getters
In practice, we’ll often use ES2015 parameter deconstruction to simplify code (especially if we need to call commit many times) :
actions: {
increment ({ commit }) {
commit('increment')
}
}
Copy the code
Distribution of the Action
Action is triggered by the store.dispatch method:
store.dispatch('increment')
Copy the code
Actions Perform asynchronous operations internally
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
Copy the code
Actions support the same payloads and objects for distribution:
// Distribute store.dispatch('incrementAsync', {amount: 10}) // distribute store.dispatch({type: 'incrementAsync', amount: 10})Copy the code
Let’s look at a more practical shopping cart example that involves calling the asynchronous API and distributing multiple mutations:
actions: {checkout ({commit, state}, products) {const savedCartItems = [...state.cart.added] Commit (types.checkout_request) // The shopping API accepts a successful callback and a failed callback shop.buyProducts(products, CHECKOUT_SUCCESS => commit(types.checkout_failure, savedCartItems)}}Copy the code
Distribute the Action in the component
You use this.$store.dispatch(‘ XXX ‘) to distribute actions in the component, or use the mapActions helper function to map the component’s methods to a store.dispatch call (which requires injecting store at the root node first) :
import { mapActions } from 'vuex' export default { // ... methods: { ... MapActions (['increment', // Map 'this.increment()' to 'this.$store.dispatch('increment')' // 'mapActions' also supports payloads: 'incrementBy' // map 'this.incrementBy(amount)' to 'this.$store.dispatch('incrementBy', amount)']),... MapActions ({add: 'increment' // map 'this.add()' to 'this.$store.dispatch('increment')'})}}Copy the code
8. Vue component transfer value
Parent component ====> Child component
- Pass values to child components in the form of bind
- The child component receives values from the parent component through props
Child component ====> Parent component
- $emit
The parent component passes the callback function to the child component, which calls the callback function via this.$emit, passing the argument to the parent component
Non-parent components pass values
Subscribe to vm.on, then Vm. on, then vm.on, and then Vm. emit
9. Vue-directive Specifies a custom directive
The find Filter difference needs to be resolved
Find the usage of the
Colloquially, find is the first item in an array that matches a condition
The function of filter is also filtering
It’s just going through the array and getting all the items that fit
Let STR =arr.find(item=>{return item > 6}) let str2 =arr. filter(item =>{return item > 6) let STR =arr. filter(item =>{return item > 6 }) console.log(arr); console.log(str); console.log(arr); console.log(str2);Copy the code
The find method returns the first qualifying item in the array, and the filter method returns an array of qualifying item items
Copy the code