[Vue] Vue super comprehensive interview questions

1.Understanding of Vue?

Vue.js (/vjuː/, or simply Vue) is an open source JavaScript framework for creating user interfaces and a web application framework for creating single-page applications.

Vue is a progressive MVVM framework for building user interfaces. So how do you understand progressive? Progressive meaning: least mandatory assertion.

Vue.js includes declarative rendering, componentized system, client-side routing, large-scale state management, construction tools, data persistence, cross-platform support, etc. However, in actual development, it does not force developers to use a specific functions, but gradually expanded according to needs.

The core focus of Vue is the view layer in the MVC pattern. At the same time, it can also easily obtain data updates and realize the interaction between the view and the model through specific methods within the component.

The core library of Vue.js only cares about view rendering, and due to its progressive nature, Vue.js is easy to integrate with third-party libraries or existing projects. Vue.js implements a set of declarative rendering engines, and compiles declarative templates into rendering functions at runtime or precompilation, and mounts them in the observer. In the rendering function (touch), the responsive system uses the response The getter method of the responsive data collects dependencies on the observers (Collect as Dependency), and the setter method of the responsive data is used to notify (notify) all observers to update. At this time, the observer Watcher will trigger the rendering function of the component (Trigger re-render). ), the render function executed by the component generates a new Virtual DOM Tree. At this time, Vue will Diff the old and new Virtual DOM Trees to find out the real DOM that needs to be operated and update it.

2. Understanding Vue two-way binding?

Vue data two-way binding mainly refers to: data changes update the view, and view changes update the data, as shown in the following figure:
Insert image description here
that is:

  • When the content of the input box changes, the data in Data changes simultaneously. That is the change of View => Data.

  • When the data in Data changes, the content of the text node changes synchronously. That is, changes in Data => View.

Among them, View changes update Data, which can be achieved through event listening, so the work of Vue's two-way data binding is mainly how to update View according to Data changes.

Vue mainly implements two-way data binding through the following four steps:

  1. Implement a listener Observer: traverse the data object, including the properties of the sub-property object, and use Object.defineProperty() to add setters and getters to the properties. In this case, assigning a value to this object will trigger the setter, and then the data changes can be monitored.
  2. Implement a parser Compile: parse the Vue template instructions, replace the variables in the template with data, then initialize the rendering page view, bind the update function to the node corresponding to each instruction, and add subscribers to monitor the data. Once the data is available Change, receive notification, call update function to update data.
  3. Implement a subscriber Watcher: Watcher subscriber is the communication bridge between Observer and Compile. Its main task is to subscribe to the message of attribute value change in Observer. When receiving the message of attribute value change, the corresponding message in Compile of the parser is triggered. update function.
  4. Implement a subscriber Dep: The subscriber adopts the publish-subscribe design pattern to collect subscriber Watchers and uniformly manage the listeners Observer and subscriber Watchers.

Insert image description here

3.What is the difference between v-show and v-if in Vue?

v-if is truly conditional in that it ensures that event listeners and subcomponents within the conditional block are destroyed and recreated appropriately during the switch; it is also lazy: if the condition is false on the initial render, nothing Do - The conditional block will not start rendering until the condition becomes true for the first time.

v-show is much simpler - the element is always rendered regardless of the initial conditions, and is simply toggled based on the CSS "display" property.

Therefore, v-if is suitable for scenarios where conditions rarely change during runtime and there is no need to switch conditions frequently; v-show is suitable for scenarios where conditions need to be switched very frequently.

4.What happens during the mounting process of Vue instance?

  • When calling new Vue, the _init method will be called.

      定义 $set、 $get 、$delete、$watch 等方法
      定义 $on、$off、$emit、$off 等事件
      定义 _update、$forceUpdate、$destroy生命周期
      调用$mount进行页面的挂载
    
  • When mounting, it is mainly through the mountComponent method.

  • Define updateComponent update function

  • Execute render to generate virtual DOM

  • _update generates a real DOM structure from the virtual DOM and renders it into the page

5. Understanding the Vue life cycle?

(1) What is the life cycle?

A Vue instance has a complete life cycle, that is, a series of processes from creation, initializing data, compiling templates, mounting Dom -> rendering, updating -> rendering, uninstalling, etc. We call this the life cycle of Vue.

(2) The role of each life cycle

life cycle describe
beforeCreate When the component instance is created, before the component's properties take effect
created The component instance has been completely created and the properties have been bound, but the real DOM has not yet been generated and $el is not yet available.
beforeMount Called before the mount starts: the relevant render function is called for the first time
mounted el is replaced by the newly created vm.$el and the hook is called after being mounted to the instance.
beforeUpdate Called before component data is updated and occurs before the virtual DOM is patched.
update After component data is updated
activited keep-alive exclusive, called when the component is activated
deadctivated keep-alive exclusive, called when the component is destroyed
beforeDestory Called before component is destroyed
destoryed Called after component is destroyed

(3) Life cycle diagram

Insert image description here

6. How to solve the slow loading speed of the SPA first screen?

  • Use code splitting: Split code into small chunks and load them on demand (lazy loading) to avoid unnecessary network requests and reduce load times.
  • Cache resources: Leverage browser cache to store reused files, such as CSS and JS files, images, etc.
  • Preload key resources: Before the first rendering, key resources, such as JS, CSS or data required for the homepage, are loaded in advance to ensure fast rendering of key content.
  • Use appropriate image formats: Choose an appropriate image format (such as JPEG, PNG, WebP, etc.) and compress if necessary to reduce file size. For some small icons, you can use font files such as iconfont instead.
  • Enable Gzip compression: Use the server-side Gzip compression algorithm to compress files to reduce transfer time and bandwidth consumption.
  • Use a CDN: Use a content delivery network (CDN) to cache and deliver files to improve file download speed and reliability.
  • Optimize API requests: Reduce the number of API calls as much as possible, and use techniques such as caching and lazy loading to optimize the efficiency of API requests.
  • Use server-side rendering: Use server-side rendering (SSR) to generate HTML to reduce the time and resources required for client-side rendering. However, it is important to note that SSR may also increase the load on the server and make the website more complex.

7.What is the routing hook function of vue-router? What is the order of execution?

The execution process of routing hooks. The types of hook functions include: global guard, routing guard, and component guard.
Complete navigation analysis process:
1. Navigation is triggered.
2. Call the beforeRouterLeave guard in the deactivated component.
3. Call the global beforeEach guard.
4. Call the beforeRouterUpdate guard (2.2+) on the reused component.
5. beforeEnter in the routing configuration.
6. Parse asynchronous routing components.
7. Call beforeRouterEnter in the activated component.
8. Call the global beforeResolve guard (2.5+).
9. Navigation is confirmed.
10. Call the global afterEach hook.
11. Trigger DOM update.
12. Call the callback function passed to next in the beforeRouterEnter guard. The created component instance will be passed in as a parameter of the callback function.

8. What should I do if the interface does not refresh when Vue adds new attributes to the object?

Vue does not allow dynamically adding new reactive properties on already created instances

If you want to update data and views synchronously, you can adopt the following three solutions:

Vue.set()
Object.assign()
$forcecUpdated()

1. Vue.set()

Add a property to the responsive object through Vue.set, and ensure that the new property is also responsive and triggers view updates

function set (target: Array<any> | Object, key: any, val: any): any {
  ...
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

This is nothing more than calling the defineReactive method again to implement the responsiveness of new attributes.

Regarding the defineReactive method, property interception is still implemented internally through Object.defineProperty.

The approximate code is as follows:

function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
        get() {
            console.log(`get ${key}:${val}`);
            return val
        },
        set(newVal) {
            if (newVal !== val) {
                console.log(`set ${key}:${newVal}`);
                val = newVal
            }
        }
    })
}

2. Object.assign()

New properties added to an object directly using Object.assign() will not trigger an update

A new object should be created, merging the properties of the original object and the mixed object

this.someObject = Object.assign({},this.someObject,{newProperty1:1,newProperty2:2 ...})

3. $forceUpdate

If you find yourself needing to do a forced update in Vue, 99.9% of the time, you're doing something wrong somewhere

$forceUpdate forces the Vue instance to re-render

PS: Only affects the instance itself and the subcomponents inserted into the slot content, not all subcomponents.

summary

如果为对象添加少量的新属性,可以直接采用Vue.set()

如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象

如果你实在不知道怎么操作时,可采取$forceUpdate()进行强制刷新 (不建议)

PS: vue3 uses proxy to achieve data responsiveness. Directly dynamically adding new attributes can still achieve data responsiveness.

9.What is the use of $nextTick in Vue?

effect:

Vue updates the DOM asynchronously. When data changes, the DOM update will not be completed immediately. The nextTick callback is a delayed callback executed after the next DOM update cycle ends.

Implementation principle:

  • nextTick mainly uses macro tasks and micro tasks. Try to use Promise according to the execution environment: you can delay the function to the end of the current function call stack

    MutationObserver: It is a new function added in H5. Its function is to monitor changes in DOM nodes. In all DOM

    After the change is completed, the callback function setImmediate is executed: used to interrupt long-running operations and run the callback function immediately after the browser completes other operations (such as events and display updates)

    If none of the above works, use setTimeout to delay the function to the DOM.

    Use it after updating. The reason is that macro tasks consume more than micro tasks. Micro tasks are used first, and the macro tasks with the largest consumption are used last.

10. What is your understanding of slot? And what are the application scenarios?

what is slot

In HTML, the slot element, as part of the Web Components technology suite, is a placeholder within a Web component.

This placeholder can be filled in later using its own markup language. Usage
scenarios
allow users to expand components through slots to better reuse components and customize them.

If the parent component uses a reused component and obtains a small amount of changes in the component in different places, it is unwise to rewrite the component.

Pass content to the specified location inside the component through the slot to complete the application of this reusable component in different scenarios.

For example, layout components, table columns, drop-down selections, pop-up boxes to display content, etc.

3. Classification
slots can be divided into the following three types:

默认插槽
具名插槽
作用域插槽

The default slot
subcomponent uses tags to determine the rendering position. The DOM structure can be placed in the tag. When the parent component is used without passing content to the slot, the DOM structure in the tag will be displayed on the page.

When using the parent component, just write content directly in the tag of the child component.

子组件Child.vue

<template>
    <slot>
      <p>插槽后备的内容</p>
    </slot>
</template>

父组件
<Child>
  <div>默认插槽</div>  
</Child>

Named slot
subcomponent uses the name attribute to represent the name of the slot, and does not pass it as the default slot.

When using the parent component, add the slot attribute on the basis of the default slot, and the value is the value of the slot name attribute of the child component.

// 子组件Child.vue

<template>
    <slot>插槽后备的内容</slot>
  <slot name="content">插槽后备的内容</slot>
</template>

//父组件
<child>
    <template v-slot:default>具名插槽</template>
    <!-- 具名插槽⽤插槽名做参数 -->
    <template v-slot:content>内容...</template>
</child>

Scope slot
The sub-component binds properties on the scope to pass the sub-component information to the parent component for use. These properties will be hung on the objects accepted by the parent component v-slot.

In the parent component, v-slot: (abbreviation: #) is used to obtain the information of the child component and used in the content.

子组件Child.vue
<template> 
  <slot name="footer" testProps="子组件的值">
          <h3>没传footer插槽</h3>
    </slot>
</template>

父组件
<child> 
    <!-- 把v-slot的值指定为作⽤域上下⽂对象 -->
    <template v-slot:default="slotProps">
      来⾃⼦组件数据:{
   
   {slotProps.testProps}}
    </template>
  <template #default="slotProps">
      来⾃⼦组件数据:{
   
   {slotProps.testProps}}
    </template>
</child>

summary:

v-slot属性只能在<template>上使用,但在只有默认插槽时可以在组件标签上使用

默认插槽名为default,可以省略default直接写v-slot

缩写为#时不能不写参数,写成#default

可以通过解构获取v-slot={user},还可以重命名v-slot="{user: newName}"和定义默认值v-slot="{user = '默认值'}"

11.What is the understanding of mixin in Vue? And what are the application scenarios?

The function of Vue's mixin is to abstract public business logic. The principle is similar to object inheritance. When the component is initialized, the mergeOptions method will be called to merge, and the strategy mode is used to merge different attributes. If the mixed data conflicts with the data of the own component, the own data shall prevail.

12. What is the difference between Vue components and plugins?

13.What is Vue.Observable?

Vue.observable turns an object into responsive data. Vue will use it internally to process the object returned by the data function

The returned object can be used directly within rendering functions and computed properties, and will trigger corresponding updates when changes occur. Also serves as a minimized cross-component state store

Vue.observable({ count : 1})

其作用等同于
new vue({ count : 1})

In Vue 2.x, the object passed in will be directly modified by Vue.observable, which is the same object as the returned object.

In Vue 3.x, a responsive proxy will be returned, but direct changes to the source object are still unresponsive.

scenes to be used

When communicating between non-parent-child components, you can use the usual bus or use vuex, but the implemented function is not too complicated, and using the above two is a bit cumbersome. At this time, observable is a good choice

14.What is the principle of key in Vue?

In Vue, key is a special attribute used to help Vue identify and track changes in the virtual DOM. When Vue updates and renders the real DOM, it uses the key attribute to compare the old and new nodes, and reuses the existing real DOM nodes as much as possible to improve performance.

When Vue performs the diff algorithm of the virtual DOM, it will use the key to match the old and new nodes to determine the update, movement or deletion of the node. It uses the key attribute to determine whether two nodes represent the same entity, not just based on whether their contents are the same. This preserves the node's state and avoids unnecessary DOM manipulation.

The key works as follows:

When Vue updates and renders the real DOM, it compares the old and new nodes to find the differences between them.
If two nodes have the same key value, Vue considers them to be the same node and will try to reuse the existing real DOM node.
If nodes have different key values, Vue will treat them as different nodes and update, move, or delete them appropriately.
Using key can provide more accurate node identification and tracking, and avoid some common problems, such as element flickering and input box content loss caused by reordering in the list.

The key must be unique and stable. It is best to use a value with a unique identifier, such as the unique ID of the data. At the same time, it is not recommended to use random numbers as keys, because a new key will be generated every time it is updated, causing all nodes to be re-rendered, making it impossible to reuse existing nodes, and reducing performance.

More accurate : Because with the key, there is no in-place reuse. In the sameNode function a.key === b.key comparison, in-place reuse can be avoided. So it will be more accurate.

Faster : Use the uniqueness of the key to generate a map object to obtain the corresponding node, which is faster than the traversal method. The source code is as follows

function createKeyToOldIdx (children, beginIdx, endIdx) {
    
    
  let i, key
  const map = {
    
    }
  for (i = beginIdx; i <= endIdx; ++i) {
    
    
    key = children[i].key
    if (isDef(key)) map[key] = i
  }
  return map
}

15.What is the understanding of keep-alive in Vue?

keep-alive is a built-in component of Vue that allows included components to retain their state and avoid re-rendering. It has the following characteristics:

  • Generally used in combination with routing and dynamic components to cache components;

  • Provide include and exclude attributes, both of which support strings or regular expressions. include means that only components with matching names will be cached, exclude means that any components with matching names will not be cached, and exclude has a higher priority than include;

  • Corresponding to the two hook functions activated and deactivated, when the component is activated, the hook function activated is triggered, and when the component is removed, the hook function deactivated is triggered.

16.Axios is encapsulated in Vue?

17.How to divide structure and components in Vue project?

文件夹和文件夹内部文件的语义一致性
单一入口/出口
就近原则,紧耦合的文件应该放到一起,且应以相对路径引用
公共的文件应该以绝对路径的方式从根目录引用
/src 外的文件不应该被引入

18.How does Vue implement permission management? How to control permissions to button level?

Front-end permission control can be divided into four aspects:

接口权限
按钮权限
菜单权限
路由权限

Interface permissions

Interface permissions are currently verified in the form of jwt. If it fails, 401 is generally returned and jumps to the login page to log in again.

After logging in, you get the token, save the token, and intercept it through the axios request interceptor. Each request carries the token in the header.

axios.interceptors.request.use(config => {
    config.headers['token'] = cookie.get('token')
    return config
})
axios.interceptors.response.use(res=>{},{response}=>{
    if (response.data.code === 40099 || response.data.code === 40098) { //token过期或者错误
        router.push('/login')
    }
})

Routing permission control

Option One

Initialization means mounting all routes, and marking the corresponding permission information on the routes, and verifying each route before jumping.

const routerMap = [
  {
    
    
    path: '/permission',
    component: Layout,
    redirect: '/permission/index',
    alwaysShow: true, // will always show the root menu
    meta: {
    
    
      title: 'permission',
      icon: 'lock',
      roles: ['admin', 'editor'] // you can set roles in root nav
    },
    children: [{
    
    
      path: 'page',
      component: () => import('@/views/permission/page'),
      name: 'pagePermission',
      meta: {
    
    
        title: 'pagePermission',
        roles: ['admin'] // or you can only set roles in sub nav
      }
    }, {
    
    
      path: 'directive',
      component: () => import('@/views/permission/directive'),
      name: 'directivePermission',
      meta: {
    
    
        title: 'directivePermission'
        // if do not set roles, means: this page does not require permission
      }
    }]
  }]

This approach has the following four disadvantages:

加载所有的路由,如果路由很多,而用户并不是所有的路由都有权限访问,对性能会有影响。

全局路由守卫里,每次路由跳转都要做权限判断。

菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译

菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识

Option II

During initialization, first mount routes that do not require permission control, such as login pages, 404 and other error pages. If the user performs mandatory access through the URL, it will directly enter 404, which is equivalent to controlling the source.

After logging in, obtain the user's permission information, then filter the routes that have permission to access, and call addRoutes in the global routing guard to add routes.

import router from './router'
import store from './store'
import {
    
     Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'// progress bar style
import {
    
     getToken } from '@/utils/auth' // getToken from cookie

NProgress.configure({
    
     showSpinner: false })// NProgress Configuration

// permission judge function
function hasPermission(roles, permissionRoles) {
    
    
  if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
  if (!permissionRoles) return true
  return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

const whiteList = ['/login', '/authredirect']// no redirect whitelist

router.beforeEach((to, from, next) => {
    
    
  NProgress.start() // start progress bar
  if (getToken()) {
    
     // determine if there has token
    /* has token*/
    if (to.path === '/login') {
    
    
      next({
    
     path: '/' })
      NProgress.done() // if current page is dashboard will not trigger    afterEach hook, so manually handle it
    } else {
    
    
      if (store.getters.roles.length === 0) {
    
     // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetUserInfo').then(res => {
    
     // 拉取user_info
          const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
          store.dispatch('GenerateRoutes', {
    
     roles }).then(() => {
    
     // 根据roles权限生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({
    
     ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
          })
        }).catch((err) => {
    
    
          store.dispatch('FedLogOut').then(() => {
    
    
            Message.error(err || 'Verification failed, please login again')
            next({
    
     path: '/' })
          })
        })
      } else {
    
    
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        if (hasPermission(store.getters.roles, to.meta.roles)) {
    
    
          next()//
        } else {
    
    
          next({
    
     path: '/401', replace: true, query: {
    
     noGoBack: true }})
        }
        // 可删 ↑
      }
    }
  } else {
    
    
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
    
     // 在免登录白名单,直接进入
      next()
    } else {
    
    
      next('/login') // 否则全部重定向到登录页
      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
    }
  }
})

router.afterEach(() => {
    
    
  NProgress.done() // finish progress bar
})

To mount on demand, routing needs to know the user's routing permissions, that is, when the user logs in, he or she needs to know what routing permissions the current user has.

This method also has the following disadvantages:

全局路由守卫里,每次路由跳转都要做判断

菜单信息写死在前端,要改个显示文字或权限信息,需要重新编译

菜单跟路由耦合在一起,定义路由的时候还有添加菜单显示标题,图标之类的信息,而且路由不一定作为菜单显示,还要多加字段进行标识

Menu permissions

Menu permissions can be understood as decoupling the page from the reason

Option One

The menu is separated from the routing, and the menu is returned by the backend

Front-end defines routing information

{
    
    
    name: "login",
    path: "/login",
    component: () => import("@/pages/Login.vue")
}

The name field is not empty. This field needs to be associated with the back-end return menu. The menu information returned by the back-end must have a field corresponding to name and perform uniqueness verification.

Make judgments in the global routing guard

function hasPermission(router, accessMenu) {
    
    
  if (whiteList.indexOf(router.path) !== -1) {
    
    
    return true;
  }
  let menu = Util.getMenuByName(router.name, accessMenu);
  if (menu.name) {
    
    
    return true;
  }
  return false;

}

Router.beforeEach(async (to, from, next) => {
    
    
  if (getToken()) {
    
    
    let userInfo = store.state.user.userInfo;
    if (!userInfo.name) {
    
    
      try {
    
    
        await store.dispatch("GetUserInfo")
        await store.dispatch('updateAccessMenu')
        if (to.path === '/login') {
    
    
          next({
    
     name: 'home_index' })
        } else {
    
    
          //Util.toDefaultPage([...routers], to.name, router, next);
          next({
    
     ...to, replace: true })//菜单权限更新完成,重新进一次当前路由
        }
      }  
      catch (e) {
    
    
        if (whiteList.indexOf(to.path) !== -1) {
    
     // 在免登录白名单,直接进入
          next()
        } else {
    
    
          next('/login')
        }
      }
    } else {
    
    
      if (to.path === '/login') {
    
    
        next({
    
     name: 'home_index' })
      } else {
    
    
        if (hasPermission(to, store.getters.accessMenu)) {
    
    
          Util.toDefaultPage(store.getters.accessMenu,to, routes, next);
        } else {
    
    
          next({
    
     path: '/403',replace:true })
        }
      }
    }
  } else {
    
    
    if (whiteList.indexOf(to.path) !== -1) {
    
     // 在免登录白名单,直接进入
      next()
    } else {
    
    
      next('/login')
    }
  }
  let menu = Util.getMenuByName(to.name, store.getters.accessMenu);
  Util.title(menu.title);
});

Router.afterEach((to) => {
    
    
  window.scrollTo(0, 0);
});

Every time the route jumps, the permissions must be judged. The judgment here is also very simple, because the name of the menu corresponds to the name of the route one-to-one, and the menu returned by the backend has already been filtered by permissions.

If the corresponding menu cannot be found based on the route name, it means that the user has no permission to access it.

If there are many routes, you can only mount routes that do not require permission control during application initialization. After obtaining the menu returned by the backend, based on the corresponding relationship between the menu and the route, the accessible routes are filtered out and dynamically mounted through addRoutes.

Disadvantages of this approach:

菜单需要与路由做一一对应,前端添加了新功能,需要通过菜单管理功能添加新的菜单,如果菜单配置的不对会导致应用不能正常使用

全局路由守卫里,每次路由跳转都要做判断

Option II

Both menus and routes are returned by the backend

Front-end unified definition of routing components

const Home = () => import("../pages/Home.vue");
const UserInfo = () => import("../pages/UserInfo.vue");
export default {
    
    
    home: Home,
    userInfo: UserInfo
};
后端路由组件返回以下格式

[
    {
    
    
        name: "home",
        path: "/",
        component: "home"
    },
    {
    
    
        name: "home",
        path: "/userinfo",
        component: "userInfo"
    }
]

Before dynamically mounting the backend return route through addRoutes, you need to process the data and replace the component field with a real component.

If there are nested routes, when designing the back-end function, you should pay attention to adding the corresponding fields, and the front-end should also process the data accordingly when it gets it.

This approach also has disadvantages:

全局路由守卫里,每次路由跳转都要做判断
前后端的配合要求更高

Button permissions

Option One

Button permissions can also be determined using v-if

But if there are too many pages, each page must obtain the user permission role and meta.btnPermissions in the routing table, and then make a judgment.

I won’t give examples in this way.

Option II

Determine button permissions through custom instructions

首先配置路由

{
    
    
    path: '/permission',
    component: Layout,
    name: '权限测试',
    meta: {
    
    
        btnPermissions: ['admin', 'supper', 'normal']
    },
    //页面需要的权限
    children: [{
    
    
        path: 'supper',
        component: _import('system/supper'),
        name: '权限测试页',
        meta: {
    
    
            btnPermissions: ['admin', 'supper']
        } //页面需要的权限
    },
    {
    
    
        path: 'normal',
        component: _import('system/normal'),
        name: '权限测试页',
        meta: {
    
    
            btnPermissions: ['admin']
        } //页面需要的权限
    }]
}
自定义权限鉴定指令

import Vue from 'vue'
/**权限指令**/
const has = Vue.directive('has', {
    
    
    bind: function (el, binding, vnode) {
    
    
        // 获取页面按钮权限
        let btnPermissionsArr = [];
        if(binding.value){
    
    
            // 如果指令传值,获取指令参数,根据指令参数和当前登录人按钮权限做比较。
            btnPermissionsArr = Array.of(binding.value);
        }else{
    
    
            // 否则获取路由中的参数,根据路由的btnPermissionsArr和当前登录人按钮权限做比较。
            btnPermissionsArr = vnode.context.$route.meta.btnPermissions;
        }
        if (!Vue.prototype.$_has(btnPermissionsArr)) {
    
    
            el.parentNode.removeChild(el);
        }
    }
});
// 权限检查方法
Vue.prototype.$_has = function (value) {
    
    
    let isExist = false;
    // 获取用户按钮权限
    let btnPermissionsStr = sessionStorage.getItem("btnPermissions");
    if (btnPermissionsStr == undefined || btnPermissionsStr == null) {
    
    
        return false;
    }
    if (value.indexOf(btnPermissionsStr) > -1) {
    
    
        isExist = true;
    }
    return isExist;
};
export {
    
    has}

You only need to quote the v-has directive in the button you use

<el-button @click='editClick' type="primary" v-has>编辑</el-button>

19.How does Vue solve cross-domain issues?

JSONP

CORS

CORS (Cross-Origin Resource Sharing) is a system that consists of a series of transmitted HTTP headers that determine whether the browser blocks front-end JavaScript code from obtaining responses to cross-origin requests.

CORS is very convenient to implement. You only need to add some HTTP headers so that the server can declare allowed access sources.

As long as the backend implements CORS, cross-domain

Proxy

Proxy, also known as network proxy, is a special network service that allows one (usually a client) to make an indirect connection with another network terminal (usually a server) through this service. Some network devices such as gateways and routers have network proxy functions. It is generally believed that proxy services are helpful in ensuring the privacy or security of network terminals and preventing attacks.

The request is forwarded to the target server through this server, and the result is forwarded to the front end. However, if the web application and the interface server are not together when the final release is launched, it will still cross domains.

module.exports = {
    
    
    devServer: {
    
    
        host: '127.0.0.1',
        port: 8084,
        open: true,// vue项目启动时自动打开浏览器
        proxy: {
    
    
            '/api': {
    
     // '/api'是代理标识,用于告诉node,url前面是/api的就是使用代理的
                target: "http://xxx.xxx.xx.xx:8080", //目标地址,一般是指后台服务器地址
                changeOrigin: true, //是否跨域
                pathRewrite: {
    
     // pathRewrite 的作用是把实际Request Url中的'/api'用""代替
                    '^/api': "" 
                }
            }
        }
    }
}

20. How to deal with errors in Vue projects?

  • handleError is called where an exception needs to be caught. First, the component that reported the error is obtained, and then the parent component of the current component is recursively searched, and the errorCaptured method is called in sequence. After all errorCaptured methods are traversed and called or when an error is reported in the errorCaptured method, the globalHandleError method is called.
  • globalHandleError calls the global errorHandler method, and then uses logError to determine the environment to output error information.
  • invokeWithErrorHandling better handles asynchronous error messages
  • logError determines the environment and chooses different error throwing methods. In non-production environments, call the warn method to handle errors.

21. What is vue-router dynamic routing? What is the problem.

We often need to map all routes matching a certain pattern to the same component. For example, we have a
User component, which must be used to render all users with different IDs. Then, we can use "dynamic path parameters" (dynamic segment) in the routing path of vue-router to achieve this effect:

 const User = {
    
    
  template: " User", 
  };
 const router = new VueRouter({
    
    
 routes: [
 	// 动态路径参数 以冒号开头
 	{
    
     path: "/user/:id", component: User },
 ],
 });

Question: What should I do if routing parameters become invalid due to reuse of vue-router components?

Solution:
1. Monitor the routing parameters through watch and then send the request

 watch:{
    
    
 "router":function(){
    
    
	this.getData(this.$router.params.xxx)
 }
}

2. Use:key to prevent reuse

router-view :key=“$route.fullPath”

22. In what aspects is the performance improvement of Vue3 mainly reflected?

Vue 3.0 is on the road to release. The goal of Vue 3.0 is to make the Vue core smaller, faster, and more powerful. Therefore, Vue 3.0 adds the following new features: (1) Changes in monitoring
mechanism

  • 3.0 will bring an observer implementation based on proxy Proxy, providing reactive tracking with full language coverage. This eliminates many limitations of the Object.defineProperty-based implementation in Vue 2: only properties can be monitored, not objects.

    Detect the addition and deletion of attributes;

    Detect changes in array index and length;

    Supports Map, Set, WeakMap and WeakSet.

    The new observer also provides the following features: Public
    API for creating observables. This provides a simple and lightweight cross-component state management solution for small to medium-sized scenarios.

    Lazy observation is used by default. In 2.x, reactive data is observed on startup no matter how large it is. If your data set is large, this may introduce a noticeable overhead on application startup. In
    3.x, only the data used to render the initially visible portion of the application is observed.

    More precise change notifications. In 2.x, forcing a new property via Vue.set will cause watchers that depend on that object to be notified of the change. In 3.x
    , only watchers that depend on specific properties will receive notifications.

    Immutable observables: We can create "immutable" versions of values ​​(even nested properties) unless the system temporarily "unblocks" them internally. This mechanism can be used to freeze
    prop passes or changes outside of the Vuex state tree.

    Better debugging capabilities: We can use the new renderTracked and renderTriggered
    hooks to track exactly when and why a component re-renders.

(2) Template

  • There are no major changes in the template, only the scope slot is changed. The mechanism of 2.x causes the scope slot to change, and the parent component will be re-rendered, while 3.0 changes the scope slot to a function, so only It will affect the re-rendering of sub-components and improve rendering performance. At the same time, regarding the render function, vue3.0
    will also make a series of changes to facilitate the habit of directly using the API to generate vdom.

(3) Object-style component declaration method

  • Components in vue2.x pass in a series of options through declarations, and
    the combination with TypeScript needs to be done through some decorators. Although the function can be realized, it is more troublesome.
    3.0 modified the declaration method of components to a class writing method, which makes it easy to integrate with TypeScript. In addition, the source code of vue is also written in TypeScript. In fact, when the functions of the code are complex, there must be a static type system to do some auxiliary management. Now vue3.0 has been completely rewritten
    in TypeScript, which makes it easier to combine TypeScript with externally exposed APIs. A static type system is indeed necessary for the maintenance of complex code.

(4) Changes in other aspects

  • The changes in vue3.0 are comprehensive. The above only involves the main three aspects, and there are some other changes: Support custom renderers, so that weex can be
    extended by custom renderers instead of directly forking How to modify the source code.

    Supports Fragment (multiple root nodes) and Portal (rendering component content in other parts of the dom) components, and handles some special scenarios.

    Based on treeshaking optimization, more built-in functions are provided.

23.How to solve the problem of data loss when Vuex page is refreshed?

Vuex data persistence is required. Generally, a local storage solution is used to save data. You can design a storage solution yourself or use a third-party plug-in.

It is recommended to use the vuex-persist plug-in, which is a plug-in for Vuex persistent storage.

You do not need to manually access storage, but save the state directly to cookies or localStorage.

24.What is the difference between the Composition API in V3 and the Options API used in V2?

  • In terms of logical organization and logic reuse, Composition API is better than Options API
  • Because the Composition API is almost functions, there will be better type inference.
  • Composition API is tree-shaking friendly, and the code is easier to compress.
  • The use of this cannot be seen in the Composition API, which reduces the situation where this points to unknown objects.
  • If it is a small component, you can continue to use the Options API, which is also very friendly.

25.What problem does $attrs appear to solve?

The main function is to transfer data in batches.

provide/inject is more suitable for application in plug-ins, mainly to achieve cross-level data transfer.

26. Design a Model with Vue3?

27.What is Vuex? How many properties are there and what are their meanings?

Vuex is a state management pattern developed specifically for Vue.js applications. The core of every Vuex application is the store. A "store" is basically a container that contains most of the state in your application.

(1) Vuex’s state storage is responsive. When the Vue component reads the state from the store, if the state in the store changes, the corresponding component will be updated efficiently accordingly.

(2) The only way to change the state in the store is to explicitly submit a mutation. This allows us to easily track every state change.

It mainly includes the following modules:

  • State: Defines the data structure of the application state. The default initial state can be set here.
  • Getter: Allows components to obtain data from the Store. The mapGetters auxiliary function only maps the getters in the store to local calculated properties.
  • Mutation: is the only method to change the state in the store, and must be a synchronous function.
  • Action: used to submit mutations, rather than directly changing the state, and can contain any asynchronous operations.
  • Module: allows a single Store to be split into multiple stores and stored in a single state tree at the same time.

28.Have you ever used Vue SSR? Talk about SSR? How to achieve?

Vue.js is a framework for building client-side applications. By default, Vue components can be output in the browser to generate DOM and operate DOM. However, it is also possible to render the same component as an HTML string on the server side, send them directly to the browser, and finally "activate" these static tags into a fully interactive application on the client.
That is: SSR roughly means that the entire HTML fragment that Vue renders the tag into on the client is completed on the server, and the HTML fragment formed on the server is directly returned to the client. This process is called server-side rendering.

The advantages and disadvantages of server-side rendering SSR are as follows:
(1) Advantages of server-side rendering :

Better SEO: Because the content of the SPA page is obtained through Ajax, and the search engine crawling tool does not wait for Ajax to be completed asynchronously before crawling the page content, so the page obtained through Ajax cannot be crawled in the SPA. Content; SSR returns the rendered page directly from the server (the data is already included in the page), so search engine crawling tools can crawl the rendered page;

Faster content arrival time (faster loading of the first screen): SPA will wait for all Vue-compiled js files to be downloaded before starting to render the page. It takes a certain amount of time to download the files, so the first screen rendering requires A certain amount of time; SSR renders the page directly from the server and returns it to the display directly. There is no need to wait to download the js file and render it again, so SSR has a faster content arrival time;

(2) Disadvantages of server-side rendering :

More development restrictions: For example, server-side rendering only supports two hook functions beforeCreate and created, which will cause some external extension libraries to require special processing before they can run in server-side rendering applications; and can be deployed in any static file Different from the completely static single-page application SPA on the server, the server-side rendering application needs to be in the Node.js server running environment;

More server load: Rendering a complete application in Node.js will obviously be more CPU-intensive than a server that just serves static files, so if you anticipate running in a high-traffic environment (high traffic), please prepare the server load accordingly and adopt caching strategies wisely.

29.How to use Vuex auxiliary functions?

30. What does vue-loader do?

Before using vue-loader, we need to install some necessary loaders. .

Required loaders include: vue-loader, vue-style-loader, vue-template-compiler, css-loader. Possible loaders include: sass-loader, less-loader, url-loader, etc.

How vue-loader works

Through vue-loader, webpack can convert .vue files into javascript that can be recognized by the browser.

The workflow of vue-loader is, simply put, divided into the following steps:

将一个 .vue 文件 切割成 template、script、styles 三个部分。

template 部分 通过 compile 生成 render、 staticRenderFns。

获取 script 部分 返回的配置项对象 scriptExports。

styles 部分,会通过 css-loader、vue-style-loader, 添加到 head 中, 或者通过 css-loader、MiniCssExtractPlugin 提取到一个 公共的css文件 中。

使用 vue-loader 提供的 normalizeComponent 方法, 合并 scriptExports、render、staticRenderFns, 返回 构建vue组件需要的配置项对象 - options, 即 **{data, props, methods, render, staticRenderFns...}**。

31.How does computed implement caching?

  1. Initialize data and computed, proxy their set and get methods respectively, and generate unique dep instances for all attributes in data.
  2. Generate a unique watcher for the sum in computed and save it in vm._computedWatchers
  3. When the render function is executed, the sum attribute will be accessed, so that the getter method defined when initComputed is executed will point Dep.target to the watcher of sum, and the specific method sum of this attribute will be called.
  4. When accessing this.count in the sum method, the get method of the this.count agent will be called, the dep of this.count will be added to the watcher of sum, and the subs in the dep will add this watcher.
  5. Set vm.count = 2, call the set method of the count agent to trigger the notify method of dep, because it is a computed attribute, just set the dirty in the watcher to true.
  6. In the last step of vm.sum, when accessing its get method, it is learned that the watcher.dirty of sum is true, and its watcher.evaluate() method is called to obtain the new value.

32. What is the difference between computed and watch in vue?

computed: It is a computed attribute that depends on other attribute values, and the computed value is cached. Only when the attribute value it depends on changes, the computed value will be recalculated the next time the computed value is obtained;

watch: It is more of an "observation" function, similar to the monitoring callback of certain data. Whenever the monitored data changes, the callback will be executed for subsequent operations;

Application scenarios :

When we need to perform numerical calculations and depend on other data, computed should be used, because the cache feature of computed can be used to avoid recalculating every time the value is obtained;

Watch should be used when we need to perform asynchronous or expensive operations when data changes. Using the watch option allows us to perform an asynchronous operation (access an API), limit how often we perform the operation, and wait until we get the final result. , set the intermediate state. These are things that computed properties cannot do.

33.Vue page rendering process?

34.Why can’t Vue2 check changes in arrays? How to solve?

35.What properties does Vnode have?

The Vnode object defined internally by Vue contains the following properties:

  • __v_isVNode: true, internal attribute, this attribute is represented as Vnode
  • __v_skip: true, internal attribute, indicating to skip reactive conversion. Reactive conversion will be judged based on this attribute.
  • isCompatRoot?: true, used to determine whether compatibility processing has been done
  • type: VNodeTypes, the type of virtual node
  • props: (VNodeProps &ExtraProps) | null, virtual node props
  • key: string | number |null, the key of the virtual stage, can be used for diff
  • ref: VNodeNormalizedRef | null, reference to the virtual stage
  • scopeId: string | null, only for SFC (single file component), when setting currentRenderingInstance to the current rendering instance, it is set in one phase
  • slotScopeIds: string[] | null, limited to single-file components, related to the slot of single-file components
  • children:VNodeNormalizedChildren, child node
  • component: ComponentInternalInstance |null, component instance
  • dirs: DirectiveBinding[] | null, the instruction bound to the current Vnode
  • transition:TransitionHooks | null,TransitionHooks
  • DOM related properties

el: HostNode | null, host stage
anchor: HostNode | null // fragment anchor
target: HostElement | null, teleport target transmitted target
targetAnchor: HostNode | null // teleport target anchor
staticCount: number, the number of static nodes included

suspense Suspense related properties
suspense: SuspenseBoundary | null
ssContent: VNode | null
ssFallback: VNode | null

optimization only Properties used for optimization
shapeFlag: number
patchFlag: number
dynamicProps: string[] | null
dynamicChildren: VNode[] | null

The root node will have the attribute
appContext: AppContext | null, instance context.
You can see that inside Vue, there are about twenty attributes for a Vnode description object.

In order to reduce some of the burden on users without being too closed, Vue created rendering h. The corresponding Vnode can be created through the h function when the user needs it.

This leaves room for some advanced players to play freely.

36.In Vue routing, what is the difference between hash mode and history mode?

(1) Implementation principle of hash mode

The early implementation of front-end routing was based on location.hash. The implementation principle is very simple. The value of location.hash is the content after # in the URL. For example, the following website has a location.hash value of '#search':

https://www.word.com#search

The implementation of hash routing mode is mainly based on the following features:

  • The hash value in the URL is only a state of the client, which means that when a request is made to the server, the hash part will not be sent;

  • Any change in the hash value will add a record to the browser's access history. Therefore, we can control hash switching through the browser's back and forward buttons;

  • You can pass the a tag and set the href attribute. When the user clicks this tag, the hash value of the URL will change; or you can use JavaScript to assign a value to loaction.hash to change the hash value of the URL;

  • We can use the hashchange event to listen for changes in hash values ​​to jump (render) the page.

(2) Implementation principle of history mode

HTML5 provides History API to implement URL changes. Among them, the two most important APIs are: history.pushState() and history.repalceState(). These two APIs can operate the browser's history without refreshing.
The only difference is that the former adds a new history record, while the latter directly replaces the current history record, as shown below:

window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);

The implementation of history routing mode is mainly based on the following features:

  • There are two APIs, pushState and repalceState, to operate and implement URL changes;

  • We can use the popstate event to monitor changes in the url to jump (render) the page;

  • history.pushState() or history.replaceState() will not trigger the popstate event. In this case, we need to manually trigger the page jump (rendering).

37.Vue 2/3 responsive design principle?

v2

The overall idea is data hijacking + observer mode.
When Vue initializes data, it will use Object.defineProperty to redefine all properties in the data. When the page uses the corresponding properties, it will first perform dependency collection (collect the watcher of the current component). If the property Changes will notify relevant dependencies for update operations (publish and subscribe)

Vue2.x uses data hijacking combined with the publish-subscribe mode (PubSub mode) to hijack the setters and getters of each property through Object.defineProperty. When the data changes, it publishes messages to subscribers and triggers corresponding listening callbacks.

When you pass a plain Javascript object to a Vue instance as its data option, Vue will iterate through its properties and convert them into getters/setters using Object.defineProperty. The getters/setters are not visible to the user, but internally they allow Vue to track dependencies and notify changes when properties are accessed and modified.

Vue's two-way data binding integrates Observer, Compile and Watcher. Observer is used to monitor the data changes of its own model. Compile is used to parse and compile template instructions. Finally, Watcher is used to build a communication bridge between Observer and Compile to achieve Data changes -> view updates, view interactive changes (such as input operations) -> two-way binding effect of data model changes.

v3

Proxy will only proxy the first layer of the object, so how does Vue3 deal with this problem?
When monitoring an array, get/set may be triggered multiple times, so how to prevent multiple triggers?

Reference answer: What is the principle of responsive data in Vue3.x? In Vue 2, the responsive principle is implemented using Object.defineProperty. However, Proxy was adopted in Vue 3.0 and the Object.defineProperty method was abandoned.
The reasons are mainly the following:
Object.defineProperty cannot monitor changes in the array subscript, resulting in adding elements through the array subscript, and
cannot respond in real time. Object.defineProperty can only hijack the properties of the object, which requires each object. Each
attribute is traversed. If the attribute value is an object, depth traversal is also required. Proxy can hijack the entire object and return a new object.

Proxy can not only proxy objects, but also proxy arrays. You can also proxy dynamically added attributes. Proxy has as many as 13 interception methods. As a new standard, Proxy will be subject to continuous performance optimization by browser manufacturers. Proxy will only proxy the first layer of the object. So how does Vue3 deal with this problem? Determine whether the current return value of Reflect.get is Object. If so, use the reactive method as a proxy, thus achieving in-depth observation. When monitoring an array, get/set may be triggered multiple times, so how to prevent it from being triggered multiple times? We can determine whether the key is the attribute of the current proxied object target itself, or whether the old value and the new value are equal. Only when one of the above two conditions is met, the trigger can be executed.
Insert image description here

Insert image description here
Insert image description here

38.How to set global variables in Vue 3?

Method 1: config.globalProperties
vue2.x mounts globally using Vue.prototype.$xxxx=xxx the form, and then this.$xxxobtains the variables or methods mounted to the global.

In Vue 3, this is equivalent to config.globalProperties. These properties will be copied into the application as part of the instantiated component.

// 之前 (Vue 2.x)
Vue.prototype.$http = () => {}

// 之后 (Vue 3.x)
const app = createApp({})
app.config.globalProperties.$http = () => {}

Method 2 Provide / Inject
vue3’s new provide/inject function can penetrate multi-layer components and transfer data from parent components to child components.

You can place global variables in the provide of the root component so that all components can use this variable.

If you need the variable to be responsive, you need to use ref or reactive to wrap the variable when providing.

39.What is the principle of CSS scope in Vue?

40.How to compile Vue template?

The core of this problem is how to convert template into render function.

Convert template module into ast grammar book - parserHTML

Mark static syntax (some nodes do not change)

Regenerate code - codeGen, use the with syntax to wrap strings

41.Diff algorithm in Vue?

Simply put, the diff algorithm has the following process:
compare peers, and then compare child nodes

  • First determine if one party has child nodes
  • The case where one party has no child nodes (if the new children has no child nodes, the old child nodes will be removed) comparison
  • When both have child nodes (core diff) recursively compare child nodes
  • The time complexity of normal Diff between two trees is O(n^3), but in actual situations we rarely move the DOM across levels, so Vue has optimized Diff from O(n^3) -> O (n),
  • Only when the old and new children are multiple child nodes, the core Diff algorithm needs to be used for same-level comparison.

The core Diff algorithm of Vue2 adopts a double-end comparison algorithm. At the same time, it starts to compare from both ends of the old and new children, and uses the key value to find the reusable node, and then performs related operations. Compared with React's Diff algorithm, under the same circumstances, it can reduce the number of mobile nodes, reduce unnecessary performance losses, and is more elegant.

Vue3.x draws on the ivi algorithm and inferno algorithm
to determine the type of VNode when creating it, and uses bit operations to determine the type of a VNode during the mount/patch process. On this basis, it cooperates with the core Diff algorithm to improve performance. It has been improved compared to Vue2.x. This algorithm also uses the idea of ​​dynamic programming to solve the longest recursive subsequence.

42. How to deploy Vue project? Have you encountered the problem of refreshing 404 after deploying the server?

1. How to deploy

In the front-end and back-end separation development mode, the front-end and back-end are deployed independently. The front-end only needs to upload the final construction to the static directory specified by the web container of the target server.

We know that after the vue project is built, it generates a series of static files

For conventional deployment, we only need to upload this directory to the target server.

// scp upload user is the host login user, host is the host external network IP, xx is the web container static resource path
scp dist.zip user@host:/xx/xx/xx

Let the web container run, taking nginx as an example

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}
配置完成记得重启nginx

// 检查配置是否正确
nginx -t 

// 平滑重启
nginx -s reload
操作完后就可以在浏览器输入域名进行访问了

Of course, the above only mentions the simplest and most direct deployment method.

The essence of automation, mirroring, containers, and pipeline deployment is to abstract and isolate this set of logic, and use programs to replace repetitive labor. This article will not go into detail.

2. 404 problem

This is a classic question. I believe many students have encountered it. So do you know the real reason?

Let’s restore the scene first:

The vue project runs normally when it is local, but when it is deployed to the server and the page is refreshed, a 404 error occurs.
First locate it. The HTTP 404 error means that the resource pointed to by the link does not exist.

The question is why doesn't it exist? And why does this problem only occur in history mode?

Why is there a problem in history mode?
Vue is a single-page application (single-page application)

SPA is a model of a network application or website. All user interactions are by dynamically rewriting the current page. As we saw earlier, no matter how many pages we apply, the construct will only produce one index.html

Now, let's go back and look at our nginx configuration

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
  }
}

According to the nginx configuration, when we enter www.xxx.com in the address bar, the index.html file in our dist directory will be opened, and then we will jump to www.xxx.com/login in the jump route

The key here is that when we perform a refresh operation on the website.com/login page, the nginx location has no relevant configuration, so a 404 will occur.

Why is there no problem in
router hash mode? We all know that the hash mode is represented by the symbol #, such as website.com/#/login, the hash value is #/login

Its characteristic is that although the hash appears in the URL, it will not be included in the HTTP request and has no impact on the server at all, so changing the hash will not reload the page.

In hash mode, only the content before the hash symbol will be included in the request. For example, website.com/#/login only website.com will be included in the request. Therefore, for the server, even if the location is not configured, it will not Will return 404 error

3. Solution

After seeing this, I believe most students can think of how to solve the problem.

The essence of the problem is that our route performs view switching through JS.

When we enter the sub-route and refresh the page, if the web container does not have a corresponding page, 404 will appear.

So we only need to configure to redirect any page to index.html and leave the routing to the front end for processing.

Modify the nginx configuration file .conf and add try_files $uri $uri/ /index.html;

server {
  listen  80;
  server_name  www.xxx.com;

  location / {
    index  /data/dist/index.html;
    try_files $uri $uri/ /index.html;
  }
}
修改完配置文件后记得配置的更新

nginx -s reload

By doing this, your server will no longer return a 404 error page because the index.html file will be returned for all paths.

To avoid this, you should cover all routing situations in your Vue application and then give a 404 page

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

Regarding back-end configuration solutions: Apache, nodejs, etc., the ideas are the same, so I won’t go into details here.

43.v-if is not recommended to be used together with v-for?

Do not use v-for and v-if in the same tag, because v-for is parsed first and v-if is parsed during parsing. If you need to use them at the same time, you can consider writing them as calculated attributes.

Never use v-if and v-for on the same element at the same time, which will cause a waste of performance (each rendering will loop first and then perform conditional judgment)

If you want to avoid this situation, nest the template in the outer layer (page rendering does not generate dom nodes), perform v-if judgment at this layer, and then perform v-for loop internally

44.What are the communication methods between Vue components?

Communication between Vue components only refers to the following three types of communication: parent-child component communication, intergenerational component communication, and sibling component communication. Below we introduce each communication method separately and explain which types of inter-component communication this method can be applied to.

(1) props / $emit is suitable for parent-child component communication.
This method is the basis of Vue components. I believe most students are familiar with it, so I will not introduce it here with examples.

(2) ref and $parent / $children are suitable for parent-child component communication
ref: if used on a normal DOM element, the reference points to the DOM element; if used on a child component, the reference points to the component instance
$parent / $children: Access parent/child instances

(3) EventBus ($emit / $on) This method is suitable for parent-child, intergenerational, and sibling component communication. This method
uses an empty Vue instance as the central event bus (event center), and uses it to trigger events and monitor events to achieve Communication between any components, including parent-child, generation-skipping, and sibling components.

(4) a t t r s / attrs/ a tt rs / listeners is suitable for cross-generation component communication
$attrs: it includes property bindings (except class and style) that are not recognized (and obtained) by prop in the parent scope. When a component does not declare any props, all parent scope bindings (except class and style) will be included here, and can be passed in to v-bind="$attrs"internal components. Usually used together with the inheritAttrs option.
$listeners: Contains v-on event listeners in the parent scope (without .native modifier). It can bev-on="$listeners"passed into the internal component

(5) Provide/inject is suitable for intergenerational component communication.
Provide variables through provider in ancestor components, and then inject variables through inject in descendant components. The provide / inject API mainly solves the communication problem between cross-level components, but its usage scenario is mainly for sub-components to obtain the status of superior components, and a relationship between active provision and dependency injection is established between cross-level components.

(6) Vuex is suitable for parent-child, intergenerational, and sibling component communication.
Vuex is a state management model specially developed for Vue.js applications. The core of every Vuex application is the store. A "store" is basically a container that contains most of the state in your application.
Vuex's state storage is reactive. When the Vue component reads the state from the store, if the state in the store changes, the corresponding component will be updated efficiently accordingly.
The only way to change the state in the store is to explicitly commit a mutation. This allows us to easily track every state change.

45.What is the Tree shaking feature in Vue? Give an example?

1.What is

Tree shaking is a technology that optimizes project packaging volume by eliminating redundant code. The technical term is Dead code elimination.

To put it simply, it is to remove useless code while keeping the code running results unchanged.

If packaging code is compared to making a cake, the traditional way is to throw in all the eggs (with shells) and mix them, then put them in the oven, and finally select and remove all the (useless) eggshells.

In treeshaking, useful egg whites and yolks (import) are put into the mix at the beginning, and finally the cake is made directly.

In other words, tree shaking is actually finding out the code used

In Vue2, no matter what features we use, they end up in production code. The main reason is that the Vue instance is a singleton in the project, and the bundler cannot detect which properties of the object are used in the code.

import Vue from 'vue'

Vue.nextTick(() => {
    
    })

The Vue3 source code introduces the tree shaking feature to divide the global API into chunks. If you don't use some of its features, they won't be included in your base package

import {
    
     nextTick, observable } from 'vue'

nextTick(() => {
    
    })

2.How to do it

Tree shaking is based on ES6 template syntax (import and export). It mainly relies on the static compilation idea of ​​ES6 modules to determine the dependencies of the module and the input and output variables at compile time.

Tree shaking does nothing more than do two things:

During the compilation phase, use ES6 Module to determine which modules have been loaded,
determine which modules and variables are not used or referenced, and then delete the corresponding code.

3. Function

Through Tree shaking, the benefits Vue3 brings us are:

  • Reduce program size (smaller)
  • Reduce program execution time (faster)
  • Facilitate optimization of program architecture in the future (more friendly)

46.What is the difference between $route and $router?

In Vue.js, $route and $router are both routing-related objects, but they have the following differences:

  1. $route: $route It is an object of current routing information, including current URL path, query parameters, path parameters and other information. $route The object is read-only, and its attribute values ​​cannot be modified directly, but need to be updated through routing jumps.

  2. $router: $routerIt is an instance object of Vue Router, including many APIs for navigation control and routing operations, such as push, replace, go, forward and other methods. $router It can be used to dynamically change the URL to achieve refresh-free jumps between pages.

Therefore, $routeit $routeris different in function. It is $routemainly used to obtain the current routing information, $router while it is used to perform routing operations, such as jumping to a specified route, forward, backward, etc. Generally speaking, $routeand $routerare closely related and often used together.

47.What is the difference between V3 and V2?

Here is a summary of some of the main differences:

  • Reactive system : Vue 3 introduces the Composition API, a new reactive system. Composition API provides a more flexible and powerful way to manage component state and logic, making code organization and reuse more convenient. The Composition API uses functions instead of objects, which can improve tree shaking optimization and reduce packaging size.

  • Smaller package size : Vue 3 has a smaller package size than Vue 2 through better Tree Shaking and more efficient runtime code generation. Vue 3’s responsive system has also been optimized for better performance.

  • Performance improvements : Vue 3 features a faster, more efficient rendering mechanism thanks to a new compiler. The differentiation algorithm of the virtual DOM has been optimized to reduce unnecessary updates and improve rendering performance.

  • Scoped slots replaced by : In Vue 3, the concept of scoped slots is replaced by a more intuitive and simplified syntax, making it easier to define and use slots in component compositions.

  • Introducing the Teleport component : Vue 3 introduced the Teleport component, which can render content at different locations in the DOM tree and is used to create modal boxes, tooltips, and other overlay effects.

  • Fragments : Vue 3 introduced a built-in component called Fragment that allows multiple elements to be grouped without adding additional wrapping elements.

  • Better TypeScript support : Vue 3 provides better TypeScript support by default, with enhanced type inference and better integration with TypeScript tools.

  • Simplified API : Vue 3 has simplified and optimized many APIs, making it easier to learn and use the framework. The new API provides better consistency and greater alignment with JavaScript standards.

While Vue 3 introduces these changes, it maintains backward compatibility with the Vue 2 API, allowing existing Vue 2 projects to be upgraded incrementally. Vue 3 provides a migrated build that is compatible with most Vue 2 code, making the transition smoother for developers.

Overall, Vue 3 brings significant improvements in performance, package size, and developer experience, while introducing the Composition API as a more powerful tool for managing component state and logic.

48.What are the advantages of Vue’s responsive development over imperative development?

Vue's responsive development has the following advantages over imperative development:

  1. Simplified code: In Vue, view updates are automated by binding data and templates, thereby avoiding the tedious and error-prone operations of manual DOM manipulation. As a result, the time required to write boilerplate code and debug code can be significantly reduced.

  2. Improve maintainability: Responsive development using Vue can help us manage the state of the application more conveniently and handle state changes uniformly. This not only improves code readability and maintainability, but also makes unit testing and integration testing easier.

  3. Enhanced user experience: Through Vue's responsive development, functions such as partial updates and asynchronous loading can be implemented, thereby improving the user experience. For example, when an item is added or removed from a list, only the corresponding item needs to be updated instead of re-rendering the entire list. For another example, when loading a large number of images, asynchronous loading and lazy loading can be used to improve page loading speed and user experience.

  4. Support complex component design: Vue's responsive development supports component-based design, which can easily split a large application into multiple small, reusable components. These components can be nested and combined as needed to form a more complex and rich UI interface, and each component has an independent state and life cycle.

In short, Vue's responsive development can help us conduct front-end development more efficiently, conveniently, and flexibly, thereby providing a better user experience and higher code quality.

49.What are the commonly used modifiers in Vue? What application scenarios are they used for?

1. What are modifiers?

In the programming world, a modifier is a symbol used to qualify types and declarations of type members.

In Vue, modifiers handle many details of DOM events, so that we no longer need to spend a lot of time dealing with these troublesome things, but can have more energy to focus on the logic processing of the program.

Modifiers in Vue are divided into the following five types:

表单修饰符
事件修饰符
鼠标按键修饰符
键值修饰符
v-bind修饰符

2. The role of modifiers


The most commonly used form modifier is the input tag when we fill in the form, and the most commonly used command is v-model.

Modifiers about the form are as follows:

lazy
trim
number
lazy

After we fill in the information and the cursor leaves the label, the value will be assigned to value, that is, the information will be synchronized after the change event.

  • lazy
<input type="text" v-model.lazy="value">
<p>{
    
    {
    
    value}}</p>
  • trim
    automatically filters the first space character entered by the user, but the spaces in the middle will not be filtered
<input type="text" v-model.trim="value">
  • number
    automatically converts the user's input value into a numeric type, but if the value cannot be parsed by parseFloat, the original value will be returned.
<input v-model.number="age" type="number">

Event modifiers
event modifiers process event capture and targets. They have the following modifiers:

stop
prevent
self
once
capture
passive
native
  • stop
    prevents the event from bubbling, which is equivalent to calling the event.stopPropagation method.
<div @click="shout(2)">
  <button @click.stop="shout(1)">ok</button>
</div>
//只输出1
  • prevent
    prevents the default behavior of the event, which is equivalent to calling the event.preventDefault method
<form v-on:submit.prevent="onSubmit"></form>
  • self
    only triggers the handler function when event.target is the current element itself
<div v-on:click.self="doThat">...</div>

When using modifiers, order matters; the corresponding code will be generated in the same order. Therefore, using v-on:click.prevent.self will prevent all clicks, while v-on:click.self.prevent will only prevent clicks on the element itself.

  • After once
    is bound, the event can only be triggered once, and it will not be triggered the second time.
<button @click.once="shout(1)">ok</button>
  • capture
    causes the event to fire from the top level containing this element downwards.
<div @click.capture="shout(1)">
    obj1
<div @click.capture="shout(2)">
    obj2
<div @click="shout(3)">
    obj3
<div @click="shout(4)">
    obj4
</div>
</div>
</div>
</div>
// 输出结构: 1 2 4 3 
  • Passive
    On the mobile side, when we are listening to element scroll events, the onscroll event will always be triggered and our webpage will become stuck. Therefore, when we use this modifier, it is equivalent to adding a .lazy modifier to the onscroll event.
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>

Do not use .passive and .prevent together as .prevent will be ignored and the browser may show you a warning.

passive tells the browser that you don't want to block the default behavior of the event

  • Native
    allows the component to listen to the native events of the root element like the built-in HTML tag. Otherwise, using v-on on the component will only listen to custom events.
<my-component v-on:click.native="doSomething"></my-component>

Using the .native modifier to operate on ordinary HTML tags will invalidate the event.

Mouse button modifiers
Mouse button modifiers are for left, right, and middle clicks, as follows:

left 左键点击
right 右键点击
middle 中键点击
<button @click.left="shout(1)">ok</button>
<button @click.right="shout(1)">ok</button>
<button @click.middle="shout(1)">ok</button>

Keyboard modifiers
Keyboard modifiers are used to modify keyboard events (onkeyup, onkeydown), as follows:

There are many keyCode, but vue provides us with aliases, which are divided into the following two types:

Ordinary keys (enter, tab, delete, space, esc, up...)
system modifier keys (ctrl, alt, meta, shift...)
// Only triggered when the key is keyCode

<input type="text" @keyup.keyCode="shout()">

You can also customize some global keyboard code aliases in the following ways

Vue.config.keyCodes.f2 = 113

v-bind modifier
v-bind modifier is mainly used to operate properties, and is used as follows:

sync
prop
camel
sync

Can perform a two-way binding on props

//父组件
<comp :myMessage.sync="bar"></comp> 
//子组件
this.$emit('update:myMessage',params);
以上这种方法相当于以下的简写

//父亲组件
<comp :myMessage="bar" @update:myMessage="func"></comp>
func(e){
    
    
 this.bar = e;
}
//子组件js
func2(){
    
    
  this.$emit('update:myMessage',params);
}

When using sync, you need to pay attention to the following two points:

When using sync, the event name format passed by the subcomponent must be update:value, where value must be exactly the same as the name declared in the props in the subcomponent.

Note that v-bind with the .sync modifier cannot be used with expressions

Using v-bind.sync on a literal object, such as v-bind.sync="{ title: doc.title }", will not work properly.

  • props
    sets custom tag attributes to avoid exposing data and preventing contamination of the HTML structure
<input id="uid" title="title1" value="1" :index.prop="index">
  • camel
    changes the name to camel case, such as converting the view-Box attribute name to viewBox
<svg :viewBox="viewBox"></svg>

3. Application scenarios

According to the function of each modifier, we can get the following application scenarios of the modifier:

.stop:阻止事件冒泡
.native:绑定原生事件
.once:事件只执行一次
.self :将事件绑定在自身身上,相当于阻止事件冒泡
.prevent:阻止默认事件
.capture:用于事件捕获
.once:只触发一次
.keyCode:监听特定键盘按下
.right:右键

50.What is the execution order of Vue’s parent component and child component life cycle hook functions?

The execution sequence of Vue's parent component and child component life cycle hook functions can be classified into the following 4 parts:

Load rendering process

father beforeCreate -> father created -> father beforeMount -> child beforeCreate -> child created -> child beforeMount -> child mounted -> father mounted

Subcomponent update process

Father beforeUpdate -> Child beforeUpdate -> Child updated -> Father updated

Parent component update process

father beforeUpdate -> father updated

destruction process

father beforeDestroy -> child beforeDestroy -> child destroyed -> father destroyed

51. Why is data in the component a function?

Why does the data in the component have to be a function and then return an object, but in the new Vue instance, the data can be directly an object?

// data
data() {
    
    
  return {
    
    
    message: "子组件",
    childName:this.name
  }
}

// new Vue
new Vue({
    
    
  el: '#app',
  router,
  template: '<App/>',
  components: {
    
    App}
})

Because components are used for reuse, and objects in JS are reference relationships, if the data in the component is an object, then the scope is not isolated, and the data attribute values ​​​​in the sub-component will affect each other. If the data option in the component is
an function, then each instance can maintain an independent copy of the returned object, and the data attribute values ​​​​between component instances will not affect each other; and new Vue instances will not be reused, so there is no reference object The problem.

52.How to dynamically bind Class and Style?

Class can be dynamically bound through object syntax and array syntax:
Object syntax:

<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>

data: {
    
    
  isActive: true,
  hasError: false
}

Array syntax:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

data: {
    
    
  activeClass: 'active',
  errorClass: 'text-danger'
}

Style can also be dynamically bound through object syntax and array syntax:
Object syntax:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
    
    
  activeColor: 'red',
  fontSize: 30
}

Array syntax:

<div v-bind:style="[styleColor, styleSize]"></div>

data: {
    
    
  styleColor: {
    
    
     color: 'red'
   },
  styleSize:{
    
    
     fontSize:'23px'
  }
}

53.How to understand Vue’s one-way data flow?

All props form a one-way downward binding between their parent and child props: updates from the parent prop will flow downward to the child component, but not vice versa.

This will prevent the child component from accidentally changing the state of the parent component, making the data flow of your application difficult to understand.

In addition, every time the parent component is updated, all props in the child component will be refreshed to the latest values.
This means you should not change props inside a child component. If you do this, Vue will issue a warning in the browser's console.

When a child component wants to modify it, it can only dispatch a custom event through $emit. After the parent component receives it, it will be modified by the parent component.

There are two common situations when trying to change a prop:

  • This prop is used to pass an initial value; the subcomponent then wants to use it as a local prop data. In this case, it's better to define a local data property and use this prop as its initial value:
props: ['initialCounter'],
data: function () {
    
    
  return {
    
    
    counter: this.initialCounter
  }
}
  • This prop is passed in as a raw value and needs to be converted. In this case it is better to define a computed property using the value of this prop
props: ['size'],
computed: {
    
    
  normalizedSize: function () {
    
    
    return this.size.trim().toLowerCase()
  }
}

54. If you directly assign a value to an array item, can Vue detect the change?

Due to JavaScript limitations, Vue cannot detect the following array changes:
when you directly set an array item using the index, for example: vm.items[indexOfItem] = newValue

When you modify the length of the array, for example: vm.items.length = newLength

To solve the first problem, Vue provides the following methods:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

To solve the second problem, Vue provides the following operation methods:

// Array.prototype.splice
vm.items.splice(newLength)

55. In which life cycle are asynchronous requests called?

It can be called in the hook functions created, beforeMount, and mounted, because in these three hook functions, data has been created, and the data returned by the server can be assigned. However, I recommend calling asynchronous requests in the created hook function, because calling asynchronous requests in the created hook function has the following advantages:
server data can be obtained faster and page loading time can be reduced;

ssr does not support beforeMount and mounted hook functions, so placing them in created helps with consistency;

56. At what stage can the DOM be accessed and manipulated?

Before the hook function mounted is called, Vue has mounted the compiled template on the page, so the DOM can be accessed and manipulated in mounted.
The specific life cycle diagram of vue can be found below. Once you understand the operations of each stage of the entire life cycle, you will not be able to trouble you with life cycle-related interview questions.
Insert image description here

57. Can parent components monitor the life cycle of child components?

For example, if there is a parent component Parent and a child component Child, if the parent component detects that the child component is mounted, it will do some logical processing. This can be achieved by writing as follows:

// Parent.vue
<Child @mounted="doSomething"/>

// Child.vue
mounted() {
    
    
  this.$emit("mounted");
}

The above requires manually triggering the event of the parent component through $emit. A simpler way is to listen through @hook when the parent component refers to the child component, as shown below:

//  Parent.vue
<Child @hook:mounted="doSomething" ></Child>

doSomething() {
    
    
   console.log('父组件监听到 mounted 钩子函数 ...');
},

//  Child.vue
mounted(){
    
    
   console.log('子组件触发 mounted 钩子函数 ...');
},    

// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...

Of course, the @hook method can not only monitor mounted, but also other life cycle events, such as created, updated, etc.

58. What is the principle of v-model?

In the vue project, we mainly use the v-model directive to create two-way data binding on form input, textarea, select and other elements. We know that v-model is essentially just syntactic sugar. v-model is used internally for different input elements. Different attributes and throw different events:
text and textarea elements use value attributes and input events;

checkbox and radio use the checked attribute and change event;

The select field has value as prop and change as event.

Take the input form element as an example:

<input v-model='something'>

相当于

<input v-bind:value="something" v-on:input="something = $event.target.value">

If in a custom component, v-model will use the prop named value and the event named input by default, as shown below:

父组件:
<ModelChild v-model="message"></ModelChild>

子组件:
<div>{
    
    {
    
    value}}</div>

props:{
    
    
    value: String
},
methods: {
    
    
  test1(){
    
    
     this.$emit('input', '小红')
  },
},

59.How many routing modes does vue-router have?

vue-router has 3 routing modes: hash, history, and abstract. The corresponding source code is as follows:

switch (mode) {
    
    
  case 'history':
    this.history = new HTML5History(this, options.base)
    break
  case 'hash':
    this.history = new HashHistory(this, options.base, this.fallback)
    break
  case 'abstract':
    this.history = new AbstractHistory(this, options.base)
    break
  default:
    if (process.env.NODE_ENV !== 'production') {
    
    
      assert(false, `invalid mode: ${
      
      mode}`)
    }
}

Among them, the descriptions of the three routing modes are as follows:

  • hash: Use URL hash value for routing. Supports all browsers, including browsers that do not support HTML5 History API;
  • history: relies on HTML5 History API and server configuration. For details, you can view the HTML5 History mode;
  • abstract: Supports all JavaScript runtime environments, such as Node.js server side. If it is found that there is no browser API, the routing will automatically force into this mode.

60.What is MVVM?

Model–View–ViewModel (MVVM) is a software architecture design pattern developed by Ken Cooper and Ted Peters, architects of Microsoft WPF and Silverlight. It is an event-driven programming method that simplifies the user interface.

MVVM originates from the classic Model–View–Controller (MVC) pattern. The emergence of MVVM promotes the separation of front-end development and back-end business logic, greatly improving the efficiency of front-end development. The core of MVVM is the ViewModel layer, which is like A transfer station (value converter), responsible for converting data objects in the Model to make the data easier to manage and use. This layer performs two-way data binding with the view layer upwards, and interacts with the Model layer through interface requests downwards. It plays the role of linking up and down.

As shown below:
Insert image description here

(1) View layer
View is the view layer, which is the user interface. The front-end is mainly built with HTML and CSS.

(2) Model layer
Model refers to the data model, which generally refers to various business logic processing and data manipulation performed by the back end. For the front end, it is the API interface provided by the back end.

(3) ViewModel layer
ViewModel is a view data layer generated and maintained by front-end developers. At this layer, the front-end developer converts the Model data obtained from the back-end and performs secondary encapsulation to generate a view data model that meets the expectations of the View layer.

It should be noted that the data model encapsulated by ViewModel includes the state and behavior of the view, while the data model of the Model layer only contains state, such as what is displayed in this part of the page and what happens when the page is loaded. Click here What happens to a block and what happens when this block is scrolled all belong to view behavior (interaction). View state and behavior are encapsulated in ViewModel. Such encapsulation allows ViewModel to completely describe the View layer.

The MVVM framework implements two-way binding, so that the content of the ViewModel will be displayed in the View layer in real time. Front-end developers no longer have to inefficiently and troublesomely update the view by manipulating the DOM. The MVVM framework has already done the dirtiest and most tiring part. , we developers only need to process and maintain the ViewModel, and the updated data view will automatically be updated accordingly.

In this way, the View layer displays not the data of the Model layer, but the data of the ViewModel. The ViewModel is responsible for interacting with the Model layer. This completely decouples the View layer and the Model layer. This decoupling is crucial. It is the front-end and back-end An important part of the separation plan implementation.

We will use a Vue example to illustrate the specific implementation of MVVM below. Students with Vue development experience should understand it at a glance:
(1) View layer

<div id="app">
    <p>{
    
    {
    
    message}}</p>
    <button v-on:click="showMessage()">Click me</button>
</div>

(2) ViewModel layer

var app = new Vue({
    
    
    el: '#app',
    data: {
    
      // 用于描述视图状态
        message: 'Hello Vue!', 
    },
    methods: {
    
      // 用于描述视图行为
        showMessage(){
    
    
            let vm = this;
            alert(vm.message);
        }
    },
    created(){
    
    
        let vm = this;
        // Ajax 获取 Model 层的数据
        ajax({
    
    
            url: '/your/server/data/api',
            success(res){
    
    
                vm.message = res;
            }
        });
    }
})

(3) Model layer

{
    
    
    "url": "/your/server/data/api",
    "res": {
    
    
        "success": true,
        "name": "IoveC",
        "domain": "www.cnblogs.com"
    }
}

61.How does the Vue framework implement monitoring of objects and arrays?

The method of detecting array changes in Vue2.x is to rewrite the common methods of arrays. Vue rewrites the prototype chain of the array in data, pointing to its own defined array prototype method. In this way, dependency updates can be notified when the array api is called. If the array contains reference types, the reference types in the array will be traversed recursively again for monitoring. This enables monitoring of array changes.

Process :

  1. Initialize the incoming data and execute initData
  2. Observe the data using new Observer
  3. Point array prototype method to overridden prototype
  4. Deep look at reference types in arrays

There are two situations where changes to the array cannot be detected.

  1. When setting an array item directly using the index, for example vm.items[indexOfItem] = newValue
  2. When modifying the length of the array, for example vm.items.length = newLength

However, there are corresponding solutions for both scenarios. Alternative to using index to set array items
//Use this method to update the view

// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)

62. Comparison of pros and cons between Proxy and Object.defineProperty

The advantages of Proxy are as follows:

  • Proxy can directly monitor objects instead of properties;
  • Proxy can directly monitor changes in the array;
  • Proxy has as many as 13 interception methods, not limited to apply, ownKeys, deleteProperty, has, etc., which Object.defineProperty does not have;
  • Proxy returns a new object. We can only operate the new object to achieve the goal, while Object.defineProperty can only traverse the object properties and modify them directly;
  • As a new standard, Proxy will be subject to continuous performance optimization by browser manufacturers, which is the legendary performance bonus of the new standard;

The advantages of Object.defineProperty are as follows:

  • It has good compatibility and supports IE9. However, Proxy has browser compatibility issues and cannot be smoothed with polyfill. Therefore, the author of Vue stated that it needs to wait until the next major version (3.0) before it can be rewritten with Proxy.

63. How does Vue use vm.$set() to solve the problem of objects not being able to respond to new attributes?

Due to the limitations of modern JavaScript, Vue cannot detect the addition or removal of object properties.
Since Vue will perform getter/setter conversion on the property when initializing the instance, the property must exist on the data object in order for Vue to convert it to reactive.
But Vue provides Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value) to add responsive properties to objects. So how does the framework itself implement it?

Let’s check the corresponding Vue source code:

export function set (target: Array<any> | Object, key: any, val: any): any {
    
    
  // target 为数组
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    
    
    // 修改数组的长度, 避免索引>数组长度导致splcie()执行有误
    target.length = Math.max(target.length, key)
    // 利用数组的splice变异方法触发响应式
    target.splice(key, 1, val)
    return val
  }
  // key 已经存在,直接修改属性值
  if (key in target && !(key in Object.prototype)) {
    
    
    target[key] = val
    return val
  }
  const ob = (target: any).__ob__
  // target 本身就不是响应式数据, 直接赋值
  if (!ob) {
    
    
    target[key] = val
    return val
  }
  // 对属性进行响应式处理
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

From reading the above source code, we can see that the implementation principle of vm.$set is:

  • If the target is an array, directly use the splice method of the array to trigger the corresponding expression;
  • If the target is an object, it will first determine whether the attribute exists and whether the object is reactive. Finally, if you want to perform responsive processing on the attribute, you will perform responsive processing by calling the defineReactive method (the defineReactive method is when Vue initializes the object, gives the object The property uses the method called by Object.defineProperty to dynamically add getter and setter functions)

64 Custom instructions? Application scenario?

In Vue, custom directives are a mechanism for extending Vue's template syntax. With custom directives, you can add custom behaviors to DOM elements and perform corresponding operations when elements are inserted, updated, and removed.

Custom directives are defined by the Vue.directive function, which receives two parameters: the directive name and the directive options object. The directive options object contains a series of hook functions that define the behavior of the directive.

The following are some common application scenarios for custom instructions:

  • Manipulate DOM: Custom instructions can be used to directly manipulate DOM elements, such as modifying the element's style, attributes, event binding, etc. You can access and manipulate DOM elements through the directive's hook function
    .

  • Form validation: You can create custom directives to implement form validation logic. Through custom instructions, you can monitor the value changes of the input box and perform validation based on custom validation rules to provide real-time feedback.

  • Permission control: Custom instructions can be used in permission control scenarios, such as hiding or disabling certain elements based on user permissions. You can perform conditional judgments based on user permissions in custom instructions and modify the display or behavior of elements.

  • Third-party library integration: When you need to use third-party libraries or plug-ins in Vue, you can use custom instructions for integration. You can create a custom directive in which you initialize and configure a third-party library and call the library's methods at appropriate times.

  • Animation and transition effects: Custom directives can be used with Vue’s transition system to implement custom animations and transition effects. You can listen to the transition hook function in a custom directive and manipulate the element's style or class name as needed to achieve the transition effect.

These are just some common application scenarios. In fact, custom instructions have a very wide range of applications and can be used flexibly according to specific needs. Through custom instructions, you can extend Vue's capabilities and achieve more complex and flexible interactive behaviors.

Guess you like

Origin blog.csdn.net/2201_75499330/article/details/131437792