vue
-
什么是vue生命周期?
答: Vue生命周期是指vue实例对象从创建之初到销毁的过程,vue所有功能的实现都是围绕其生命周期进行的,在生命周期的不同阶段调用对应的钩子函数可以实现组件数据管理和DOM渲染两大重要功能。
-
vue生命周期的作用是什么?
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑
-
vue的生命周期的八个钩子函数?
• beforeCreat() 创建前 在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在此生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
• created()被创建 data 和 methods都已经被初始化好了,可以调用了
• beforeMount() 挂载前 在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
• mounted()已挂载 Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
• beforeupdate()更新前 页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
• updated()更新 页面显示的数据和data中的数据已经保持同步了,都是最新的
• beforeDestroy() 销毁前 Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
• destroyed()被销毁 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。 -
第一次页面加载会触发哪几个钩子?
答: 第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子.
-
简述每个周期具体适合哪些场景?
答:beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom -
created和mounted的区别?
答:created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。 -
DOM渲染在哪个周期中已经完成?
答:mounted
Vue路由
-
mvvm框架是什么?
mvvm即Model-View-ViewModel,mvvm的设计原理是基于mvc的
MVVM是Model-View-ViewModel的缩写,Model代表数据模型负责业务逻辑和数据封装,View代表UI组件负责界面和显示,ViewModel监听模型数据的改变和控制视图行为,处理用户交互,简单来说就是通过双向数据绑定把View层和Model层连接起来。在MVVM架构下,View和Model没有直接联系,而是通过ViewModel进行交互,我们只关注业务逻辑,不需要手动操作DOM,不需要关注View和Model的同步工作 -
vue-router是什么?有哪些组件?
• Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。
• <router-link>和<router-view>和<keep-alive>
3.active-class 是哪个组件的属性?
active-class是router-link终端属性,用来做选中样式的切换,当router-link标签被点击时将会应用这个样式
4 怎么定义vue-router的动态路由?怎么获取传过来的值?
动态路由的创建,主要是使用path属性过程中,使用动态路径参数,以冒号开头,如下:
{
path: '/details/:id'
name: 'Details'
components: Details
}
访问details目录下的所有文件,如果details/a,details/b等,都会映射到Details组件上。
当匹配到/details下的路由时,参数值会被设置到this.
r
o
u
t
e
.
p
a
r
a
m
s
下
,
所
以
通
过
这
个
属
性
可
以
获
取
动
态
参
数
c
o
n
s
o
l
e
.
l
o
g
(
t
h
i
s
.
route.params下,所以通过这个属性可以获取动态参数 console.log(this.
route.params下,所以通过这个属性可以获取动态参数console.log(this.route.params.id)
- vue-router有哪几种导航钩子?
全局前置守卫
const router = new VueRouter({})
router.beforeEach((to, from, next) = {
// to do somethings
})
to:Route,代表要进入的目标,它是一个路由对象。
from:Route,代表当前正要离开的路由,也是一个路由对象
next:Function,必须需要调用的方法,具体的执行效果则依赖next方法调用的参数
next():进入管道中的下一个钩子,如果全部的钩子执行完了,则导航的状态就是comfirmed(确认的)
next(false):终端当前的导航。如浏览器URL改变,那么URL会充值到from路由对应的地址。
next(’/’)||next({path:’/’}):跳转到一个不同的地址。当前导航终端,执行新的导航。
- next 方法必须调用,否则钩子函数无法resolved
全局后置钩子
router.afterEach((to, from) = {
// to do somethings
})
后置钩子并没有next函数,也不会改变导航本身。
路由独享钩子
beforEnter
const router = new VueRouter({
routes: [
{
path: ‘/home’,
component: Home,
beforeEnter: (to, from, next) = {
// to do somethings
// 参数与全局守卫参数一样
}
}
]
})
组件内导航钩子
const Home = {
template:<div</div
,
beforeRouteEnter(to, from, next){
// 在渲染该组件的对应路由被 confirm 前调用
// 不能获取组件实例 ‘this’,因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next){
// 在当前路由改变,但是该组件被复用时调用
// 例:对于一个动态参数的路径 /home/:id,在/home/1 和 /home/2 之间跳转的时候
// 由于会渲染同样的 Home 组件,因此组件实例会被复用,而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 ‘this’
},
beforeRouteLeave(to, from, next){
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 ‘this’
}
}
beforeRouterEnter不能访问this,因为守卫在导航确认前被调用,因此新组建还没有被创建,可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并把实例作为回调的方法参数。
const Home = {
template:<div</div
,
beforeRouteEnter(to, from, next){
next( vm = {
// 通过 ‘vm’ 访问组件实例
})
}
}
-
$route和 $router的区别是什么?
router为VueRouter的实例,是一个全局路由对象,包含了路由跳转的方法、钩子函数等。
route 是路由信息对象||跳转的路由对象,每一个路由都会有一个route对象,是一个局部对象,包含path,params,hash,query,fullPath,matched,name等路由信息参数。 -
vue-router响应路由参数的变化
• 用watch 检测
// 监听当前路由发生变化的时候执行
watch: {
$route(to, from){
console.log(to.path)
// 对路由变化做出响应
}
}
• 组件内导航钩子函数
beforeRouteUpdate(to, from, next){
// to do somethings
} -
vue-router响应路由参数的变化
• 用watch 检测
// 监听当前路由发生变化的时候执行
watch: {
$route(to, from){
console.log(to.path)
// 对路由变化做出响应
}
}
• 组件内导航钩子函数
beforeRouteUpdate(to, from, next){
// to do somethings
} -
vue-router的两种模式
• hash
o 原理是onhashchage事件,可以在window对象上监听这个事件
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL)
let hash = location.hash.slice(1)
}
• history
o 利用了HTML5 History Interface 中新增的pushState()和replaceState()方法。
o 需要后台配置支持。如果刷新时,服务器没有响应响应的资源,会刷出404, -
vue-router实现路由懒加载(动态加载路由)
• 把不同路由对应的组件分割成不同的代码块,然后当路由被访问时才加载对应的组件即为路由的懒加载,可以加快项目的加载速度,提高效率
const router = new VueRouter({
routes: [
{
path: ‘/home’,
name: ‘Home’,
component:() = import(’…/views/home’)
}
]
})
Vue常见面试题
1.vue 的优点?
vue的优势:轻量级框架、简单易学、双向数据绑定、组件化、数据和结构的分离、虚拟DOM、运行速度快。
2. vue父组件向子组件传递数据?
子组件向父组件出传递数据,使用自定义事件的方式。
父组件向子组件传递数据,使用props属性的方式。
3. vue子组件向父组件传值?
-
v-if和v-show的相同点和不同点?
1、相同点:
v-show 和 v-if 都能控制元素的显示和隐藏。
2、不同点:
2.1实现本质方法不同
v-show 本质就是通过设置 css 中的 display 设置为 none,控制隐藏
v-if 是动态的向 DOM 树内添加或者删除 DOM 元素
2.2)编译的区别
v-show 其实就是在控制 css v-if 切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件
监听和子组件
2.4)性能比较
v-show 只编译一次,后面其实就是控制 css,而 v-if 不停的销毁和创建,故 v-show
性能更好一。
4、总结(适用场景):
如果要频繁切换某节点时,使用 v-show(无论 true 或者 false 初始都会进行渲染,此
后通过 css 来控制显示隐藏,因此切换开销比较小,初始开销较大),如果不需要频繁切换某节
点时,使用 v-if(因为懒加载,初始为 false 时,不会渲染,但是因为它是通过添加和删除 dom
元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销比较大) -
如何让css只在当前组件中起作用?
当前组件<style>写成<style scoped>
-
<keep-alive></keep-alive>
的作用是什么?
<keep-alive></keep-alive>
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
大白话: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>
进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染 -
vue如何获取并操作DOM元素
方法一:
直接给相应的元素加id,然后再document.getElementById(“id”);获取,然后设置相应属性或样式;
方法二:
使用ref,给相应的元素加ref=“name” 然后再this.$refs.name获取到该元素,并且可以直接调用子组件中定义的方法; -
说出几种vue当中的指令和它的用法?
1、v-if:判断是否隐藏
2、v-for:数据循环
3、v-bind:class:绑定一个属性
4、v-model:实现数据双向绑定
5、v-if v-show
6、v-once
7、v-html:
8、v-cloak: -
vue-loader是什么?使用它的用途有哪些?
vue-loader会解析文件,提取出每个语言块,如果有必要会通过其他loader处理,最后将他们组装成一个commonjs模块;module.exports出一个vue.js组件对象 -
V-for 为什么必须使用key?
增加Key可以标识组件的唯一性,key的作用主要是为了高效的更新虚拟DOM -
axios的基本概念及安装配置方法?
ajax:异步请求,是一种无需再重新加载整个网页的情况下,能够更新部分网页的技术
axios:用于浏览器和node.js的基于promise的HTTP客户端
1.从浏览器制作XMLHttpRequests
2.让HTTP从node.js的请求
3.支持promise api
4.拦截请求和响应
5.转换请求和响应数据
6.取消请求
7.自动转换成json数据
8.客户端支持防止xsrf
axios的安装:
cmd命令行进入到vue项目下,执行npm install axios 然后执行提示npm install --save axios vue-axios
配置方法:
打开vue的编辑器,找到当前项目的main.js文件,输入:
import axios from ‘axios’
Vue.prototype.axios = axios
这时候还不能跨域请求,
在config下的index.js里输入:proxyTable: { '/api': { //使用"/api"来代替"http://f.apiplus.c" target: 'http://127.0.0.1:5000/', //源地址 changeOrigin: true, //改变源 ,允许跨域 pathRewrite: { '^/api': '' //路径重写 } }
- axios解决跨域问题(vue-cli3)?
https://www.cnblogs.com/l-y-h/p/11815452.html
- axios解决跨域问题(vue-cli3)?
-
vue中v-model的应用及使用详解?
v-model用于表单数据的双向绑定 -
Scss的安装和使用?
-
请说出vue.cli项目中src目录每个文件夹和文件的用法?
assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置;view视图;app.vue是一个应用主组件;main.js是入口文件 -
vue中computed和watch的区别,以及适用场景?
computed:通过属性计算而得来的属性
1、computed内部的函数在调用时不加()。
2、computed是依赖vm中data的属性变化而变化的,也就是说,当data中的属性发生改变的时候,当前函数才会执行,data中的属性没有改变的时候,当前函数不会执行。
3、computed中的函数必须用return返回。
4、在computed中不要对data中的属性进行赋值操作。如果对data中的属性进行赋值操作了,就是data中的属性发生改变,从而触发computed中的函数,形成死循环了。
5、当computed中的函数所依赖的属性没有发生改变,那么调用当前函数的时候会从缓存中读取。
使用场景:当一个值受多个属性影响的时候------------购物车商品结算
watch:属性监听
1、watch中的函数名称必须要和data中的属性名一致,因为watch是依赖data中的属性,当data中的属性发生改变的时候,watch中的函数就会执行。
2、watch中的函数有两个参数,前者是newVal,后者是oldVal。
3、watch中的函数是不需要调用的。
4、watch只会监听数据的值是否发生改变,而不会去监听数据的地址是否发生改变。也就是说,watch想要监听引用类型数据的变化,需要进行深度监听。“obj.name”(){}------如果obj的属性太多,这种方法的效率很低,obj:{handler(newVal){},deep:true}------用handler+deep的方式进行深度监听。
5、特殊情况下,watch无法监听到数组的变化,特殊情况就是说更改数组中的数据时,数组已经更改,但是视图没有更新。更改数组必须要用splice()或者 s e t 。 t h i s . a r r . s p l i c e ( 0 , 1 , 100 ) − − − − − 修 改 a r r 中 第 0 项 开 始 的 1 个 数 据 为 100 , t h i s . set。this.arr.splice(0,1,100)-----修改arr中第0项开始的1个数据为100,this. set。this.arr.splice(0,1,100)−−−−−修改arr中第0项开始的1个数据为100,this.set(this.arr,0,100)-----修改arr第0项值为100。
6、immediate:true 页面首次加载的时候做一次监听。使用场景:当一条数据的更改影响到多条数据的时候---------搜索框
区别:
1、功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
2、是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
3、是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
4、使用场景:computed----当一个属性受多个属性影响的时候,使用computed-------购物车商品结算。watch----当一条数据影响多条数据的时候,使用watch-------搜索框。 -
v-on可以监听多个方法吗?
可以
18. Vue.js中this. n e x t T i c k ( ) 的 使 用 ? t h i s . nextTick()的使用? this. nextTick()的使用?this.nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
19. vue组件中data为什么必须是一个函数?
在 new Vue() 中,data 是可以作为一个对象进行操作的,然而在 component 中,data 只能以函数的形式存在,不能直接将对象赋值给它
17. vue中如何使用event对象?
18. Vue组件间通信6种方式(网上找视频看)?
19. 渐进式框架的理解?
20. Vue中双向数据绑定是如何实现的?
24. 单页面与多页面间的区别及优缺点?
单页面应用(SPA),通俗一点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。多应用于pc端。
多页面(MPA),就是指一个应用中有多个页面,页面跳转时是整页刷新
单页面的优点:
1,用户体验好,快,内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
2,前后端分离
3,页面效果会比较炫酷(比如切换页面内容时的专场动画)
单页面缺点:
1,不利于seo
2,导航不可用,如果一定要导航需要自行实现前进、后退。(由于是单页面不能用浏览器的前进后退功能,所以需要自己建立堆栈管理)
3,初次加载时耗时多
4,页面复杂度提高很多
25.vue 过滤器filter的详解?
1.代码运用的地方
<!-- 在双花括号中 -->
{{ date | formatDate}}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="data | formatDate"></div>
2.场景: 时间格式的转化
-
注册过滤器函数
首先定义过滤器有两种方式,第一种是全局过滤器,我们可以直接在vue对象上使用filter方法注册过滤器,这种全局注册的过滤器在任何一个组件内都可以使用。第二种则是组件内部的过滤器,注册组件内部过滤器则只能在当前组件内使用,接下来我们使用这两种方式注册过滤器函数。
// 全局函数Vue.filter('formatTime', function (value) { const date = new Date(val); const hour = date.getHours(); const minutes = date.getMinutes(); const seconds = date.getSeconds(); return `${hour} : ${minutes} : ${seconds}`; })
4. 过滤器可以串联:
{{ message | filterA | filterB }}
5. 接收参数
{{ message | filterA(‘arg1’, arg2) }}
filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个 参数,普通字符串 ‘arg1’ 作为第二个参数,表达式 arg2 的值作为第三个参数。
26. v-for与v-if的优先级?
永远不要把 v-if 和 v-for 同时用在同一个元素上。
一般我们在两种常见的情况下会倾向于这样做:
为了过滤一个列表中的项目 (比如 v-for=“user in users” v-if=“user.isActive”)。在这种情形下,请将 users替换为一个计算属性 (比如 activeUsers),让其返回过滤后的列表。
为了避免渲染本应该被隐藏的列表 (比如 v-for=“user in users” v-if=“shouldShowUsers”)。这种情形下,请将 v-if 移动至容器元素上 (比如 ul, ol)。
27.static和assets的区别?
assets和static两个都是用于存放静态资源文件。
放在static中的文件不会进行构建编译处理,也就不会压缩体积,在打包时效率会更高,但体积更大在服务器中就会占据更大的空间
放在assets中的文件会进行压缩体积、代码格式化,压缩后会放置在static中一同上传服务器。
因此建议样式文件放在assets中进行打包,引入的第三方文件放到static中,因为引入的文件已经做过打包处理。
28.vue常用的指令
v-if v-for v-html v-text
29.vue常用的修饰符
lazy :v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步
number 如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符
trim 如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符
30.vue中数组变动更新检测?
1.变异方法
顾名思义,变异方法会改变被这些方法调用的原始数组,它们也将会触发视图更新,这些方法如下
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
使用举例:example1.items.push({ message: ‘Baz’ })
2.非变异方法
非变异方法与变异方法的区别就是,非变异方法不会改变原始数组,总是返回一个新数组,
当使用非变异方法时,可以用新数组替换旧数组,非变异方法大致有:filter(), concat() 和 slice()
31.Vue.set方法(视图更新)?
https://www.cnblogs.com/dream111/p/13519818.html
32.vue自定义指令详解?
https://www.html.cn/qa/vue-js/19257.html
33.vue.js的两大核心?
vue.js的两大核心:1. 数据驱动 ------------- 2.组件系统
- 数据驱动,也就是数据的双向绑定
Vue 响应式核心就是,getter 的时候会收集依赖,setter 的时候会触发依赖更新
vue将遍历data中对象的所有property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。
getter 的时候我们会收集依赖,依赖收集就是订阅数据变化watcher的收集,依赖收集的目的是当响应式数据发生变化时,能够通知相应的订阅者去处理相关的逻辑。
setter 的时候会触发依赖更新,之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。 - 组件系统
组件的核心选项
1 模板(template):模板声明了数据和最终展现给用户的DOM之间的映射关系。
2 初始数据(data):一个组件的初始数据状态。对于可复用的组件来说,这通常是私有的状态。
3 接受的外部参数(props):组件之间通过参数来进行数据的传递和共享。
4 方法(methods):对数据的改动操作一般都在组件的方法内进行。
5 生命周期钩子函数(lifecycle hooks):一个组件会触发多个生命周期钩子函数,最新2.0版本对于生命周期函数名称改动很大。
6 私有资源(assets):Vue.js当中将用户自定义的指令、过滤器、组件等统称为资源。一个组件可以声明自己的私有资源。私有资源只有该组件和它的子组件可以调用
34.Jquery和vue对比?
vue适用的场景:复杂数据操作的后台页面,表单填写页面
jquery适用的场景:比如说一些html5的动画页面,一些需要js来操作页面样式的页面
然而二者也是可以结合起来一起使用的,vue侧重数据绑定,jquery侧重样式操作,动画效果等,则会更加高效率的完成业务需求
35.vue—组件引入及使用的几种方式?
@符号的使用
组件的放置位置
36.vue-cli打包项目后路径错误问题?
一、问题描述
执行 npm run build 命令后,打包生成dist文件夹,访问的时候报如下错误:
二、解决办法
在根目录下,新建 vue.config.js文件,内容如下,
module.exports = {
publicPath:'./',
configureWebpack:{
resolve: {
alias: {
'assets': '@/assets',
'common': '@/common',
'components': '@/components',
'network': '@/network',
'views': '@/views',
'plugins': '@/plugins',
}
}
}
}
37.前端三大框架的对比?
[MVX框架模式:MVC+MVP+MVVM
1.MVC:Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开。
View通过Controller来和Model联系,Controller是View和Model的协调者,View和Model不直接联系,基本联系都是单向的。
用户User通过控制器Controller来操作模板Model从而达到视图View的变化。
2.MVP:是从MVC模式演变而来的,都是通过Controller/Presenter负责逻辑的处理+Model提供数据+View负责显示。
在MVP中,Presenter完全把View和Model进行了分离,主要的程序逻辑在Presenter里实现。
并且,Presenter和View是没有直接关联的,是通过定义好的接口进行交互,从而使得在变更View的时候可以保持Presenter不变。
MVP模式的框架:Riot,js。
3.MVVM:MVVM是把MVC里的Controller和MVP里的Presenter改成了ViewModel。Model+View+ViewModel。
View的变化会自动更新到Model, Model的变化也会自动同步到View上显示。
这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作。
Vue.js是什么?
看到了上面的框架模式介绍,我们可以知道它是属于MVVM模式的框架。那它有哪些特性呢?
其实Vue.js不是一个框架,因为它只聚焦视图层,是一个构建数据驱动的Web界面的库。
Vue.js通过简单的API(应用程序编程接口)提供高效的数据绑定和灵活的组件系统。
Vue.js的特性如下:
-
轻量级的框架
-
双向数据绑定
-
指令
-
插件化
Vue.js与其他框架的区别?
- 与AngularJS的区别
相同点:
都支持指令:内置指令和自定义指令。
都支持过滤器:内置过滤器和自定义过滤器。
都支持双向数据绑定。
都不支持低端浏览器。
不同点:
1.AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观。
2.在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。
Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立触发的。
对于庞大的应用来说,这个优化差异还是比较明显的。
- 与React的区别
相同点:
React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用。
中心思想相同:一切都是组件,组件实例之间可以嵌套。
都提供合理的钩子函数,可以让开发者定制化地去处理需求。
都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载。
在组件开发中都支持mixins的特性。
不同点:
React依赖Virtual DOM,而Vue.js使用的是DOM模板。React采用的Virtual DOM会对渲染出来的结果做脏检查。
Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作DOM。
38.如何实现跨组件 v-model(双向数据绑定)?
39.delete和Vue.delete删除数组的区别?
40.SPA首屏加载慢如何解决?
1.将公共的js库用script引入,让浏览器并行下载资源
2.配置路由,组件,页面。使用懒加载,在调用某个组件时在下载某个js
3.加一个首屏的loading视图,可以提高用户体验
41.vue-router与location.href的用法区别?
42.详解Vue的slot新用法?
https://www.cnblogs.com/dream111/p/13520027.html
43.axios和ajax优缺点的理解?
https://blog.csdn.net/changbozizf/article/details/105456089?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-1-105456089.nonecase&utm_term=axios%E7%9A%84%E4%BC%98%E7%BC%BA%E7%82%B9
44. Vue封装组件的过程详解?
https://blog.csdn.net/tangxiujiang/article/details/79620542
45. vue 各种组件通信方法(父子 子父 兄弟 爷孙 毫无关系的组件)、
父子组件通信
props 和 $emit 父子组件通信
子组件有时需要与父组件进行沟通,沟通的方式就是子组件 emit 事件,父组件通过监听这个事件来做进一步动作。而父组件与子组件通信则使用 props
假设这里有一个父组件并引入了一个子组件 my-comp:
1 <my-comp v-for="msg in msgs" :key="msg.id" :msg="msg"></my-comp>
父组件有一系列 msg 数据需要通过子组件渲染,将 msg 作为 prop 传递给子组件即可:
import MyComp from '@/components/MyComp.vue'
export default {
name: 'home',
components: {
MyComp
},
data () {
return {
msgs: [{
id: 1, data: 'hello js'
}, {
id: 2, data: 'css world'
}, {
id: 3, data: 'animated style'
}]
}
}
}
我们通过点击子组件每一项触发一个事件,父组件监听这个事件去动态改变子组件的 color 样式,这就是父组件监听子组件事件,事件处理函数可以从子组件传递值给父组件:
<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg" :colored="colored" @handle-change-color="handleChangeColor"></my-comp>
首先增加一个事件 handle-change-color 当这个事件被触发时修改名为 color 的 data,然后将 colored 通过 props 传入到子组件:
import MyComp from ‘@/components/MyComp.vue’
export default {
name: ‘home’,
components: { // 注册组件
MyComp
},
data () {
return {
colored: false, // 状态
msgs: [{
id: 1, data: ‘hello js’
}, {
id: 2, data: ‘css world’
}, {
id: 3, data: ‘animated style’
}]
}
},
methods: {
handleChangeColor () {
this.colored = !this.colored // 监听事件动态改变 colored
}
// handleChangeColor (param) { // 子组件触发的事件可能包含参数
}
}
然后编辑子组件:
<div>
<div @click="handleClick" :style="{color}">
{{msg.id}} - {{msg.data}} ⭕
</div>
</div>
首先渲染数据,并监听 click 点击事件,当点击触发事件处理函数 handleClick
export default {
name: 'MyComp',
computed: {
color () { // color 为样式
return this.colored ? 'red' : 'black' // 根据父组件传入的 props 动态修改样式
}
},
props: ['msg', 'colored'],
methods: {
handleClick (e) {
this.$emit('handle-change-color') // 使用 $emit 方法触发父组件 handle-change-color 事件
// this.$emit('handler', 'param') // 还可以给事件传递参数
}
}
}
子组件接收 colored 父组件传递来的 prop,返回一个计算后的属性 color,根据 colored 返回不同样式。handleClick 处理当子组件元素被点击时 $emit 派发父组件的 handle-change-color 事件
效果如下:
父组件 $children 操作子组件
使用 $children 操作子组件。如上述例子中,colored 被定义在父组件中,可以将其移动到子组件中,并在父组件通过 $children 访问到子组件:
<template>
<div @click="handleClick" class="home">
<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg"></my-comp>
</div>
</template>
handleClick 事件被放置在 div 中
import MyComp from '@/components/MyComp.vue'
export default {
// ...
data () {
return {
msgs: [{
// ...
}]
}
},
methods: {
handleClick () {
this.$children.forEach(child => {
child.$data.colored = !child.$data.colored // 逐一控制子组件的 $data
})
}
}
}
在子组件中不需要 $emit 事件,只需维护一个 data:
export default {
name: 'MyComp',
data () {
return {
colored: false // colored 状态
}
},
computed: {
color () {
return this.colored ? 'red' : 'black'
}
},
props: ['msg']
}
子组件 $parent 访问父组件
子组件可通过 $parent 来修改父组件的 $data,因此 colored 定义在父组件中。
<template>
<div class="home">
<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg" :colored="colored"></my-comp>
</div>
</template>
通过 prop 传递 colored 参数给子组件
import MyComp from '@/components/MyComp.vue'
export default {
name: 'home',
components: {
MyComp
},
data () {
return {
colored: false, // 父组件维护一个 colored 状态
msgs: [{
// ...
}]
}
}
}
父组件定义 colored 状态
<template>
<div>
<div @click="handleClick" :style="{color}">
{{msg.id}} - {{msg.data}} ⭕
</div>
</div>
</template>
子组件渲染 msg 并监听 click 事件
export default {
// ...
props: ['msg', 'colored'],
methods: {
handleClick (e) {
this.$parent.$data.colored = !this.$parent.$data.colored
}
}
}
通过 $parent 访问父组件,并修改 $data 状态
非父子组件通信
中央事件总线
我们可以使用使用中央事件总线来处理非父子组件间的通信
具体步骤是创建一个 Vue 实例,然后 o n 监 听 事 件 , on 监听事件, on监听事件,emit 来派发事件
// src/eventBus.js
import Vue from 'vue'
export default new Vue()
首先创建并导出一个 Vue 实例
import bus from '@/eventbus'
export default {
// ...
methods: {
handleClick (e) {
bus.$emit('change-color')
}
}
}
后代元素 $emit 触发 eventBus 的事件
import bus from '@/eventbus'
export default {
// ...
mounted () {
bus.$on('change-color', () => {
this.colored = !this.colored
})
}
}
祖先元素 $on 方法监听 eventBus 的事件
provide/inject
适用于祖先和后代关系的组件间的通信,祖先元素通过 provide 提供一个值,后代元素则通过 inject 获取到这个值。这个值默认是非响应的,如果是对象那么则是响应式的:
export default {
name: 'home',
provide () {
return {
colored: this.colored // 依赖于 data
}
},
components: {
MyComp
},
data () {
return {
colored: { // 必须为对象
value: false
},
msgs: [{
// ...
首先通过 provide 对外提供一个 colored,这个属性依赖于 data 中的 colored,该变量必须为一个对象,才是响应式的。
⚠️ 必须为一个对象
methods: {
handleChangeColor () {
this.colored.value = !this.colored.value
}
}
祖先组件监听事件或其他途径去修改 data 改变状态。
export default {
name: 'MyComp',
inject: ['colored'], // inject colored
computed: {
color () {
return this.colored.value ? 'red' : 'black' // do more...
}
},
// ...
后代组件通过 inject 获取到祖先组件提供的对象,根据对象做进一步动作。
$root 直接访问根组件
根据官方的文档,我们可以通过 $root 来直接访问到 Vue 实例
比方说将数据存储在 Vue 实例中:
// src/main.js
new Vue({
data () {
return { // 在这里!!
colored: false
}
},
router,
store,
render: h => h(App)
}).$mount('#app')
然后我们在其他各个组件中都能够使用:
export default {
name: 'MyComp',
// ...
mounted () {
console.log(this.$root) // 直接访问到根组件
},
// ...
}
46.vue封装通用组件?
https://blog.csdn.net/weixin_44135121/category_9384698.html
47.vue更新数组时触发视图更新的方法?
Vue包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
替换数组:
例如:filter(), concat()和 slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用这些非变异方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
注意事项:
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
举个例子:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
为了解决第一类问题,以下两种方式都可以实现和vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也可以使用vm.$set实例方法,该方法是全局方法 Vue.set 的一个别名:
vm.$set(vm.items, indexOfItem, newValue)
为了解决第二类问题,你可以使用 splice:
vm.items.splice(newLength)
vuex常见面试题
- vuex是什么?怎么使用?那些功能场景使用他们?
只用来读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。
在main.js引入store,注入。新建了一个目录store,…… export 。
场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车
state
Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。
mutations
mutations定义的方法动态修改Vuex 的 store 中的状态或数据。
getters
类似vue的计算属性,主要用来过滤一些数据。
action
actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。
2.vuex有几种属性?
有五种,分别是 State、 Getter、Mutation 、Action、 Module
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex
-
不使用vuex 会带来什么问题?
可维护性会下降,想修改数据要维护三个地方; 可读性会下降,因为一个组件里的数据,根本就看不出来是从哪来的; 增加耦合,大量的上传派发,会让耦合性大大增加,本来Vue用Component就是为了减少耦合,现在这么用,和组件化的初衷相背。
-
vue.js中ajax请求代码应该写在组件的methods还是vuex的actions中?
一种是:“请求后端接口”这个ajax代码应该是写在按钮的点击事件处理函数中,然后在这个处理函数里面提交mutations
还一种是:直接将“请求后端接口”这个ajax代码写在actions中,actions中提交mutations,按钮的点击事件处理函数中只写一个分发actions的按钮 -
vuex中如何异步修改状态?
第一步 在你建立vuex的store.js中声明actions方法
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state={//状态对象
count1:1,
},
const mutations={//触发状态
jia(state,n){
state.count1+=n;
},
jian(state){
state.count1--;
},
},
const actions={
jiaAction(context){
context.commit('jia',10)
/*这句话就是说,我现在store调用了同步的方法jia()*/
},
jianAction({commit}){
commit('jian')/*这句话就是说,我现在store调用了同步的方法jian()*/
}
}
export default new Vuex.Store({
state,
mutations,
getters,
actions/*这与state,mutations的操作方法是相同*/
})
2
第二步 在你的模板(比如a.vue)里引入你需要actions方法
1)import引入mapActions
import {mapState,mapMutations,mapGetters,mapActions} from 'vuex'
2)在你的方法中引入 ...mapActions(['jiaAction','jianAction'])
格式一般都是固定照抄即可
代码如下:
<template>
<div>
<div>
{{count1}}
</div>
</div>
</template>
<script>
import store from '@/store'
import {mapState,mapMutations,mapGetters,mapActions} from 'vuex'
export default{
data(){
return{
}
},
methods:{
...mapMutations([
'jia','jian'
]),
...mapActions(['jiaAction','jianAction'])
},
computed:{
...mapState(["count1"]),
},
store
}
</script>
<style scoped>
.color{
color:red;
}
</style>
3
第三步在你的组件的模板(a.vue)里引入点击事件
代码如下:
<template>
<div>
<div>
{{count1}}
</div>
<p>
<button @click="jiaAction">+</button>
<button @click="jianAction">-</button>
</p>
</div>
</template>
整体代码如下:
<template>
<div>
<div>
{{count1}}
</div>
<p>
<button @click="jiaAction">+</button>
<button @click="jianAction">-</button>
</p>
</div>
</template>
<script>
import store from '@/store'
import {mapState,mapMutations,mapGetters,mapActions} from 'vuex'
export default{
data(){
return{
}
},
methods:{
...mapMutations([
'jia','jian'
]),
...mapActions(['jiaAction','jianAction'])
},
computed:{
...mapState(["count1"]),
},
store
}
</script>
注:现在你点击你的+或-的按钮,观察它的值与你把
<button @click="jiaAction">+</button>
<button @click="jianAction">-</button>
换成
<button @click="jia">+</button>
<button @click="jian">-</button>
有何不同?
没有区别说明你调试代码成功
4
第四步 进行异步验证
我们在我们的store.js中的jiaAction加入jiaAction方法
setTimeout(()=>{
context.commit('jian')
},3000)
console.log('我先被执行');
你再观察结果,你会发现jian这个方法在3s之后执行,你点jia依然可以在3s之内先执行,这就是异步修改状态与同步的区别。
整体代码如下:
a.vue部分
<template>
<div>
<div>
{{count1}}
</div>
<p>
<button @click="jiaAction">+</button>
<button @click="jianAction">-</button>
</p>
</div>
</template>
整体代码如下:
<template>
<div>
<div>
{{count1}}
</div>
<p>
<button @click="jiaAction">+</button>
<button @click="jianAction">-</button>
</p>
</div>
</template>
<script>
import store from '@/store'
import {mapState,mapMutations,mapGetters,mapActions} from 'vuex'
export default{
data(){
return{
}
},
methods:{
...mapMutations([
'jia','jian'
]),
...mapActions(['jiaAction','jianAction'])
},
computed:{
...mapState(["count1"]),
},
store
}
</script>
store.js部分
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state={//状态对象
count1:1,
},
const mutations={//触发状态
jia(state,n){
state.count1+=n;
},
jian(state){
state.count1--;
},
},
const actions={
jiaAction(context){
setTimeout(()=>{
context.commit('jian')
},3000)
console.log('我先被执行');
context.commit('jia',10)
/*这句话就是说,我现在store调用了同步的方法jia()*/
},
jianAction({commit}){
commit('jian')/*这句话就是说,我现在store调用了同步的方法jian()*/
}
}
export default new Vuex.Store({
state,
mutations,
getters,
actions/*这与state,mutations的操作方法是相同*/
})
-
vuex 中actions和mutations 的区别?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化Mutation 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法:
store.commit(‘increment’)
Action Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。 让我们来注册一个简单的 action:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。当我们在之后介绍到 Modules 时,你就知道 context 对象为什么不是 store 实例本身了。
实践中,我们会经常用到 ES2015 的 参数解构 来简化代码(特别是我们需要调用 commit 很多次的时候):
actions: {
increment ({ commit }) {
commit('increment')
}
}