v-if和v-show的区别
- v-if是通过控制dom节点的存在与否来控制元素的显隐;
- v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;
为何v-for中要使用key
v-for在更新已渲染的元素队列时,它会根据key值去判断某个值是否被修改。如果被修改则重新渲染这一项,如果没有被修改则继续复用之前的元素,并且会移除 key 不存在的元素。
生命周期
描述vue生命周期(有父子组件的情况下)
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
vue组件如何通讯
父传子值:父组件中使用v-on方式传递,子组件使用props接收。(子组件不能修改从父组件接收的值)
子传父值:子组件利用this.$emit()
向父组件传值,父组件使用v-on监听事件(通过事件形式)
父组件调用子组件的方法:使用$ref
子组件调用父组件的方法:同传值
vue的prop是单向下行绑定:父级的prop的更新会流到子组件中,但是反过来不行,可有时我们需要同步修改父组件中的data值。sync是vue中用于“双向绑定”的语法糖。
<text-document :title.sync="doc.title"></text-document>
//当子组件需要更新 title 的值时,它需要显式地触发一个更新事件:
this.$emit('update:title', newValue)
$emit/$on
用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级
var Event=new Vue();
Event.$emit(事件名,数据);//触发
Event.$on(事件名,data => {});//监听
兄弟组件之间的传值和父子组件之间的传值非常相似,都是通过$emit;
原理是:vue一个新的实例,类似于一个站,连接着两个组件,也就是一个中央事件总线;
下面是一个bus实例:
vue-router传参的几种方式
vue-router传递参数分为两大类,四小类
1.编程式的导航 router.push
- 调用$router.push直接传参
- 通过路由属性中的name匹配路由,再根据params传递参数
- 通过路由属性中的path匹配路由,再根据query传递参数
2.声明式导航 <router-link>
vue 路由传参 params 与 query两种方式的区别
1、用法上的
刚才已经说了,query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.name和this.route.params.name。
2、展示上的
query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
query: 中文做了转码
http://localhost:8080/#/c?sometext=%E8%BF%99%E6%98%AF%E5%B0%8F%E7%BE%8A%E5%90%8C%E5%AD%A6
params: 可以看出地址栏不会带有传入的参数,且再次刷新页面后参数会丢失
http://localhost:8080/#/b
描述组件渲染和更新过程
双向数据绑定v-model的实现原理
MVVM和MVC
- Model(模型):负责从数据库中取数据
- View(视图):负责展示数据的地方
- Controller(控制器):用户交互的地方,例如点击事件等等
- 思想:Controller将Model的数据展示在View上
MVVM - VM也就是视图模型,做了两件事情,一是将模型转为视图,实现方式是双向数据绑定;二是视图转化成模型,实现方式是DOM事件监听。
- 思想:实现了 View 和 Model 的自动同步,也就是当 Model 的属性改变时,我们不用再自己手动操作 Dom 元素,来改变 View 的显示,而是改变属性后该属性对应 View 层显示会自动改变(对应Vue数据驱动的思想)
区别:
整体看来,MVVM 比 MVC 精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作 DOM 元素。因为在 MVVM 中,View 不知道 Model 的存在,Model 和 ViewModel 也观察不到 View,这种低耦合模式提高代码的可重用性
vuex
- vuex五个核心属性?
state,getter,mutation,action - Vuex中状态是对象时,使用时要注意什么?
因为对象是引用类型,复制后改变属性还是会影响原始数据,这样会改变state里面的状态,是不允许,所以先用深度克隆复制对象,再修改。 - getter相当于包装器,不会修改原始数据,只是对原数据包装处理。mutation内部必须是同步函数。action提交的是mutation而不是直接变更状态,可异步。
- 怎么在带命名空间的模块内注册全局的action?
actions: {
actionA: {
root: true,
handler (context, data) { ... }
}
}
- 组件中怎么提交modules中的带命名空间的moduleA中的mutationA?
this.$store.commit('moduleA/mutationA',data)
为什么v-if和v-for不建议用在同一标签?
在Vue中,v-for优先级是高于v-if的,会导致先渲染无用节点,增加无用的dom操作。
不需要响应式的数据应该怎么处理?
在我们的Vue开发中,会有一些数据,从始至终都未曾改变过,这种死数据,既然不改变,那也就不需要对他做响应式处理了,不然只会做一些无用功消耗性能,比如一些写死的下拉框,写死的表格数据,这些数据量大的死数据,如果都进行响应式处理,那会消耗大量性能。
// 方法一:将数据定义在data之外
data () {
this.list1 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list2 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list3 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list4 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
this.list5 = { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx }
return {}
}
// 方法二:Object.freeze()
data () {
return {
list1: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list2: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list3: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list4: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
list5: Object.freeze({xxxxxxxxxxxxxxxxxxxxxxxx}),
}
}
说说nextTick的用处?
Vue采用的是异步更新的策略,通俗点说就是,同一事件循环内多次修改,会统一进行一次视图更新,这样才能节省性能嘛
Vue的SSR是什么?有什么好处?
- SSR就是服务端渲染
- 基于nodejs serve服务环境开发,所有html代码在服务端渲染
- 数据返回给前端,然后前端进行“激活”,即可成为浏览器识别的html代码
- SSR首次加载更快,有更好的用户体验,有更好的seo优化,因为爬虫能看到整个页面的内容,如果是vue项目,由于数据还要经过解析,这就造成爬虫并不会等待你的数据加载完成,所以其实Vue项目的seo体验并不是很好
Vue响应式是怎么实现的?
整体思路是数据劫持+观察者模式
使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的dep属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)。
provide和inject是响应式的吗?
provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
使用场景:由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject可以轻松实现跨级访问祖先组件的数据
// 祖先组件
provide(){
return {
// keyName: { name: this.name }, // value 是对象才能实现响应式,也就是引用类型
keyName: this.changeValue // 通过函数的方式也可以[注意,这里是把函数作为value,而不是this.changeValue()]
// keyName: 'test' value 如果是基本类型,就无法实现响应式
}
},
data(){
return {
name:'张三'
}
},
methods: {
changeValue(){
this.name = '改变后的名字-李四'
}
}
// 后代组件
inject:['keyName']
create(){
console.log(this.keyName) // 改变后的名字-李四
}
如何将获取data中某一个数据的初始状态?
使用实例属性$options
data() {
return {
num: 10
},
mounted() {
this.num = 1000
},
methods: {
howMuch() {
// 计算出num增加了多少,那就是1000 - 初始值
// 可以通过this.$options.data().xxx来获取初始值
console.log(1000 - this.$options.data().num)
}
}
<script>
export default {
name: "Test",
data() {
return {
};
},
//在data外面定义的属性和方法通过$options可以获取和调用
name: "zs",
age: 12,
haha() {
console.log("haha");
},
created() {
console.log(this.$options.name); // zs
console.log(this.$options.age); //12
this.$options.haha(); // haha
},
</script>
Vue2与Vue3的对比
- 对于ts的支持不友好,难以推导数据,类型
- 大量的api挂载在vue对象原型上,难以实现treeshaking
- vue3.0支持
<template>
多个根标签,而2不支持
vue3.0新特性
- setup()
- ref()
- reactive()
- isRef()
- toRefs()
- computed()
- watch()
- LifeCycle Hooks(新的生命周期)
- Template refs
- globalProperties
- Suspense
setup() 函数是 vue3 中,专门为组件提供的新属性。它为我们使用 vue3 的 Composition API 新特性提供了统一的入口, setup 函数会在 beforeCreate 、created 之前执行, vue3也是取消了这两个钩子,统一用setup代替, 该函数相当于一个生命周期函数,vue中过去的data,methods,watch等全部都用对应的新增api写在setup()函数中。
reactive 函数
reactive函数的用法和ref相似,也就是将数据变成响应式数据,当数据发生改变时ui也会自动更新。不同的是ref是基于基本数据类型的,而reactive是用于复杂数据类型,比如对象和数组。
isRef() 用来判断某个值是否为 ref() 创建出来的对象
toRefs() 函数
oRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据
LifeCycle Hooks(新的生命周期)
Template refs
通过refs获取真实dom元素, 这个和react 的用法一样,为了获得对模板内元素或组件实例的引用,我们可以像往常一样在setup()中声明一个ref并返回它
- 还是跟往常一样,在 html 中写入 ref 的名称
- 在steup 中定义一个 ref
- steup 中返回 ref的实例
- onMounted 中可以得到 ref的RefImpl的对象, 通过.value 获取真实dom
<template>
<!--第一步:还是跟往常一样,在 html 中写入 ref 的名称-->
<div class="mine" ref="elmRefs">
<span>1111</span>
</div>
</template>
<script lang="ts">
import { set } from 'lodash';
import { defineComponent, onMounted, ref } from 'vue';
export default defineComponent({
setup(props, context) {
// 获取真实dom
const elmRefs = ref<null | HTMLElement>(null);
onMounted (() => {
console.log(elmRefs.value); // 得到一个 RefImpl 的对象, 通过 .value 访问到数据
})
return {
elmRefs
}
}
});
</script>
Suspense 组件
react的suspense组件可以使我们轻松定义加载延迟组件,vue中使用的suspnese就是在仿照react
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
OtherComponent是通过懒加载加载进来的,所以渲染页面的时候可能会有延迟,但使用了Suspense之后,可优化交互。
在外面使用Suspense标签,并在fallback中声明OtherComponent加载完成前做的事,即可优化整个页面的交互
vue 3.x 完整组件模版结构
一个完成的vue 3.x 完整组件模版结构包含了:组件名称、 props、components、setup(hooks、computed、watch、methods 等)
vue中router与route区别
- route表示当前路由信息,包含当前url解析信息。包含当前路径,参数,query对象等
- router是全局路由对象的实例,是route构造方法的实例
push、go、replace……
vue中的路由钩子
- 全局钩子函数:router.beforeEach router.afterEach
- 针对单个路由钩子函数: beforeEnter
- 组件钩子函数:beforeRouteEnter beforeRouteUpdate beforeRouteLeave
keep-alive对于页面生命周期的影响
keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一 个抽象组件,所以在页面渲染完毕后不会被渲染成一个DOM元素。
activated:页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
注意点:
- created() {}, //只执行一次 之后不会再被执行 可以用activated()代替
- beforeDestroy() 、destroyed() 不会执行 可以用deactivated()代替
- 可以在beforeRouteLeave(to, from, next)生命周期去监听路由离开时做相应的逻辑动态的去更改下个页面时否要被缓存
from.meta.keepAlive = false;
from.meta.keepAlive = true;
- watch里监听路由的变话在其他页面也会执行里面的代码
watch: {
//设置了缓存的路由 在其他页面也会触发改事件
$route(to, from) {
console.log('路由发生了改变')
console.log(to.path);
console.log(from.path);
}
},