2022年最新Vue常见基础面试题(看这一篇就够了)

文章目录

vue 的两个核心🌟🌟

组件系统、数据驱动

什么是双向数据绑定?🌟🌟🌟

v-model,数据发生变化,同步视图,视图发生变化,同步数据

什么是单向数据流?🌟🌟🌟

在父向子传值的时候,如果改变父组件的值,子组件会跟着同步更新,反之不允许

MVVM 的设计思想的优势?🌟🌟🌟

  • 双向绑定技术,当 Model 变化时,View 也会自动变化,view 发生更新,model 也跟着同步
  • 我们减少了 dom 的操作,因为我们只需要关注数据就可以
  • mvvm 的设计思想大大提高了代码的耦合性

事件传参🌟🌟🌟🌟

  • 没有传递参数,事件函数的默认第一个参数是事件对象
  • 如果传递了参数,事件函数就没有了默认参数,全部变为对应位置的实参的形参,就没有了事件对象
  • 既有自己传的的参数,也有事件对象,通过$event 传递事件对象,在事件函数内部通过对应位置的形参来接收事件对象,传递 $event 没有强制性的位置,但是建议放在最后

自定义指令:directive🌟🌟🌟

为什么自定义指令?

vue 提供的系统指令满足不了我们的需求,那么我们就需要自定义指令

通过 Vue.directive 进行自定义指令的定义

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

计算属性:computed🌟🌟🌟🌟🌟

定义的时候是一个方法,使用的时候当作属性使用

只要 return 后面的数据发生变化,该计算属性就会重新计算

计算属性具有缓存特性

监听器:watch🌟🌟🌟🌟🌟

可以监听数据发生变化,可以监听的数据有(props、data、computed、$route) watch 侦听器如果监听的是一个对象,需要开启深度监听

watch:{
  num:{
    // 监听数据发生变化的处理函数
    handler(newNum) {
      console.log(newNum)
    },
    // 是否开启深度监听
    deep: true
  }
}

如果想实现首次监听配置 immediate 为 true

过滤器🌟🌟🌟🌟

可以对数据格式进行处理,例如常用的例如格式化时间 使用方式通过 数据名 |(管道符)后面跟过滤器的名字

生命周期函数🌟🌟🌟🌟🌟

生命周期:是指一个对象从创建到运行到销毁的整个过程,被称为生命周期

生命周函数:在不同的生命周期阶段会自动执行对应的函数,而这些函数则被成为生命周期函数

// 创建阶段
      beforeCreate() {
        // 这个生命周函数,代表开始创建实例了
        console.log('beforeCreate',this.num)
      },
      created () {
        // 代表数据和方法已经初始化成功了,此处dom还没有挂载到页面上
        console.log('created',this.num,this.$el)
      },
      beforeMount () {
        // 挂在之前
        console.log('beforeMount',this.$el)
      },
      mounted () {
        // dom已经挂载了
        console.log('mounted',this.$el)
      },
      // 运行更新阶段
      beforeUpdate () {
        // 数据更新,页面还没有同步
        console.log('beforeUpdated',this.num,document.getElementById('app').innerHTML)
      },
      updated () {
        // 数据更新,页面已经同步
        console.log('updated',this.num,document.getElementById('app').innerHTML)
      },
      // 销毁阶段
      beforeDestroy () {
        // 销毁之前
        console.log('beforeDestroy')
      },
      destroyed () {
        // 已经销毁了
        console.log('destroy')
      }

在 vue 中通过索引直接在修改数组中的某一项数据,页面是否更新?🌟🌟🌟

在 vue 中对 对象新添加属性,页面是否更新?

不更新,如果想解决这个问题,vm.$set(vm.list, 1, ‘or’)或者 Vue.set

但是 vm.list[3].a = 456,通过索引修改某一项的对象内部的属性是没问题的

vue 组件中的 data 为什么是一个函数,返回一个对象?🌟🌟

如果不是一个函数返回一个新的对象,组件如果多次使用,实际公用的是同一个数据

但是如果是通过函数 返回一个新的对象,这样的话,每个组件的使用数据是独立的

组件🌟🌟🌟🌟

如何创建一个全局组件🌟🌟🌟

通过 Vue.component 来创建一个全局组件,第一个参数是组件名字,第二个参数是组件的配置对象,可以通过 template 配置组件的结构,data 定义数据等等

如何创建一个局部组件🌟🌟🌟

在组件内部通过 components 来创建一个局部组件

全局组件和局部组件的区别

局部组件:只能在当前的父组件中使用

全局组件: 在任意地方使用

如何定义局部自定义指令🌟🌟🌟

在组件内部通过 directives 来创建一个局部指令

全局指令和局部指令的区别

局部指令:只能在当前的组件中使用

全局指令: 在任意地方使用

如何定义局部过滤器🌟🌟🌟

在组件内部通过 filters 来创建一个局部过滤器

全局过滤器和局部过滤器的区别

局部过滤器:只能在当前的组件中使用

全局过滤器: 在任意地方使用

组件传值🌟🌟🌟🌟🌟

Props

  • 父亲怎么传:通过属性绑定形式传
  • 儿子怎么接收:通过 props 来接收

Emit

  • 子怎么传:通过 this.$emit 触发一个自定义事件,并且发送一个值
  • 父怎么接收:通过定义自定义事件的事件函数的形参来接收

ref

  • 通过添加 ref 和 $refs 配合, 也可以很方便的获取子组件, 访问调用子组件的属性或方法
// 父组件中
<template>
  <div class="hello_world">
    <com-a ref="coma"></com-a> // this.$refs.coma.count = 200
    <com-b ref="comb"></com-b> // this.$refs.comb.addFn()
  </div>
</template>

$children

$parent

v-model

sync

兄弟组件传值🌟🌟🌟🌟

定义一个事件中心,或者是第三方

接收值的组件:通过该事件中心的$on 来定义自定义事件的事件函数来接收值

eventBus.$on('getTab1', data => {
  console.log('接收tab1传递的值', data)
})

另一个兄弟组件怎么传:通过事件中心的$emit 触发对应的 $on 的事件,并且把值传递过去

eventBus.$emit('getTab1', this.num)

跨组件传值🌟🌟🌟🌟

Vue.component('my-sub1', {
  template: '#my-sub1',
  data() {
    return {
      money: 10000000
    }
  },
  provide: {
    money: 1000
  },
  components: {
    'sub-a': {
      template: '<div>子组件<sub-b></sub-b></div>',
      components: {
        'sub-b': {
          template: '<div>子组件{{money}}</div>',
          inject: ['money']
        }
      }
    }
  }
})
new Vue({
  el: '#app'
})

vuex

provide inject

  • 成对出现:provide 和 inject 是成对出现的

  • 作用:用于父组件向子孙组件传递数据

使用方法:

  • provide 在父组件中, 返回要传给下级的数据
  • inject 在需要使用这个数据的子孙组件中注入数据。(不论组件层次有多深)

组件插槽🌟🌟🌟🌟

  • 默认插槽:

    • 在组件标签中间可以传递一些子节点
    • 组件内部利用 slot 标签进行接收
  • 具名插槽

    • 在组件标签中间通过定义 slot 的名字传递子节点

      <my-banner>
        <div slot="header">
          头部
        </div>
        <div slot="footer">
          底部
        </div>
      </my-banner>
      
    • 组件内部利用 slot 的 name 进行对应接收

      <template id="banner">
        <div>
          <slot name="header"></slot>
          <slot name="footer"></slot>
        </div>
      </template>
      
  • 作用域插槽

    • 在组件内部定义数据,将数据传递给插槽的结构

    • 通过给 slot 动态绑定属性

      <template id="my-li">
          <ul>
            <li v-for="item in arr">
              <slot :row="item"></slot>
            </li>
          </ul>
        </template>
      
    • 插槽内部:通过 slot-scope=“scope”来接收

      <my-li>
        <template slot-scope="scope">
          <p>{{scope.row}}</p>
        </template>
      </my-li>
      <my-li>
        <template slot-scope="scope">
          <a href="04-侦听器.html">{{scope.row}}</a>
        </template>
      </my-li>
      

Promise 的使用🌟🌟🌟🌟🌟

利用 Promise 处理异步解决回调地狱的问题

Promise 的 all 的方法

Promise 的 race 的方法

面试题:

现在有三个接口地址,需要三个接口地址请求完事之后进行下一步的逻辑处理(不一定按顺序请求完成)

// .then回调
axios.get('http://xxx').then(res => {
  console.log(res)
  axios.get('http://xxx').then(res => {
    console.log(res)
    axios.get('http://xxx').then(res => {
      console.log(res)
    })
  })
})

// .then返回新的Promise继续调用.then
axios
  .get('http://xxx')
  .then(res => {
    return axios.get('http://xxx')
  })
  .then(res => {
    return axios.get('http://xxx')
  })
  .then(res => {
    console.log('三个请求完事')
  })

// async await
const asyncHandle = async function() {
  const res1 = await axios.get('http://xxx1')
  const res2 = await axios.get('http://xxx')
  const res3 = await axios.get('http://xxx')
  console.log(res1, res2, res3)
}

asyncHandle()
// Promise all方法
const getComments = new Promise(() => {
  axios.get('http://xxx')
})

Promise.all([
  axios.get('http://xxx'),
  axios.get('http://xxx'),
  axios.get('http://xxx')
]).then(res => {
  console.log(res)
})

axios 拦截器🌟🌟🌟🌟

请求拦截

axios.interceptors.request.use

响应拦截

axios.interceptors.response.use

路由🌟🌟🌟🌟

什么是路由?

路由就是对应关系,组件和 url 地址,根据不同的地址显示不同的组件,路由也是实现 spa(单页面应用程序)的主要核心,因为单页面应用程序,就是只有一个 html,在这个 html 里面切换组件,根据 url,例如地址为/home,在这个页面中就显示 home 组件

前端路由:url 和组件

后端路由:根据不同的地址请求不同的接口

路由(opens new window)

在 vue 中路由传参

  • params 传参

    • 在跳转的时候可以通过/home/10

    • 路由规则:

      new VueRouter({
        routes: [
          {
            path: '/home/:id',
            component: Home
          }
        ]
      })
      
    • 组件内部怎么来接收参数

      this.$route.params.id
      
  • query 传参

    • 在跳转的时候可以通过/home?id=10

    • 组件内部怎么来接收参数

      this.$route.query.id
      

路由 history 模式注意的问题

嵌套路由🌟🌟🌟

编程式导航🌟🌟🌟

路由钩子🌟🌟🌟🌟

全局钩子:都会对所有的路由进行拦截

beforeEach:进入之前

afterEach:已经进入了

路由独享钩子:可以针对某一个路由进行拦截,这个需要写在路由规则里

 {
    path: '/',
    name: 'home',
    beforeEnter: (to,from,next)=>{
      console.log('即将进入home')
    },
    component: Home
  }

组件内的守卫:

针对组件进行拦截

beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
    next()
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
    console.log('即将离开about')
    if(confirm('当前表单没有提交?确定要离开首页?')){
      next()
    }
  }

webpack 中 babel.loader.plugin 有什么区别?🌟🌟🌟

babel: 将高级语法转换成浏览器可以识别的语法

loader: 加载器, 结合 webpack 来处理非 js 资源文件 .css .less .sass .png

plugin: webpack 的各种各样的插件,能够增强 webpack 的功能

vue 脚手架的安装和使用🌟🌟

命令行方式

配置文档(opens new window)

利用 vue.config.js 关闭 esLint

ui 界面方式

文档(opens new window)

安装 element-ui

  • 安装 vue-cli-plugin-element 插件

使用 element 中 select 组件

  • 注册组件

    import Vue from 'vue'
    import { Button, Select } from 'element-ui'
    
    Vue.use(Button)
    Vue.use(Select)
    
  • 使用组件

    <el-select v-model="value" placeholder="请选择">
      <el-option
        v-for="item in options"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      ></el-option>
    </el-select>
    
  • 复制数据

     options: [{
              value: '选项1',
              label: '黄金糕'
            }, {
              value: '选项2',
              label: '双皮奶'
            }, {
              value: '选项3',
              label: '蚵仔煎'
            }, {
              value: '选项4',
              label: '龙须面'
            }, {
              value: '选项5',
              label: '北京烤鸭'
            }],
            value: ''
    

安装 axios🌟🌟

  • 安装依赖》运行依赖》axios
  • 使用 axios 发送请求
  • 利用 Vue.prorotype 挂载到原型上

vue 动画🌟🌟

文档(opens new window)

利用类名添加动画

在进入/离开的过渡中,会有 6 个 class 切换。

  1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  3. v-enter-to: 2.1.8 版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
  4. v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  6. v-leave-to: 2.1.8 版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
  • 首先给需要添加动画的元素用 transition 包裹起来

  • 利用类名实现动画

    .v-enter,
    .v-leave-to {
      transform: translate(200px, 0);
    }
    .v-enter-active,
    .v-leave-active {
      transition: transform 1s;
    }
    .v-enter-to,
    .v-leave {
      transform: translate(0, 0);
    }
    
  • 自定义动画类名

    <transition name="box2">
      <div class="box" v-show="flag"></div>
    </transition>
    
    .box2-enter,
    .box2-leave-to {
      opacity: 0;
    }
    .box2-enter-active,
    .box2-leave-active {
      transition: opacity 1s;
    }
    .box2-enter-to,
    .box2-leave {
      opacity: 1;
    }
    

结合 css 动画库设置动画🌟🌟

  • 引入 css 动画库

  • 通过 enter-active-class、leave-active-class 设置动画

    <transition
      enter-active-class="animated bounceIn"
      leave-active-class="animated bounceOut"
    >
      <div class="box" v-show="flag"></div>
    </transition>
    

vuex 的缺陷🌟🌟🌟

vuex 的数据属于应用级别的数据,应用刷新,数据会重置 (具有响应式, 不能持久存储)

结合本地存储来使用

单纯的使用本地: 本地的数据(持久存储,不具有响应式)

vue 单页面应用的优缺点🌟🌟🌟🌟

缺点:

  • 不利于 seo
  • 兼容到 ie9
  • 初次加载耗时相对增多

优点

  • 用户体验好,不用重新刷新整个页面
  • 前后端分离
  • mvvm 设计模式
  • 减轻服务期压力,只需要服务器提供数据

加深面试题

关于项目打包你都做了什么? 你的项目优化具体做了哪些? 你的项目如何打包的?🌟🌟🌟🌟🌟

  • 移除 console,借助 babel 插件 babel-plugin-transform-remove-console
  • 判断环境,只在发布阶段使用上面的插件, 通过 process.env.NODE_ENV ‘production’ || “development”
  • 因为开发阶段和发布阶段入口代码有区别,通过 chainWebpack 配置自定义的打包入口,
// 配置自定义入口文件
chainWebpack: config => {
  // when: 相当于if 第一个参数:(条件) 第二个参数(满足条件执行的回调函数) if(条件) { 满足条件执行的逻辑 }
  // 开发期间 --- main-dev.js
  config.when(process.env.NODE_ENV === 'development', config => {
    config
      .entry('app')
      .clear()
      .add('./src/main-dev.js')
  })

  // 发布阶段 --- main-prod.js
  config.when(process.env.NODE_ENV === 'production', config => {
    config
      .entry('app')
      .clear()
      .add('./src/main-prod.js')
  })
}
  • 发布阶段为了减小打包体积, 忽略 js 打包,配置 externals,关于 css 样式,在发布的入口文件中注释掉即可, 加载 cdn 资源文件,加载 cdn 资源文件的优势,减小自己服务器的压力,同时 cdn 资源会就近原则访问
  • 只在发布阶段使用 cdn 资源,通过给 htmlwebpackPlugin 添加标识,标识为不同的值,此时就可以在 html 中判断 htmlwebpackPlugin 标识为开发阶段还是发布阶段从而按需加载 cdn 资源
  • 路由懒加载,路由按需加载, 匹配到哪个路由规则,加载对应的资源文件

虚拟 dom🌟🌟🌟

本质上就是一个 JS 对象,用来描述你希望在屏幕上看到的内容

作用:描述了真实dom结构,核心属性
真实的dom节点有很多属性的,如果直接操作真实的dom,消耗性能
vue里面template写的结构转换render函数,render函数执行会返回虚拟dom结构 >> 渲染出真实dom

优势:

1、数据更新的时候,虚拟dom对比(旧的虚拟dom结构和新的虚拟dom结构进行对比),对比出差异以后,更新到真实的dom里面(最小化操作dom)

2、同级比较,如果标签名不一致或者key不一致直接替换,不会进行深层次对比

3、次序深度优先
跨平台

浏览器,小程序 , 支付宝小程序,抖音小程序,打包安卓,ios应用 ,electron桌面应用

vue/react >> 虚拟dom 渲染的时候根据不同的平台去进行渲染

渲染浏览器环境的方法

渲染小程序的方法

dom diff的性能好

跨平台

Diff 算法🌟🌟🌟🌟

虚拟 dom 高效更新执行过程

  • 初次渲染时,会根据 model 数据创建一个虚拟 DOM 对象(树)
  • 根据虚拟 DOM 生成真正的 DOM,渲染到页面
  • 当数据变化后,会重新根据新的数据,创建新的虚拟 DOM 对象(树)
  • 与上一次得到的虚拟 DOM 对象,使用 Diff 算法比对(找不同),得到需要更新的内容
  • 最终,React 只将变化的内容更新(patch)到 DOM 中,重新渲染到页面
  • 什么是虚拟 dom:用 js 对象来表示页面上 dom 元素的的样式体现
  • 虚拟 dom 的作用:高效更新页面,还有就是让 react 脱离了浏览器的概念
  • 怎么来高效更新页面的:就是在第一次渲染页面的时候生成一份初始的虚拟 dom 树,然后当数据改变之后,再生成一份虚拟 dom 树,然后根据新旧 dom 树进行对比,对比完成之后,把有区别的进行更新
  • diff 算法的作用就是:新旧虚拟 dom 树在对比的时候就是通过 diff 算法来对比的
  • diff 算法又是怎么去对比的:tree diff、component diff、element diff

面试语术:

你知道虚拟 dom 吗?简单又谈一下?

本质上就是一个 JS 对象,用来描述你希望在屏幕上看到的内容,虚拟 dom 可以实现高效更新,(后面如果自己能说一气说出来)

如何实现高效更新的?

利用新旧虚拟 dom 树进行对比,从而进行局部进行更新

如何进行新旧 dom 树进行对比?

利用 diff 算法,主要是 tree diff 树对比,component diff 组件对比,element diff 元素对比

加上一些其他话术

所以虚拟 dom 在前端中不管是 vue、react 等等都采用

axios 配置代理服务器🌟🌟🌟🌟

什么是跨域?

在浏览器里面域名、端口、ip 地址、协议,有任何一项不同,则跨域

A 网站:http://localhost:8080/#/

B 网站:http://localhost:3000/#/

处理跨域的方式?

JsonP(只能处理 get 请求)、cors(后端开启)、代理服务器

module.exports = {
  devServer: {
    host: 'localhost',
    port: 8080,
    proxy: {
      '/api': {
        target: 'http://localhost:3000', // 要跨域的域名
        changeOrigin: true // 是否开启跨域
      },
      '/get': {
        target: 'http://localhost:3000', // 要跨域的域名
        changeOrigin: true // 是否开启跨域
      }
    }
  }
}

小程序分包加载🌟🌟🌟

某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。

在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。

在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。

目前小程序分包大小有以下限制:

  • 整个小程序所有分包大小不超过 12M
  • 单个分包/主包大小不能超过 2M

对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。

代码演示,分包加载之前

pages: [
  'pages/tabs/home',
  'pages/tabs/cates',
  'pages/tabs/search',
  'pages/tabs/cart',
  'pages/tabs/my',
  'pages/goods_list',
  'pages/goods_detail/main',
  'pages/order',
  'pages/orderList'
]

抽离之后

pages: [
      'pages/tabs/home',
      'pages/tabs/cates',
      'pages/tabs/search',
      'pages/tabs/cart',
      'pages/tabs/my',
      'pages/order',
      'pages/orderList'
    ],
    subpackages: [
      {
        name: 'goods',
        root: 'goods',
        pages: [
          'goods_list',
          'goods_detail/main'
        ]
      }
    ]

图片或者图标等资源文件使用线上资源

v-if 和 v-for 避免结合使用🌟🌟🌟

因为 v-for 的优先级大于 v-if,所以会先根据所有数据生成结构,然后在根据,v-if 进行按需渲染

<div id="app">
  <ul>
    <li v-for="item in arr" v-if="item%2===0">{{ item }}</li>
  </ul>
</div>
<script src="./vue.js"></script>
<script>
  new Vue({
    el: '#app',
    data: {
      arr: [1, 2, 3, 4]
    }
  })
</script>

我们可以采用计算属性来避免此问题,这样的话,先通过计算属性,计算出要渲染的数据,然后直接循环计算属性即可

<div id="app">
  <ul>
    <li v-for="item in newArr">{{ item }}</li>
  </ul>
</div>
<script src="./vue.js"></script>
<script>
  new Vue({
    el: '#app',
    data: {
      arr: [1, 2, 3, 4]
    },
    computed: {
      newArr() {
        return this.arr.filter(item => {
          return item % 2 === 0
        })
      }
    }
  })
</script>

vue 中 route 和 router 的区别🌟🌟🌟🌟

  • route 是当前路由信息,可以获取到当前路由地址参数等等
  • router 是全局路由(VueRouter)实例对象,可以通过 router 进行路由的跳转后退等等

如何封装一个插件🌟🌟

  • 定义一个 button 组件,在 index.js 中引入并注册

  • 在 components 中创建一个 index.js

    import sgButton from './button.vue'
    function install (Vue) {
      Vue.component(sgButton.name, sgButton)
    }
    
    export default {
      install
    }
    
  • 在 main.js 中导入该 js 文件,当调用 Vue.use 方法,会默认调用内部的 install 方法

面试题

你有封装过插件吗? Vue.use 的原理是什么?

当调用 Vue.use 方法,会默认调用内部的 install 方法,install 这个方法默认的第一个形参就是 Vue,这样的话我们就可以通过 Vue 注册一些全局组件,给 Vue 扩展一下方法。

vueI18n 的使用🌟🌟

vue 中实现语言切换的方式如何实现的

1.NPM 项目安装

cnpm i vue-i18n

2.使用方法

/* 国际化使用规则 */
import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)
<!-- 需要国际化的数据定义在此处 -->
const messages = {
  en: {
    message: {
      hello: 'world hello'
    }
  },
  zh: {
    message: {
      hello: '世界'
    }
  }
}
<!-- 使用i18n -->
const i18n = new VueI18n({
  locale: 'zh',
  messages
})

export default {
  data () {
    return {
      hello: this.$t('message.hello')
    }
  },
  i18n
}

3.页面数据使用

<div id="#app">
  <p>{{ $t("message.hello") }}</p>
</div>

4.案例练习

定义基本结构
<div id="app">
  <button>切换语言</button>
  <ul>
    <li>首页</li>
    <li>新闻</li>
    <li>关于</li>
    <li>概况</li>
  </ul>
</div>

ul{
  list-style: none;
  li{
    width: 20%;
    height: 70px;
    line-height: 70px;
    background: green;
    color: #fff;
    float: left;
    margin-left: 2%;
    text-align: center;
    line-height: 70px;
  }
}
 
    
定义语言包

zh.js

export default {
  nav: ['首页', '新闻', '概况', '关于']
}

en.js

export default {
  nav: ['home', 'news', 'gk', 'about']
}
在 main.js 中引入语言包
import zh from './i18n/zh.js'
import en from './i18n/en.js'
Vue.use(VueI18n)

const i18n = new VueI18n({
  locale: 'en',
  messages: {
    zh,
    en
  }
})
数据渲染和切换
<template>
  <div id="app">
    <button @click="changeLang">切换语言</button>
    <ul>
      <li v-for="(item, index) in $t('nav')" :key="index">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    methods: {
      changeLang() {
        this.$i18n.locale = this.$i18n.locale === 'en' ? 'zh' : 'en'
      }
    }
  }
</script>

keep-alive🌟🌟🌟🌟

  1. vue自带的组件 >> 主要功能是缓存组件 >> 提升性能
  2. 使用场景:可以少网络请求,如果当前组件数据量比较大,就可以节省网络请求 >> 提升用户体验
  3. 举例:如果详情页面之间进行切换,就可以使用keep-alive进行缓存组件,防止同样的数据重复请求
  <keep-alive>
       <router-view />
    </keep-alive>

在这里插入图片描述

一、Keep-alive 是什么

keep-alivevue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM

keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们

keep-alive可以设置以下props属性:

  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存
  • max - 数字。最多可以缓存多少组件实例

关于keep-alive的基本用法:

<keep-alive>
  <component :is="view"></component>
</keep-alive>

使用includesexclude

<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>

<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值),匿名组件不能被匹配

设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activateddeactivated):

  • 首次进入组件时:beforeRouteEnter > beforeCreate > created> mounted > activated > … … > beforeRouteLeave > deactivated
  • 再次进入组件时:beforeRouteEnter >activated > … … > beforeRouteLeave > deactivated
二、使用场景

使用原则:当我们在某些场景下不需要让页面重新加载时我们可以使用keepalive

举个栗子:

当我们从首页–>列表页–>商详页–>再返回,这时候列表页应该是需要keep-alive

首页–>列表页–>商详页–>返回到列表页(需要缓存)–>返回到首页(需要缓存)–>再次进入列表页(不需要缓存),这时候可以按需来控制页面的keep-alive

vue-router 中 hash 和 history 的区别

  • history 没有#/,会比 hash 好看
  • history 模式是采用的 h5history.pushState API 来完成 URL 跳转而无须重新加载页面
  • hash 是利用 location.hash 进行跳转的
  • hash 是不需要后台配置支持的
  • history 不过这种模式要玩好,还需要后台配置支持

this.$nextTick()的作用

这个函数是可以等 dom 重新更新完成会调用

数据渲染完成,页面完成更新即调用 this.$nextTik

当修改了数据,dom 是异步同步的,所以,如果更改了数据,在修改数据下面重新操作 dom 会出问题,需要保证 dom 也更新完成才能操作。

  • 12
    点赞
  • 132
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

itpeilibo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值