Vue
mvvm 和 mvc 区别
MVC 的思想:一句话描述就是 Controller 负责将 Model 的数据用 View 显示出来,换句话说就是在 Controller 里面把 Model 的数据赋值给 View
MVVM 新增了 VM 类,做了两件事达到了数据的双向绑定 一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听
MVVM 与 MVC 最大的区别就是:它实现了 View 和 Model 的自动同步,也就是当 Model 的属性改变时,我们不用再自己手动操作 Dom 元素,来改变 View 的显示,而是改变属性后该属性对应 View 层显示会自动改变(对应Vue数据驱动的思想)
严格的 MVVM 要求 View 不能和 Model 直接通信,而 Vue 提供了$refs 这个属性,让 Model 可以直接操作 View,违反了这一规定,所以说 Vue 没有完全遵循 MVVM
为什么 data 是一个函数
组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果
Vue 组件通讯有哪几种方式
props
和$emit
:父组件向子组件传递数据是通过props
传递的,子组件给父组件传递数据是通过$emit
触发事件来做到的$parent
,$children
获取当前组件的父组件和当前组件的子组件$attrs
和$listeners
,适用于爷孙组件通讯父组件中通过
provide
来提供变量,然后在子组件中通过inject
来注入变量。(官方不推荐在实际业务中使用,但是写组件库时很常用)$refs
获取组件实例envetBus
任意组件数据传递 这种情况下可以使用全局事件总线的方式 , 兄弟组件如何通讯?vuex
状态管理
Vue 的生命周期方法有哪些 一般在哪一步发请求
beforeCreate 在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问
created 实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。这里没有$el,如果非要想与 Dom 进行交互,可以通过 vm.$nextTick 来访问 Dom
beforeMount 在挂载开始之前被调用:相关的 render 函数首次被调用。
mounted 在挂载完成后发生,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom 节点
beforeUpdate 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁(patch)之前。可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程
updated 发生在更新完成之后,当前阶段组件 Dom 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新,该钩子在服务器端渲染期间不被调用。
beforeDestroy 实例销毁之前调用。在这一步,实例仍然完全可用。我们可以在这时进行善后收尾工作,比如清除计时器。
destroyed Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。
activated keep-alive 专属,组件被激活时调用
deactivated keep-alive 专属,组件被销毁时调用
可以在钩子函数 created、beforeMount、mounted 中进行异步请求,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。
异步请求在哪一步发起?
如果异步请求不需要依赖 Dom 推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
- 能更快获取到服务端数据,减少页面 loading 时间;
- ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性
v-if、v-show 的区别
- v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。
- v-show 会被编译成指令,条件不满足时控制样式将对应节点隐藏 (display:none)
使用场景
v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景 v-show 适用于需要非常频繁切换条件的场景
computed 和 watch 的区别
计算属性 computed
- 支持缓存,只有依赖数据发生改变,才会重新进行计算
- 不支持异步,当 computed 内有异步操作时无效,无法监听数据的变化
- computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值,只在相关响应式依赖发生改变时它们才会重新求值
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性, 一般用 computed
- 如果 computed 属性属性值是函数,那么默认会走 get 方法;函数的返回值就是属性的属性值;在 computed 中的,属性都有一个 get 和一个 set 方法,当数据变化时,调用 set 方法
侦听属性 watch
- 不支持缓存,数据发生改变,会直接触发相应的操作
- watch支持异步
- 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值
- 当一个属性发生变化时,需要执行对应的操作
- 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate
:组件加载立即触发回调函数执行deep
: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep 无法监听到数组的变动(通过数字下标修改数组中元素的值)和对象的新增,参考 vue 如何监测数据的表动,只有以响应式的方式触发才会被监听到
Vue 和 原生 js(jquery) 的区别
原生 js、jQuery:jQuery 只是对原生 js 的 API 进行了封装,操作更加方便,但是数据和视图层没有分开,本质上还是要操作 DOM 实现逻辑。
vue:不仅对 js 的 API 实现了封装,还实现了其他功能,使数据和视图层分开,通过数据驱动,操作的是数据,而不是 DOM,能让开发者更加关注到数据上
说说 Vue 的优点和缺点(或者项目为什么选择使用 Vue)
优点:
视图数据分离,
声明式编码
,让操作者不再直接操作 DOM 对象,有更多的去时间思考业务逻辑传统方式编写,依赖关系混乱,代码复用率不高。
组件化
可以提高代码可阅读性以及代码复用率虚拟DOM
+优秀的diff算法
,尽量复用 DOM 节点
4.渐进式框架
,只需一个轻量小巧的核心库
,可以引入各式各样的Vue插件
进行扩展。
缺点:
Vue 是单页面应用
对于搜索引擎不友好,影响SEO
,比如两个 Vue 页面(路由)它的路径是:index.html#aaa 和 index.html#bbb,但对于搜索引擎来说就是一个页面 index.html,这时搜索引擎就无法收录你的页面
Vue2 和 Vue3 的响应式区别
Vue2:
基于Object.defineProperty
,不具备监听数组的能力,需要重新定义数组的原型来达到响应式
Object.defineProperty
无法检测到对象属性的添加和删除
由于 Vue 会在初始化实例时对属性执行getter
/setter
转化,所有属性必须在 data 对象上存在才能让 Vue 将它转换为响应式
深度监听
需要一次性递归,对性能影响比较大
Vue3:
基于Proxy
和Reflect
,可以原生监听数组,可以监听对象属性的添加和删除
提示
不需要一次性遍历data
的属性,可以显著提高性能
因为Proxy
是ES6
新增的属性,有些浏览器还不支持,只能兼容到IE11
vue-router 有几种路由方式?区别?
hash
:url#后面的东西就是 hash,hash 虽然出现再 URL 中,但不会被包含再 HTTP 中,对后端完全没有影响,因此改变 hash 不会重新加载页面(兼容性好,但不美观)
history
:利用 HTML5 History 中新增的 pushState()和 replaceState()当调用它们修改浏览器的历史记录栈后,虽然当前 url 改变了,但浏览器不会刷新页面。这就为单页面应用前端路由“更新视图但不重新请求页面”提供了基础,虽然美观,但是刷新会出现 404,需要后端进行配置
讲一下 VueX 的工作原理?
- Vuex 本质是一个对象
- Vuex 对象有两个属性,一个是 install 方法,一个是 Store 这个类
- install 方法的作用是将 store 这个实例挂载到所有的组件上,注意是同一个 store 实例。
- Store 这个类拥有 commit,dispatch 这些方法,Store 类里将传入的 state 包装成 data,作为 new Vue 的参数,从而实现了 state 值的响应式。
谈一下对 vuex 的理解
vuex 是专门为 vue 提供的全局状态管理系统
,用于多个组件中数据共享
、数据缓存
(无法持久化、内部核心原理是通过创造一个全局实例 new Vue)
主要包括以下几个模块:
State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
Getter:getters 可以认为是 store 的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。(
命名空间
)
Vuex 中 mapState、mapGetters、mapMutations、mapActions
Vue.set()和 vm.$set()
可以使原来对象
和数组
的无法监听变的可监听,使数据正常渲染。
$nexttick 是怎么可以获取到更新后的 dom 的?
vue 是依靠数据驱动视图更新的,该更新的过程是异步的。即:当侦听到你的数据发生变化时, Vue 将开启一个队列(该队列被 Vue 官方称为异步更新队列)。视图需要等队列中所有数据变化完成之后,再统一进行更新。
$nextTick(callback),这里的回调函数( callback)将在数据更新完成,视图更新完毕之后被调用
vue-router 中 push 和 replace 的区别
1.this.$router.push()
描述:跳转到不同的 url,但这个方法会向 history 栈添加一个记录,点击后退会返回到上一个页面。
2.this.$router.replace()
描述:同样是跳转到指定的 url,但是这个方法不会向 history 里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。
3.this.$router.go(n)
相对于当前页面向前或向后跳转多少个页面,类似 window.history.go(n)。n 可为正数可为负数。正数返回上一个页面
项目中 vue-router 设置的是 history 模式,部署到服务器上要怎么处理
我在 koa2 项目中,使用中间件 koa2-connect-history-api-fallback ,它用于处理 vue-router 使用 history 模式返回 404 的问题