文章目录
vue 的两个核心🌟🌟什么是双向数据绑定?🌟🌟🌟什么是单向数据流?🌟🌟🌟MVVM 的设计思想的优势?🌟🌟🌟事件传参🌟🌟🌟🌟自定义指令:directive🌟🌟🌟计算属性:computed🌟🌟🌟🌟🌟监听器:watch🌟🌟🌟🌟🌟过滤器🌟🌟🌟🌟生命周期函数🌟🌟🌟🌟🌟在 vue 中通过索引直接在修改数组中的某一项数据,页面是否更新?🌟🌟🌟vue 组件中的 data 为什么是一个函数,返回一个对象?🌟🌟组件🌟🌟🌟🌟如何创建一个全局组件🌟🌟🌟如何创建一个局部组件🌟🌟🌟如何定义局部自定义指令🌟🌟🌟如何定义局部过滤器🌟🌟🌟组件传值🌟🌟🌟🌟🌟PropsEmitref$children$parentv-modelsync兄弟组件传值🌟🌟🌟🌟跨组件传值🌟🌟🌟🌟vuexprovide inject组件插槽🌟🌟🌟🌟Promise 的使用🌟🌟🌟🌟🌟axios 拦截器🌟🌟🌟🌟路由🌟🌟🌟🌟在 vue 中路由传参嵌套路由🌟🌟🌟编程式导航🌟🌟🌟路由钩子🌟🌟🌟🌟webpack 中 babel.loader.plugin 有什么区别?🌟🌟🌟vue 脚手架的安装和使用🌟🌟命令行方式ui 界面方式安装 element-ui使用 element 中 select 组件安装 axios🌟🌟vue 动画🌟🌟利用类名添加动画结合 css 动画库设置动画🌟🌟vuex 的缺陷🌟🌟🌟vue 单页面应用的优缺点🌟🌟🌟🌟加深面试题关于项目打包你都做了什么? 你的项目优化具体做了哪些? 你的项目如何打包的?🌟🌟🌟🌟🌟虚拟 dom🌟🌟🌟Diff 算法🌟🌟🌟🌟axios 配置代理服务器🌟🌟🌟🌟小程序分包加载🌟🌟🌟v-if 和 v-for 避免结合使用🌟🌟🌟vue 中 route 和 router 的区别🌟🌟🌟🌟如何封装一个插件🌟🌟vueI18n 的使用🌟🌟定义基本结构定义语言包在 main.js 中引入语言包数据渲染和切换keep-alive🌟🌟🌟🌟一、Keep-alive 是什么二、使用场景vue-router 中 hash 和 history 的区别this.$nextTick()的作用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 为什么是一个函数,返回一个对象?🌟🌟
如果不是一个函数返回一个新的对象,组件如果多次使用,实际公用的是同一个数据
但是如果是通过函数 返回一个新的对象,这样的话,每个组件的使用数据是独立的
组件🌟🌟🌟🌟
如何创建一个全局组件🌟🌟🌟
通过 ponent 来创建一个全局组件,第一个参数是组件名字,第二个参数是组件的配置对象,可以通过 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.$a.count = 200<com-b ref="comb"></com-b> // this.$b.addFn()</div></template>
$children
$parent
v-model
sync
兄弟组件传值🌟🌟🌟🌟
定义一个事件中心,或者是第三方
接收值的组件:通过该事件中心的$on 来定义自定义事件的事件函数来接收值
eventBus.$on('getTab1', data => {console.log('接收tab1传递的值', data)})
另一个兄弟组件怎么传:通过事件中心的$emit 触发对应的 $on 的事件,并且把值传递过去
eventBus.$emit('getTab1', this.num)
跨组件传值🌟🌟🌟🌟
ponent('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继续调用.thenaxios.get('http://xxx').then(res => {return axios.get('http://xxx')}).then(res => {return axios.get('http://xxx')}).then(res => {console.log('三个请求完事')})// async awaitconst 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-optionv-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 切换。
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时v-enter
被移除),在过渡/动画完成之后移除。v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。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 设置动画
<transitionenter-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.jsconfig.when(process.env.NODE_ENV === 'development', config => {config.entry('app').clear().add('./src/main-dev.js')})// 发布阶段 --- main-prod.jsconfig.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) {ponent(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🌟🌟🌟🌟
vue自带的组件 >> 主要功能是缓存组件 >> 提升性能使用场景:可以少网络请求,如果当前组件数据量比较大,就可以节省网络请求 >> 提升用户体验举例:如果详情页面之间进行切换,就可以使用keep-alive
进行缓存组件,防止同样的数据重复请求<keep-alive><router-view /></keep-alive>
一、Keep-alive 是什么
keep-alive
是
vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染
DOM
keep-alive
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
keep-alive
可以设置以下props
属性:
include
- 字符串或正则表达式。只有名称匹配的组件会被缓存exclude
- 字符串或正则表达式。任何名称匹配的组件都不会被缓存max
- 数字。最多可以缓存多少组件实例
关于keep-alive
的基本用法:
<keep-alive><component :is="view"></component></keep-alive>
使用includes
和exclude
:
<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 缓存的组件,会多出两个生命周期钩子(activated
与deactivated
):
首次进入组件时: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 也更新完成才能操作。