文章目录
- 1·**Vue**的核心是什么
- 2·请简述你对vue的理解
- 3·请简述vue的单向数据流
- 4·Vue常用的修饰符有哪些
- 5·v-text与{{}}区别
- 6·v-on可以绑定多个方法吗
- 7·Vue循环的key作用
- 8. 什么是计算属性
- 9.Vue单页面的优缺点
- 10:Vuex是什么?怎么使用?在那种场景下使用
- 11:Vue中路由跳转方式(声明式/编程式)
- 12:Vue的生命周期请简述
- 13: Vue生命周期的作用
- 14:DOM渲染在那个生命周期阶段内完成
- 15:Vue路由模式hash和history,简单讲一下
- 16:Vue路由传参的两种方式,prams和query方式与区别
- 17: Vue数据绑定的几种方式
- 18:Vue的路由钩子函数/路由守卫有哪些
- 19:Vue-cli中如何自定义指令
- 20:Vue中指令有哪些
- 21:Vue如何定义一个过滤器
- 22:对vue 中keep-alive的理解
- 23:Mvvm与mvc的区别
- 24:Vue组件中的data为什么是函数
- 25:Vue双向绑定的原理
- 26:Vue中组件怎么传值
- 27:槽口请简述
- 28:计算属性与watch区别
- 29:Vue首屏加载慢的原因
- 30: Route与router区别
- 31:Vue路由懒加载(按需加载路由)
- 32:v-for与v-if优先级
- 33:vue的常用配置选项及其作用
- vue的项目中遇见的问题
1·Vue的核心是什么
数据驱动:Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它让开发者省去了操作DOM的过程,只需要改变数据。Vue对操作进行监听,当视图发生改变时,vue监听到这些变化,从而改变数据,这样就形成了数据的双向绑定。
组件响应原理:数据(model)改变驱动视图(view)自动更新
组件化:组件化实现了扩展HTML元素,封装可用的代码。
2·请简述你对vue的理解
Vue是目前最流行的一种渐进式的自底向上增量开发的一种js框架,
渐进式体现了可以在原有的基础上,将一两个功能模块进行使用vue开发
自底向上增量开发体现在先实现简单的基础页面。在去添加功能,从简单到复杂的这么一个过程
主要是用来解决:数据绑定的问题,开发大型单页面应用的
mvvm框架:
M:模型层,负责业务数据相关
V(View,视图层):负责视图相关,细分下来就是html+css层,
VM(ViewModel):M与V的桥梁,负责监听M或者修改V,是双向绑定的要点,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步
复杂的数据状态维护完全由 MVVM 来统一管理。
3·请简述vue的单向数据流
所谓单行数据流是指vue将数据从父元素传递给子元素,其子元素里的数据进行改变以后,父元素里的数据并不会随着子元素的变化进行变化
4·Vue常用的修饰符有哪些
键盘修饰符
On:表示方向键上键被触发
Ctrl:表示ctrl建被按下
Enter:表示回车键被按下
Space:表示空格键被按下
事件修饰符:
Prevent:表示阻止事件的默认行为
Stop:表示阻止事件的冒泡行为
Capture:表示事件的捕获行为
Self:表示只触发自己范围内的事件
Once:表示只会触发一次该事件
5·v-text与{{}}区别
v-text与{{}}等价
{{}}叫做插值模板,v-text叫做指令
{{}}会造成屏幕闪动:在渲染数据量比较大的数据的时候,可能会把大括号给显示出来
解决屏幕闪动的办法就是使用v-cloak,或者是使用v-text
v-clock的使用是:
第一步:在el挂载的标签上添加
第二步:设置css,[v-clock]{display:none}
6·v-on可以绑定多个方法吗
v-on可以绑定多个方法,多个方法之间通过逗号隔开
也可以绑定给一个事件绑定多个修饰符
7·Vue循环的key作用
Key的作用是用来高效的更新虚拟dom,
在新旧节点进行对比的时候,key值就相当于一个唯一的标识符,
因为有了这个key值,所以在渲染元素的时候,通常会复用已有的元素,而并不是重新进行渲染,提高了渲染的效率
8. 什么是计算属性
计算属性的本质上是vue实例下的一个属性,不过该属性具有计算的功能,在进行一些逻辑运算的时候就可以使用计算属性,减少了插值模板的逻辑运算,
计算属性在计算值变化的时候,会自动进行重新计算,并将结果渲染到视图层,并将结果放到缓存中,下次要是展示就直接拿出来使用,不需要重新调用,只有在值进行变化的时候会重新调用
9.Vue单页面的优缺点
Vue单页面是指:只有一个主页面的应用,在页面进行加载的时候,就加载出该页面所需的所有的东西
单页面的优点:
用户体验好,快,内容的改变并不会引起整个页面的重新加载
比较好的前后端分离,分工明确
采用组件化的思想,代码结构更加清晰明了
单页面的缺点:
就是不利于搜引擎的抓取,
首次渲染比较慢
10:Vuex是什么?怎么使用?在那种场景下使用
Vuex是状态管理工具
使用的话:首先要进行vuex的下载,
下载完成以后将其引入到main.js中,将其绑定到vue实例中
Vuex的一般作用是:组件之间数据或者方法的一种共享
State:存放数据的,一般使用this.$store.state调用
mutations:用来对state的数据进行修改的,一般采用commit进行调用
mutatons:{
名字(state,payload){
State.num= State.num+1
}
}
//调用的时候:Payload就是传过来的参数
This.$store.commit(“名字”,payload)
Actions:用来进行异步操作的数据请求,一般采用dispatch进行调用
//Content表示this.$store
actions: {
vuexget(content, payload) {
getlink("/data/list/recom").then((ok) => {
content.commit("xiu", ok.data)
})
}
},
// 调用的时候:
This. $store.dispatch(“名字”, payload)
Getters:功能类似于computed的,是对state里的数据进行逻辑运算的
Modules:项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
11:Vue中路由跳转方式(声明式/编程式)
Vue的路由跳转分为两种一种是声明式的:
<router-link to=” 你要去的路径”>
一种是编程式的:编程式的一般是通过this.$router.push(“你要去的路径”)
12:Vue的生命周期请简述
Vue的生命周期就是vue实例从创建到销毁的过程
其中包括开始创建,初始化数据,编译模板,挂载dom,渲染,更新,卸载等一系列的过程,称为vue的生命周期
Beforecreate:在vue实例创建之前
Created:vue实例已经创建完成,但是dom还没有挂载上
Beforemount:在dom准备渲染之前
Mounted:dom已经挂载好了,此时可以操作dom
Beforeupdate:在所有的组件更新之前
Updated:在所有的组件更新之后
Beforedestory:在vue实例销毁之前
destored:在vue实例销毁之后
13: Vue生命周期的作用
Vue的生命周期函数的作用是,是开发者在不同的阶段添加自己代码的机会,可以更加便利的控制vue整个过程中的逻辑
14:DOM渲染在那个生命周期阶段内完成
在mounted:模板编译完成以后得周期进行
15:Vue路由模式hash和history,简单讲一下
Hash:[query]在url的显示上有#,比较丑,在回车刷新的时候不会丢失页面,依旧在hash对应的页面,支持一些低版本的浏览器
History:[params]在url的显示上没有#,比较好看,在回车刷新的时候会发生页面的丢失,一般就是404错误,并且是html5新出的api,不太兼容低版本的浏览器
16:Vue路由传参的两种方式,prams和query方式与区别
Pramas传参一般分为三个步骤:
-
在路由规则里配置要去的页面【给谁传参数就将参数绑定到谁的路径上】
Path:”/all/:xm”
-
开始发送:
this.$router.push({name:" 你要去的路由的名字",params:{xm:id}})
-
接受参数:
this.$route.params.xm
Query传参一般的为两步:
-
开始发送:
this.$router.push({name:" 你要去的路由的名字",query:{xm:id}})
-
接受参数
this.$route. query. xm
两者模式的区别:
-
用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.name和this.route.params.name。
-
url展示上:params类似于post,query更加类似于我们ajax中get传参,说的再简单一点,前者在浏览器地址栏中不显示参数,后者显示,所以params传值相对安全一些
17: Vue数据绑定的几种方式
a) 将数据绑定到{{}}或者v-text上
b) 将数据绑定到v-html标签上
c) 将数据绑定到v-bind上,以属性的样式进行解析
d) 通过一次性绑定v-once
e) 通过双向绑定v-model
18:Vue的路由钩子函数/路由守卫有哪些
路由守卫是指在路由进行跳转的时候被自动调用的函数
其中包括:
-
全局前置守卫:router.beforeEach((to,from,next)=>{}
-
全局后置守卫: router.afterEach((to,from)=>{}
-
路由独享守卫:beforeEnter(to,from,next){ }
-
前置组件内的守卫:beforeRouterEnter(to,from,next){ }
-
后置组件内守卫:beforeRouterleave(to,from,next){ }
19:Vue-cli中如何自定义指令
Directives:{
自定义指令名字:{
自定义钩子函数(val){
//形参就是把自定义指令放在那个dom上他就是谁
}
}
}
自定义指令的钩子函数是:
Bind:绑定指令到相关元素上,只执行一次
Unbind:接触指令和元素之间的绑定,只执行一次
Update:指令所在的组件节点更新时调用
Componentupdate:指令所在的组件节点更新完后调用
Inserted:绑定指令的元素在页面中展示时调用
20:Vue中指令有哪些
v-for:循环数组,对象,字符串,数字
v-on:绑定事件监听
v-bind:动态绑定一个或者多个属性
v-model:表单控件或者组件上创建双向绑定
v-if v-else v-else-if 条件渲染
v-show 根据表达式真假,切换元素的display
v-html 更新元素的innerhtml
v-text 更新元素的textcontent
v-pre 跳过这个元素和子元素的编译过程
v-clock 这个指令保持在元素上知道关联实例结束编译
v-once 只渲染一次
21:Vue如何定义一个过滤器
Vue中有两种过滤器,一种全局过滤器,一种局部过滤器
使用方法:
{{表达式 | 过滤器}}
其中全局过滤器的书写时:
vue.filter{
过滤器名字(val){
Return 结果
}
}
其中局部过滤器的书写时:
filters{
过滤器名字(val){
Return 结果
}
}
22:对vue 中keep-alive的理解
概念:keep-alive是vue的内置组件,当它动态包裹组件时,会缓存不活动的组件实例,它自身不会渲染成一个DOM元素也不会出现在父组件链中
作用:在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间以及性能消耗,提高用户体验。
使用:
<keep-alive include="Comb,Comc">
<component :is="com"></component>
</keep-alive>
生命周期函数:
Activated在keep-alive组件激活时调用,
deactivated在keep-alive组件停用时调用
23:Mvvm与mvc的区别
Mvc模型视图控制器,视图是可以直接访问模型,所以,视图里面会包含模型信息,mvc关注的是模型不变,所以,在mvc中,模型不依赖视图,但是视图依赖模型
Mvvm 模型 视图 和vm vm是作为模型和视图的桥梁,当模型层数据改变,vm会检测到并通知视图层进行相应的修改
24:Vue组件中的data为什么是函数
Data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响
如果是引用类型(对象),当多个组件共用一个数据源时,一处数据改变,所有的组件数据都会改变,所以要利用函数通过return返回对象的拷贝,(返回一个新数据),让每个实例都有自己的作用域,相互不影响。
25:Vue双向绑定的原理
Vue双向绑定就是:数据变化更新视图,视图变化更新数据
Vue数据双向绑定是通过数据劫持结合发布订阅者模式来实现的,
数据劫持:object.defineproperty可以感知到数据变化,在通过setter进行获得,getter设置
观察者模式 当属性发生改变的时候,使用该数据的地方也发生改变
26:Vue中组件怎么传值
正向:父传子 父组件把要传递的数据绑定在属性上,发送,子组件通过props接收
逆向:子传父 子组件通过this.$emit(自定义事件名,要发送的数据),父组件设置一个监听事件来接收,然后拿到数据
**兄弟:**eventbus 中央事件总线
第一步:创建一个eventbus的文件夹以及index.js的文件
第二步:在a组件中引入中央事件总线,设置一个抛出事件
eventBus.$emit("pao","我是数据")
第三步:在b组件同样引入中央事件总线,用来接收抛出事件
eventBus.$on("pao",(msg)=>{
this.text=msg;
})
通过:Vuex
27:槽口请简述
大概分这几点,首先槽口(插槽)可以放什么内容?放在哪?什么作用?可以放任意内容,在子组件中使用,是为了将父组件中的子组件模板数据正常显示。
具名插槽和匿名插槽,作用域插槽,说白了就是在组件上的属性,可以在组件元素内使用,
可以在父组件中使用slot-scope从子组件获取数据
28:计算属性与watch区别
Computed watch 区别就是computed的缓存功能,当无关数据数据改变时,不会重新计算,直接使用缓存中的值。
计算属性是用来声明式的描述一个值依赖了其他的值,当所依赖的值后者变量发生变化时,计算属性也跟着改变,
Watch监听的是在data中定义的变量,当该变量变化时,会触发watch中的方法
29:Vue首屏加载慢的原因
-
路由懒加载
-
使用webpack的externals属性把不需要打包的库文件分离出去,减少打包后文件的大小
module.exports = { externals: { jquery: 'jQuery' } };
-
Ui框架按需引入加载
-
使用v-if和v-else添加加载的动态效果
-
使用vue的ssr技术
30: Route与router区别
- router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。
2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等
31:Vue路由懒加载(按需加载路由)
component: () => import(’…/views/About.vue’)
32:v-for与v-if优先级
首先不要把v-if与用在同一个元素上,原因:v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。
v-for 比 v-if 具有更高的优先级
33:vue的常用配置选项及其作用
- el: 最外层元素选择器
- props: 声明接收哪些属性
- data: 状态数据
- computed: 计算属性
- methods: 事件回调函数
- watch: 监视属性变化
- directives: 注册自定义指令
- filters: 注册局部过滤器
- components: 配置组件
vue的项目中遇见的问题
列表进入详情页的传参问题
params传参时,如果没有在路由中定义参数,也是可以传过去的,同时也能接收到,但是一旦刷新页面,这个参数就不存在了。
跨域问题
proxyTable: {
// 用‘/api’开头,代理所有请求到目标服务器
'/api': {
target: 'http://jsonplaceholder.typicode.com', // 接口域名
changeOrigin: true, // 是否启用跨域
pathRewrite: { //
'^/api': ''
}
}
}复制代码
vant的按需加载
-
安装
-
安装babel-plugin-import插件使其按需加载:
-
在 .babelrc文件中中添加插件配置 :
-
在main.js中按需加载你需要的插件
-
在根组件使用
-
在页面中使用:
如何修改ui库中组件的样式
首先我们vue文件的样式都是写在标签中的,正常我们写的vue样式,都会被加上[data-v-23d425f8]这个属性,但是第三方组件内部的标签并没有编译为附带[data-v-23d425f8]这个属性
【解决办法一】
-
给第三方组件写一个class,在当前组件中写一个是不带scoped标签的样式,然后直接在里面修改第三方组件的样式
【但是存在全局污染和命名冲突的问题】
【解决办法二】
-
通过深度选择器解决:/deep/
例如修改上图中组件里的
van-ellipsis
类的样式,可以这样做:.van-tabs /deep/ .van-ellipsis { color: blue}; //编译后的结果就是 .van-tabs[[data-v-23d425f8]] .van-ellipsis { color: blue};
【注意:/deep/是less和sass样式的选择器,要是报错,可以替换为
::v-deep
,无论是**/deep/和::v-deep
**都是>>>的别名】
定时器问题
在a页面写一个定时,让他每秒钟打印一个1,然后跳转到b页面,此时可以看到,定时器依然在执行,这样特别浪费浏览器的性能
【解决方案一】:
-
在beforeDestroy()生命周期内清除定时器
beforeDestroy() { //time就是那个定时器,定义在data中 clearInterval(this.timer); this.timer = null; }复制代码
【解决方案二】
-
通过$once这个事件侦听器器在定义完定时器之后的位置来清除定时器
const timer = setInterval(() =>{ // 某些定时器操作 }, 500); // 通过$once来监听定时器,在beforeDestroy钩子可以被清除。 this.$once('hook:beforeDestroy', () => { clearInterval(timer); })
移动端的适配问题
在做手机端时,适配是必须要处理的一个问题
根据网页尺寸计算html的font-size大小,flex.js文件的导入
在main.js中,直接import './config/rem'
导入即可
轮播需求
vue-awesome-swiper这个轮播组件,真的非常强大,基本可以满足我们的轮播需求。
vue-awesome-swiper组件实质上基于swiper
的,或者说就是能在vue中跑的swiper
使用过程:
安装: cnpm install vue-awesome-swiper --save
引用:
import 'swiper/dist/css/swiper.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
//在components中注册组件
components: {
swiper,
swiperSlide
}
fastClick的300ms延迟解决方案
开发移动端项目,点击事件会有300ms延迟的问题
【解决:】
安装 fastClick
cnpm install fastclick -S
在main.js中引入fastClick
和初始化
import FastClick from 'fastclick'; // 引入插件
FastClick.attach(document.body); // 使用 fastclick复制代码
解决首屏加载问题
-
路由懒加载
-
开启gzip压缩代码,可以帮助我们压缩30%左右【但是需要前后端配合】
gzip的使用就是 1:使用cnpm进行下载 2:在config.js中进行配置,将productionGzip: true, // false不开启gizp,true开启
前端性能分析工具
-
hiper【使用cnpm对hiper进行下载】
-
在cmd命令中输入相关的指令检测性能,具体可看官网
hiper 测试的网址
当我们项目打开速度慢时,这个工具可以帮助我们快速定位出到底在哪一步影响的页面加载的速度。
vue获取数据的两种方式
-
导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
这种方式是我们大部分都在使用的,使用这种方式时,我们会先加载导航和渲染组件,然后在组件的
created
或者monted钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态-
因此对于用户体验上来说,在获取数据之前,页面的组件已经加载,但是数据并没有请求来,所以需要在不能展示数据的那块,中要有一个loading的加载中的组件或者骨架屏。
-
当页面数据获取失败,可以理解为请求超时的时候,我们要展示的是断网的组件。
<!--加载中或者骨架屏--> <div v-if="loading"></div> <!--请求失败,即断网的提示组件--> <div v-if="error"></div> <!--请求成功--> <div v-if="ok"></div>
-
-
导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
这种方式是在页面的beforeRouteEnter钩子中请求数据,只有在数据获取成功之后才会跳转导航页面。
beforeRouteEnter (to, from, next) { api.article.articleDetail(to.query.id).then(res=> { next(vm => { vm.info = res.data; vm.loadFinish = true }) }) }
- beforeRouteEnter钩子中的this还不能使用,要是想要进行赋值或者调用,就只能通过在next()方法的回调函数中处理,这个回调函数的第一个参数就代表了this,他会在组件初始化成功后进行操作。
- 这里使用不了this,所以只能在页面组件内引入api或者我们的axios
- 赋值操作也可以写在method方法中,但是调用这个赋值方法还是
vm.yourFunction()
的方式。 - 们需要在当前页面进入之前,即在上一个页面的时候有一个加载的提示,比如页面顶部的进度条
- 全局的页面顶部进度条,可以在main.js中通过router.beforeEach(to, from, next) {}来设置,当页面路由变化时,显示页面顶部的进度条,进入新路由后隐藏掉进度条。
mixins混入简化常见操作
我们在开发中经常会遇到金钱保留两位小数,时间戳转换等操作。每次我们会写成一个公共函数,然后在页面里面的filters进行过滤
import { u_fixed } from './tool'
const mixins = {
filters: {
// 保留两位小数
mixin_fixed2 (val) {
return u_fixed(val)
},
// 数字转汉字,16000 => 1.60万
mixin_num2chinese (val) {
return val > 9999 ? u_fixed(val/10000) + '万' : val;
}
}}
export default mixins
引入
调用:mixins:[mixins]
使用:{{1000 | mixin_fixed2}}
的axios
- 赋值操作也可以写在method方法中,但是调用这个赋值方法还是
vm.yourFunction()
的方式。 - 们需要在当前页面进入之前,即在上一个页面的时候有一个加载的提示,比如页面顶部的进度条
- 全局的页面顶部进度条,可以在main.js中通过router.beforeEach(to, from, next) {}来设置,当页面路由变化时,显示页面顶部的进度条,进入新路由后隐藏掉进度条。
mixins混入简化常见操作
我们在开发中经常会遇到金钱保留两位小数,时间戳转换等操作。每次我们会写成一个公共函数,然后在页面里面的filters进行过滤
import { u_fixed } from './tool'
const mixins = {
filters: {
// 保留两位小数
mixin_fixed2 (val) {
return u_fixed(val)
},
// 数字转汉字,16000 => 1.60万
mixin_num2chinese (val) {
return val > 9999 ? u_fixed(val/10000) + '万' : val;
}
}}
export default mixins
引入
调用:mixins:[mixins]
使用:{{1000 | mixin_fixed2}}