vue
组件传值
非父子组件之间传递数据 父子 祖孙 兄弟
3.1 引入第三方 new vue 定义为 eventBus
在组件中 created 中订阅方法 eventBus.$on("自定义事件名",methods 中的方法名)
在另一个兄弟组件中的 methods 中写函数,在函数中发布 eventBus 订阅的方法
eventBus.$emit("自定义事件名”)
在组件的 template 中绑定事件(比如 click)
父组件中通过 provide 来提供变量,然后在子组件中通过 inject 来注入变量。(官方不推荐在实际业务中适用,但是写组件库时很常用。) 祖孙
pros 和 $emit 父子组件
vuex
$refs 父子组件
watch、methods 和 computed 的区别?
怎么认识vuex **vuex 有哪几种属性?**
Vuex就是一个仓库,仓库里面放了很多对象。
其中state就是数据源存放地,对应于一般Vue对象里面的data
它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
vuex的Getter特性
A、getters 可以对State进行计算操作,它就是Store的计算属性
B、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
C、 如果一个状态只在一个组件内使用,是可以不用getters
· vuex的Mutation特性
Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。
Vuex 页面刷新数据丢失怎么解决
第一次加载页面会触发那几个钩子函数
父子组件 钩子函数的加载顺序
父beforeCreated ->父created ->父beforeMounted ->子beforeCreated ->子created ->子beforeMounted ->子mounted -> 父mounted
实现数据双向绑定的原理
Vue 主要通过以下 4 个步骤来实现数据双向绑定的:
实现一个监听器 Observer:对数据对象进行遍历,包括子属性对象的属性,利用 Object.defineProperty() 对属性都加上 setter 和 getter。这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化。
实现一个解析器 Compile:解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,调用更新函数进行数据更新。
实现一个订阅者 Watcher:Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁 ,主要的任务是订阅 Observer 中的属性值变化的消息,当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。
实现一个订阅器 Dep:订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher,对监听器 Observer 和 订阅者 Watcher 进行统一管理。
Vue-router 的钩子函数都有哪些?
vue-router 有 3 种路由模式:hash、history、abstract,对应的源码如下所示:
- hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
- history : 依赖 HTML5 History API 和服务器配置。具体可以查看 HTML5 History 模式;
- abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.
路由传值的方式有哪几种
Vue-router 传参可以分为两大类,分别是编程式的导航 router.push 和声明式的导航
1、router.push
this.$router.push("home") 直接传递路由地址,但是不能传递参数
this.$router.push({name:"news",params:{userId:123}) 这种方式传递参数目标页面刷新会报错
this.$router.push({path:"/news',query:{uersId:123})
查询参数 和 name 配对的式 params,和 path 配对的是 query
2、声明式导航
字符串 <router-link to:"news"></router-link>
<router-link :to:"{name:'news',params:{userid:1111}}"></route-link>
<router-link :to="{path:'/news',query:{userId:1111}}"></router-link>
query 和 params 之间的区别是什么?(必会)
1、query 要用 path 来引入,params 要用 name 来引入
2、接收参数时,分别是 this.$route.query.name 和 this.$route.params.name(注意:是$route
而不是$router
3、query 更加类似于我们 ajax 中 get 传参,params 则类似于 post,前者在浏览器的地址栏中 显示,params 不显示
4、params 传值一刷新就没了,query 传值刷新还存在
$route 和$router 的区别是什么?
$route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由
信息参数
$router 为 VueRouter 的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,
例如 history 对象,经常用的跳转链接就可以用 this.router.push 会往 history 栈中添加一个新的记 录。返回上一个 history 也是使用$router.go 方法
路由之间是怎么跳转的?有哪些方式?
<router-link to="需要跳转到页面的路径">
this.$router.push()跳转到指定的 url,并在 history 中添加记录,点击回退返回到上一个页面
this.$router.replace()跳转到指定的 url,但是 history 中不会添加记录,点击回退到上上个页面
this.$touter.go(n)向前或者后跳转 n 个页面,n 可以是正数也可以是负数
为什么data是一个函数
组件的data写成一个函数,数据以函数返回值形式定义,这样复用一次组件,就会返回一个新的data
而单纯的写成对象形式,组件实例共用一份data
Vue 项目优化的解决方案都有哪些?(必会)
1、 使用 mini-css-extract-plugin 插件抽离 css
2、 配置 optimization 把公共的 js 代码抽离出来
3、 通过 webpack 处理文件压缩
4、 不打包框架、库文件,通过 cdn 的方式引入
5、 小图片使用 base64
6、 配置项目文件懒加载
7、 UI 库配置按需加载
开启 Gzip 压缩
防抖节流
nextTick
在下次dom更新循环结束之后执行的延迟回调,在修改数据之后立即使用这个方法,获取更新后的dom
怎样理解 Vue 的单项数据流
数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改。这样会防止从子组件意外改变父组件的状态,从而导致你的应用的数据流向难以理解。
**hash 模式**
1、location.has 的值实际就是 URL 中 # 后面的东西。它的特点在于:hash虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
2、可以为 hash 的改变添加监听事件
`window.addEventListener("hashchange",funcRef,false)`
每一次改变 hash (window.location.hash),都会在浏览器的访问历史中增加一个记录,利用hash的以上特点,就可以实现前端路由“更新视图但不重新请求页面”的功能了
特点:兼容性好但是不美观
**history 模式**
利用 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。
这两个方法应用于浏览器的历史记录站,在当前已有的 back、forward、go 的基础上,他们提供了对历史记录进行修改的功能。这两个方法有个共同点:当调用他们修改浏览器历史记录栈后,虽然当前 URL 改变了,但浏览器不会刷新页面,这就为单页面应用前端路由“更新视图但不重新请求页面”提供了基础
特点:虽然美观,但是刷新会出现 404 需要后端进行配置。
diff 算法了解吗?
diff算法采用同级比较。
- 1、tag 标签不一致直接新节点替换旧节点。
- 2、tag 标签一样。
先替换属性
对比子元素
- 新老都有子元素,采用双指针方式进行对比
sameVnode 判断tag和key完全相同为同一节点,进行节点复用
头和头相等对比
尾和尾相等对比
头和尾相等对比
------
sameVnode 的时候传入两个新老子节点patch(oldChild,newChild)
乱序情况 -- 上面的都不符合,先遍历旧子节点数组形成 key值映射的map对象。
然后根据新子节点数组循环 按照key值和位置关系移动以及新增节点 最后删除多余的旧子节点 如果移动旧节点同样需要patch(oldChild,newChild)
- 新的有子元素,老的没有子元素。-- 直接将子元素虚拟节点转化成真实节点插入即可。
- 新的没有子元素,老的有子元素。 -- 直接清空 innerHtml
- 3、无 tag 标签 -- 文本节点直接比较内容是否一致
this指向
```
var a=2;
function printA(){
console.log(this.a);
}
var obj={
a:10,
foo:printA,
bar:function(){
printA();
}
}
obj.bar();
var f=obj.foo;
f();
var a = 2;
var obj = {
a:10,
timer: function () {
setTimeout(function () {
console.log(this.a);
})
}
};
obj.timer();
```
宏任务 微任务
console.log('script start')
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
setTimeout(function() {
console.log('setTimeout')
}, 0)
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
console.log('script end')
//*script start => async2 end =>Promise => script end => async1 end => promise1=> promise2 => setTimeout*