vue常见题型(10-15)
文章目录
- 11.Vue中的$nextTick有什么作用
- 11.1.是什么?
- 11.1.1场景
- 11.2.场景
- 12.vue实例挂载的过程(流程)
- 12.1.思考
- 13.diff算法
- 13.1.是什么
- 13.2.比较方式
- 13.3.小结
- 14.组件和插件有什么区别?
- 14.1.组件是什么
- 14.2.插件是什么
- 14.3.区别
- 14.3.1.编写形式
- 14.3.1.1.编写组件
- 14.3.1.2.编写插件
- 14.3.2.注册形式
- 14.3.2.1.组件注册
- 14.3.2.2.插件注册
- 14.4.使用场景
- 15.`Vue`项目中跨域问题
- 15.1.跨域是什么
- 15.2.如何解决
- 15.2.1.CORS
- 15.2.2.Proxy
- 方案一
- 方案二
- 方案三
11.Vue中的$nextTick有什么作用
11.1.是什么?
🍚定义:在下次DOM
更新循环结束之后执行延迟回调。在修改数据之后立即使用此方法,获取更新后的DOM
Vue
此框架在更新DOM
时是异步执行的。当数据发生变化,将开启一个异步更新队列,视图需要等队列
中所有数据变化完成之后,再统一进行更新。
结构
<div id="app">{{dataListMessage}}</div>
构建实例
const vm = new Vue({
el:"#app",
data:{
dataListMessage:"原始值"
}
})
🍿修改值
this.dataListMessage = "新值1"
this.dataListMessage = "新值2"
this.dataListMessage = "新值3"
🍕此时获取页面最新的DOM
节点,却发现获取到的是原先的值
console.log(vm.$el.textContent)//原始值
🌭这是因为dataListMessage
数据在发现变化时,vue
并不会立刻去更新DOM
,而是将修改数据的操作放在了一个异步操作队列中
如果一直修改相同数据,异步操作队列还会进行去重。
等待同一事件循环中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM
的更新。
11.1.1场景
{{num}}
for(let i=0;i<100000;i++){
num = i
}
🥓如果没有nextTick
更新机制,那么num
每次更新值都会触发视图更新(更新10万次),有nextTick
机制,只需要更新一次,所以 nextTick
本质是一种优化策略
11.2.场景
🥗如果想要在修改数据后立刻得到更新后的DOM
结构,可以使用Vue.nextTick()
第一个参数:回调函数(获取最近的DOM
结构)
第二个参数:执行函数上下文
//修改数据
vm.dataListMessage = "111"
//dom还未更新
console.log(vm.$el.textContent)//原始的值
Vue.nextTick(function(){
//dom更新了
console.log(vm.$el.textContent)//111
})
🥞组件内使用vm.$nextTick()
实例方法只需要通过this.$nextTick()
,回调函数中的this
将自动绑定到当前的Vue
实例上
this.dataListMessage = "222新值"
console.log(this.$el.textContent)//“原先的值”
this.$nextTick(function(){
console.log(this.$el.textContent)
})
🥟🥟$nextTick
会返回一个Promise
对象,用async/await
简化
12.vue实例挂载的过程(流程)
12.1.思考
🍔new Vue() 这个过程内部做了什么? 是如何完成数据的绑定;如何将数据渲染到视图的
调用_init
方法
- 定义
$set、$get、$delete、$watch
等方法 - 定义
$on、$off、$emit、$off
等事件 - 定义
_update、$forceUpdate、$destroy
生命周期
调用$mount
进行页面的挂载 - 通过
mountComponent
方法 - 定义
updateComponent
更新函数 - 执行
render
生成虚拟DOM
_update
将虚拟DOM
生成真实DOM
结构,并渲染到页面上
13.diff算法
13.1.是什么
🍔是一种通过同层的树节点进行比较的高效算法
特点:
- 只会在同层进行比较,不会跨层级比较
- 在比较的过程中,循环从两边向中间比较
在很多场景下都有应用,在vue
中,作用于虚拟dom
渲染成真实dom
的新旧VNode
节点比较
13.2.比较方式
🥟整体策略:深度优先、同层比较
- 只会在同层级进行比较
13.3.小结
- 当数据发生改变时,订阅者
watcher
会调用patch
给真实的DOM
打补丁 - 通过
isSameVnode
进行判断,相同则调用patchVnode
方法
patchVnode
做了以下系列操作 - 找到对应的真实
dom
,称为el
- 如果都有文本节点且不相等,将
el
文本节点设置为Vnode
的文本节点 - 如果
oldVnode
有子节点而没有VNode
,则删除el
子节点 - 如果
oldVnode
没有子节点而有VNode
,则将VNode
的子节点真实化后添加到el
- 如果两者都有子节点,则执行
updateChildren
函数比较子节点
🍞updateChildren
主要做了以下操作 - 设置新旧
VNode
的头尾指针 - 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用
patchVnode
进行patch
重复流程,调用createElem
创建一个新节点,从哈希表寻找key
一致的VNode
节点再分情况操作。
14.组件和插件有什么区别?
14.1.组件是什么
🍔回顾以前对组件的定义:
🥞是把图形、非图形的各种逻辑抽象为一个统一的概念来实现开发的模式,在vue中每一个.vue文件都可以视为一个组件。
🍿优势:
- 能降低整个系统的耦合度,在保持接口不变的情况下,可以替换不同的组件快速完成需求
- 调试方便,整个系统是通过组件组合起来的,在有问题时,可以用排除法直接移除组件,进行调试
- 提高可维护性,每个组件职责单一,并且组件在系统中是被复用的,所有对代码进行优化可获得系统的整体升级。
14.2.插件是什么
🌯插件通常用来为 Vue
添加全局功能。插件的功能范围没有严格的限制-一般有以下几种
- 添加全局方法或属性。如
vue-custom-element
- 添加全局资源:指令/过滤器/过渡等。如
vue-touch
- 通过全局混入来添加一些组件选项。如
vue-router
- 添加实例方法,通过把它们添加到
Vue.prototype
上实现 - 一个库,提供自己的
API
,同时提供上面提到的一个或多个功能。如vue-router
14.3.区别
🥟以下几个方面:
- 编写形式
- 注册形式
- 使用场景
14.3.1.编写形式
14.3.1.1.编写组件
🍚编写一个组件,常见的vue
单文件的这种格式,每一个.vue
文件是一个组件
<template>
</template>
<script>
export default{...}
</script>
<style>
</style>
也可以通过template
属性来编写一个组件,如果组件内容多,可以在外部定义template
组件内容,反之,可直接写在template
属性上
<template id="id">
<div>component!</div>
</template>
Vue.component('componentA',{
template:'#id',
template:`<div>component</div>`
})
14.3.1.2.编写插件
🧀插件的实现应该暴露一个install
方法,第一个参数是Vue
构造器,第二个参数是一个可选的选项对象
emitFun.install = function(Vue,options){
//1.添加全局方法或属性
Vue.addGlobalFun = function(){
//...
}
//2.添加全局资源
Vue.directive('zkshyy',{
bind(el,binding,vnode,oldVnode){
//...
}
})
//3.注入组件选项
Vue.mixin({
created:function(){
//...
}
})
//4.添加实例方法
Vue.prototype.$addGlobalFun = function(options){
//...
}
}
14.3.2.注册形式
14.3.2.1.组件注册
🚗vue
组件注册分为全局和局部注册
全局:通过Vue.component
方法,第一个参数为组件名称,第二个参数为传入的配置项
Vue.component('com-name',{})
局部:只需在用到的地方通过components
属性注册一个组件
const comp1 = {...} //定义一个组件
export default{
components:{
comp1 //局部注册
}
}
14.3.2.2.插件注册
🎉通过Vue.use()
的方式进行注册(安装),第一个参数为名字,第二个参数是可选择的配置项
Vue.use(插件名字,{})
需要注意:
注册插件时,需要调用new Vue()
启动应用之前完成
Vue.use
会自动阻止多次注册相同插件,只会注册一次
14.4.使用场景
🧨组件(component)用来构成App
的业务模块,它的目标是App.vue
🎉插件(plugin)用来增加你的技术栈的功能模块,它的目标是Vue
本身
15.Vue
项目中跨域问题
15.1.跨域是什么
🥞本质是浏览器基于同源策略的一种安全手段。
同源策略,是一种约定,是浏览器最核心同时最基本的安全功能。
同源,即指在同一个域,具有以下三个相同点
- 协议相同
- 主机相同
- 端口相同
反之非同源请求,就会产生跨域。一旦跨域,接口是已经把数据返回回来了,是浏览器的限制,而获取不到数据。
15.2.如何解决
🥫列举三种方式
- JSONP
- CORS
- Proxy
在项目中,主要针对CORS
或Proxy
这两种方案进行展开
15.2.1.CORS
🚕CORS
是一个系统,由一系列传输的HTTP头组成,决定浏览器是否阻止前端JavaScript
代码获取跨域请求的响应。
只需要增加一些HTTP
头,让服务器能声明允许的访问来源,只要后端实现了cors
,就实现了跨域。
以koa
框架举例
添加中间件,直接设置Access-Control-Allow-Origin
响应头,
app.use(async(ctx,next)=>{
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, A
uthorization, Accept, X-Requested-With , yourHeaderFeild');
ctx.set('Access-Control-Allow-Methods', 'PUT','POST','GET','DELETE','OPTIONS');
if(ctx.method == 'OPTIONS'){
ctx.body = 200;
}else{
await next();
}
})
🐱🏍Access-Control-Allow-Origin
设置为*其意义不大,实际应用上,上线前会将Access-Control-Allow-Origin
值 设为目标host
15.2.2.Proxy
🍿代理,是一种特殊的网络服务,允许一个通过这个服务与另一个网络终端进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。
一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。
方案一
如果是用vue-cli
脚手架工具搭建的项目,可通过webpack
为我们起一个本地服务器作为请求的代理对象。
通过该服务器转发请求至目标服务器,得到结果再转发给前端,但是,最终发布上线时如果web应用和接口服务器不在一起仍会跨域
在vue.config.js
文件,配置以下代码
amodule.exports = {
devServer:{
host:'127.xxx',
port:8083,
open:true,
proxy:{
'/api':{
target:"",//目标服务器地址
changeOrigin:true,//是否跨域
pathRewrite:{
'^/api':""
}
}
}
}
}
🚜通过axios
发送请求,配置请求的根路径
axios.defaults.baseRUL = '/api'
方案二
还可通过服务端实现代理请求转发
以express
框架为例
var express = require('express');
const proxy = require('http-proxy-middleware')
const app = express()
app.use(express.static(_dirname + '/'))
app.use('/api',proxy({target:'http://localhost:8080',changeOrigin:false}));
module.exports = app
方案三
🥓通过配置nginx
实现代理
server{
listen 80;
# server_name www.josephxia.com;
location / {
root /var/www/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api{
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}