Vue解决了什么问题
虚拟dom:dom操作时非常消耗性能,不再使用原生的dom操作,极大的释放了dom操作,但本质还是操作dom,只是换了一种方式。
视图,数据,结构分离:使数据的修改变得更为简单。不需要修改逻辑代码只需要操作数据即可
组件化:将一个单页面的各种模块拆分到不同的组件中,便于开发以及后期的维护管理
MVVM的理解
model-view-viewmodel的缩写,mvvm把视图和逻辑代码区分开。在mvvm的框架下,view和model没有直接的交互,是通过view-model进行数据的双向交互。
viewmodel通过双向数据绑定,将model和view连接起来,因此model和view的数据同步工作时完全自动的。
开发者只需要关注业务逻辑,不需要手动操作dom,也不需要关注数据的同步问题,这些由mvvm统一管理
自定义组件
在子组件中创建模板,在props中接受父组件传递的数据,在父组件中引入子组件,然后在components中创建子组件,挂载到父组件的template中
props 父传子使用 $emit(参1,参2)子传父时使用 参1是自定义的事件名,参2是要传递的数据,在父组件的子组件中绑定自定义事件名,调用一个函数,函数的形参就是传递的数据
$children 获取的是一个数组 $parent 获取的是一个对象
this.$children[0].msg = "hello world" //父组件修改子组件data中的数据
this.$parent.msg //子组件拿到父组件data中的数据
eventBus 总线程
兄弟传参时使用 在传数据的一方引入bus,
通过函数调用
this.emit(参1,参2),参1是自定义的事件名,参2是要传递的数据,在接收的一方引入bus,在created中调用this.$on(自定义事件名,回调函数(data){})data就是传递的数据
ref/refs 区别在于ref绑定在dom元素上,引用的就是dom元素,refs在组件的实例化调用获取到ref传递的dom元素内容
$attrs / $listeners
将数据挂在到子组件的标签上去后,在子组件中使用this.$attrs直接获取到所有挂载的数据,返回的是一个对象
nextTick的理解
使用的原因是Vue是异步修改DOM的,并不鼓励开发者直接接触DOM,但有时需要对数据更改后的DOM元素做相应的处理,但获取的数据不是修改之后的,所以要使用this.$nextTick()
原理是Vue通过异步队列控制DOM的更新和nextTick回调函数的先后执行顺序
<button @click="change()">按钮</button><h1 ref="gss">{{msg}}</h1>
//JS
export default{
name:"app",
data(){
return {
msg:"123"
}
},
methods:{
change(){
this.msg = "456";
console.log(this.refs["gss"].innerHTML)//123
this.$nextTick(function(){
console.log(this.refs["gss"].innerHTML)//456
})
}
}
}
Vue的生命周期函数
beforeCreate(创建前):在此生命周期函数里,data 和 methods 的数据还没有初始化
created(创建后):在此生命周期内,data和methods中的数据已经初始化完毕,最早使用data数据的钩子函数
beforeMount(载入前):在此生命周期函数里,模板已经在内存中编译好了,但还没有挂载到页面,页面此时是旧的
mounted(载入后):此时页面已经渲染完毕,这个是最早可以操作dom的钩子函数
beforeUpdate(修改前):页面显示的数据旧的,data的数据是新的
updated(修改后):页面于data的数据已经同步
beforeDestroy(销毁前):该钩子函数执行的时候,数据还可以使用
destroyed(销毁后):数据已经销毁完毕
activated(keep-alive组件激活调用)
deactivated(keep-alive组件停用调用)
errorcapture(捕获来自子孙组件错误是调用)
虚拟dom的原理
虚拟dom就是用对象的方式区代真实的dom操作。
当页面打开时浏览器解析HTML元素,构建一个dom树,将状态保存起来,在内存中模拟dom操作,又会生成一个dom树,两个进行比较,根据diff算法找出不同的地方,之渲染一次不同的地方
diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom
双向数据绑定的原理
vue的双向数据绑定只要是采用数据劫持结合开发者和订阅者方式
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式。 通过Object.defineProperty()来劫持各个属性的setter,getter, 在数据变动时发布消息给订阅者,触发相应监听回调
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者。 通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令。
最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;。
数据劫持:当我们访问或设置对象的属性的时候,都会触发相对应的函数,然后在这个函数里返回或设置属性的值。我们可以在触发函数的时候动一些手脚做点我们自己想做的事情,这也就是“劫持”操作
Proxy相比于defineProperty的优势Proxy相比于defineProperty的优势 Vue3.0摒弃了Object.defineProperty,改为基于Proxy的观察者机制探索
Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实施响应。
Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。 如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象才是更好的选择。
而要取代它的Proxy有以下两个优点: 可以劫持整个对象,并返回一个新对象。 有多种劫持操作(13种)
watch、computed和methods的区别
methods在重新渲染的时候每次都会被重新的调用
computed 是自动监听依赖值的变化,从而动态返回内容,主要目的是简化模板内的复杂运算
watch也可以影响数据的变化,当绑定的数据方法变化时触发响应的函数, 需要在数据变化时执行异步或开销较大的操作时使用watch。
virtual-dom原理实现(虚拟dom)
virtual-dom(简称vdom)的概念得益于react的出现react这个框架的非常重要的特性之一。
相比于频繁的手动去操作dom而带来性能问题,vdom很好的将dom做了一层映射关系 进而将在我们本需要直接进行dom的一系列操作,映射到了操作vdom,而vdom上定义了 关于真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作, 并将这些操作放到vdom中进行,这样就通过操作vdom来提高直接操作的dom的效率和性能。
在vue的整个应用生命周期当中,每次需要更新视图的时候便会使用vdom
vdom算法是基于snabbdom算法所做的修改。
实现
①用js对象构造一个虚拟的dom树,插入到文档中;
②状态变更时,记录新树和旧树的差异;
③把上面的差异构建到真正的dom中
vue-router
单页面的跳转
hash:使用URLhash 的值来作为路由
history:依赖于HTML5 History API和服务器配置
abstract:严格模式支持所有的JavaScript运行环境根据model参数来决定时那种方式
原理是更新视图但不重新请求页面
vuex的理解
Vuex 是适用于 Vue.js 应用的状态管理库,为应用中的所有组件提供集中式状态存储与操作,保证了所有状态以可预测的方式进行修改。
优点 当state中定义一个数据后,可以在所在项目的任何组件中进行获取,修改,修改可以得到全局的变更
运行机制:vue提供数据来驱动试图,通过dispath派发actions,通过commit调用mutations的方法,修改state的数据
①state:定义初始数据。
②mutations:更改Vuex的store中的状态的唯一方法是提交mutation
③getters:可以对 state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性
④actions:异步操作初始数据,其实就是调用mutations里面的方法。
⑤module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。
Vuex的映射: state getters需要映射在computed实例中,mutations actions 等需要放在methods实例中
vue从初始化页面–>修改数据–>刷新页面UI过程?
当vue进入初始化页面的时候会遍历data的属性,通过object.defineproperty转换成getet/setter形式,实现数据劫持,
compile对元素的指令进行解析,初始化视图,订阅watcher来更新视图,watcher会添加到Dep中,初始化完毕。数据发生改变时,触发observer的setter方法,
调用Dep.notfiy(),Dep数组开始遍历所有的订阅者,调用update方法,在通过diff算法,patch相应的更新,完成视图的改变
Vue的响应式原理
Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录作为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
Vue.js的特点
轻量级的框架组件化 和 响应式设计实现数据与结构的分离数据的双向绑定 优点是减少了dom操作数据驱动
插槽
插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。
子组件
<template>
<div>
<h1>商品列表</h1>
<solt></solt>
</div>
</template>
<script>
export default { name:'child',
}
</script>
父组件
<template>
<div>
<h1>商品列表</h1>
<child>
<div>苹果,香蕉</div>
</child>
</div>
</template>
vue-router有哪几种导航钩子
① 全局导航钩子:一般用来判断权限,以及页面丢失时需要执行的操作;
beforeEach()每次路由进入之前执行的函数。
afterEach()每次路由进入之后执行的函数。
beforeResolve()2.5新增
② 单个路由(实例钩子)
beforeEnter()
beforeLeave()
③ 组件路由钩子:
beforeRouteEnter()
beforeRouteLeave()
beforeRouteUpdate()
vue组件中的data为什么是一个函数
data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。
Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了
路由懒加载
在单页应用中,如果没有应用懒加载,运用webpack打包后的文件很大,进入首页时,加载的内容过多,不利于用户体验。
而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力。
原理:vue异步组件技术:异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 实现按需加载
一
component:(resolve) => {
require(["@/components/HelloWorld"],resolve);
}
二
const info = () => import("@/components/info");
三
const info = (resolve) => {
import("@/components/info").then(modul => {
resolve(modul);
})
}
四
const info = r => require.ensure([],() => r(
require("@/components/info")
),"info");
Vue.js是什么?
vue就是一个js库,并且无依赖别的js库。vue的核心库只关注视图层,非常容易与其它库或已有项目整合。
Vue.js是一个轻巧、高性能、可组件化的MVVM库,同时拥有非常容易上手的API。
scoped原理及穿透方法
vue中的scoped通过在DOM结构以及css样式上加唯一不重复的标记:data-v-hash的方式,以保证唯一,达到样式私有模块化的目的。
scoped穿透:/deep/ >>>
vue.cli项目中src目录每个文件夹和文件的用法
asstes 静态资源文件
components 组件
router 路由的配置
view 视图
app.vue 应用主组件
main.js 入口文件
Vue中key值的作用
主要是为了高效的更新虚拟DOM
Vue怎么重置data
使用Object.assign(),vm.$data可以获取当前状态下的data,
vm.$options.data可以获取到组件初始化状态下的data。
Object.assign(this.$data, this.$options.data())
组件中写name选项有什么作用
项目使用keep-alive时,可搭配组件的name进行缓存过滤。
DOM做递归组件时需要调用自身name
vue-devtools调试工具里显示的组件名称是由vue中组件name决定的
route和router
route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。router是“路由实例对象”,包括了路由的跳转方法(push、go),钩子函数等。
Vue和React的区别
监听数据变化的实现原理不同:Vue通过getter/setter以及函数的劫持,能快速的计算出Vdom的差异,这是它在渲染的过程中,会跟踪每个组件的依赖关系,不需要重新渲染组件树。react是默认通过比较的引用方式进行,如果不优化,每当应用的状态被改变时,所有的子组件页时重新渲染,导致大量的不必要的vdom重新渲染
数据流的不同:Vue默认双向绑定数据,组件和dom动过v-model双向绑定。但是父子组件之间,props在2x版本中时单项的数据流,react一直提倡单向数据流
模板渲染的方式不同:react是通过JSX渲染模板,vue是通过拓展HTML语法进行渲染
标题首屏加载优化
不长改变的库放到index.html中,用cdn引入然后找到 build/webpack.base.conf.js 文件,在 module.exports = { } 中添加以下代码:
externals: {
'vue': 'Vue',
'vue-router': 'VueRouter',
'element-ui': 'ELEMENT',
},
路由懒加载
vue的组件尽量不要全局引入使用更轻量级的工具库
开启gzip压缩:这个优化是两方面的,前端将文件打包成.gz文件,然后通过nginx的配置,让浏览器直接解析.gz文件。
不生成map文件,找到config/index.js文件,修改为productionSourcceMap:false
Vue3.0的简单了解
新的API
setup()函数
关于Typescript的支持
替换Object.defineProperty为 Proxy 的支持。关于Proxy代替带来的性能上的提升,因为传统的原型链拦截的方法,无法检测对象及数组的一些更新操作,但使用Proxy又带来了浏览器兼容问题。
vue-cli 替我们做了哪些工作
vue-cli是基于 Vue.js 进行快速开发的完整系统,也可以理解成是很多 npm 包的集合。
vue-cli完成的功能
vue 文件 --> .js 文件
ES6 语法 --> ES5 语法
Sass,Less,Stylus --> CSS
对 jpg,png,font 等静态资源的处理
热更新
定义环境变量,区分 dev 和 production 模式
如果开发者需要补充或修改默认设置,需要在 package.json 同级下新建一个 vue.config.js 文件
v-for 与 v-if 的优先级
v-for比v-if优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。
vue怎么兼容IE
使用babel-polyfill插件
$set是干嘛用的
<template>
<h1>{{arr}}</h1>
<button @click="change()">点击</button>
</template>
<script>
export default {
data(){
return {
arr:[1,2,3]
}
},
methods:{
change(){
this.arr[1]=0;
console.log(this.arr); //[1,0,3]
}
}
}
</script>
当我们点击按钮想要根据数组arr的下标改变其元素的时候,你会发现data中的数据改变了,但是页面中的数据并没有改变。这时候就需要$set出场了。
change(){
this.$set(this.list,1,0);
}
改变/添加 对象属性的时候:this.$set(data实例,“属性名(添加的属性名)”,“属性值(添加的属性值)”)
改变/添加 数组属性的时候:this.$set(data实例,数组下标,“改变后的元素(添加的元素)”)
vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。让 Vue 追踪依赖,在属性被访问和修改时通知变化。
所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
当你在对象上新加了一个属性newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制,vue.$set是能让vue知道你添加了属性, 它会给你做处理
vue中"dependencies","devDependencies"是什么?
dependencies是生产环境
devDependencies 是开发测试环境