vue 的路由传参方式
在 Vue.js 中,路由传参主要有两种方式:通过路径参数和通过查询参数。
路径参数: 路径参数是 URL 的一部分,通常用于标识特定的资源。例如:
// 定义路由 const routes = [ { path: '/user/:id', component: User } ] //
在组件中获取参数 export default { created() { console.log(this.$route.params.id)
} }
查询参数:
查询参数是 URL 中 ? 后面的键值对,通常用于传递非必要的参数。例如:
// 定义路由 const routes = [ { path: '/search', component: Search } ] //
在组件中获取参数 export default { created() {
console.log(this.$route.query.keyword) } }
编程式导航传参:
可以使用 this.$router.push 或 this.$router.replace 方法进行编程式导航并传递参数。例如:
// 传递路径参数 this.$router.push({ name: 'user', params: { id: 123 } }) //
传递查询参数 this.$router.push({ path: '/search', query: { keyword: 'vue' } })
通过以上方式,可以在 Vue.js 中实现路由传参,并在组件中获取相应的参数。
vue 响应式原理以及双向绑定实现代码
Vue.js 的响应式原理是通过数据劫持和发布-订阅模式来实现的。核心是 Object.defineProperty 方法,通过它来劫持对象的属性,并在属性被访问或修改时进行相应的操作。
响应式原理:
- 数据劫持:通过
Object.defineProperty劫持对象的属性,拦截属性的读取和设置操作。 - 发布-订阅模式:当数据变化时,通知所有依赖该数据的订阅者进行更新。
通过以上代码,可以实现一个简单的响应式系统,当 state.count 变化时,会自动触发依赖该数据的副作用函数进行更新。
双向绑定是通过 v-model 指令实现的,它本质上是语法糖,封装了 value 和 input 事件的绑定。例如:
v-model 会自动绑定 input 元素的 value 属性和 input 事件,实现数据的双向绑定。
vue3 响应式原理,有什么不同
Vue 3 的响应式系统相比 Vue 2 有了显著的改进,主要体现在以下几个方面:
-
Proxy 代替 Object.defineProperty: Vue 3 使用
Proxy对象代替了 Vue 2 中的Object.defineProperty。Proxy可以直接监听对象和数组的变化,并且可以监听动态添加的属性,这解决了 Vue 2 无法检测数组和对象新增属性的问题。 -
更好的性能: 由于
Proxy的使用,Vue 3 的响应式系统在性能上有了显著提升。Proxy可以直接监听整个对象,而不需要递归地遍历每个属性,这使得响应式系统的初始化速度更快。 -
更灵活的 API: Vue 3 提供了
reactive和ref两种 API 来创建响应式数据。reactive用于创建深层次的响应式对象,而ref用于创建基本类型的响应式数据。这使得开发者可以根据具体需求选择合适的 API。 -
更好的 TypeScript 支持: Vue 3 的响应式系统对 TypeScript 有更好的支持,类型推断更加准确,使得在 TypeScript 项目中使用 Vue 3 更加方便。
通过以上改进,Vue 3 的响应式系统在性能、灵活性和开发体验上都有了显著提升。
Vue2如何做数组的监听
在 Vue 2 中,由于 Object.defineProperty 的限制,无法直接监听数组的变化。为了实现对数组的监听,Vue 2 对数组的方法进行了重写,拦截了数组的变更操作。以下是 Vue 2 中监听数组变化的几种方式:
- 重写数组方法:
Vue 2 重写了数组的变更方法,如
push、pop、shift、unshift、splice、sort和reverse,在这些方法被调用时,会触发视图更新。
const vm = new Vue({
data: {
items: [1, 2, 3]
}
})
// 触发视图更新
vm.items.push(4)
- 使用
Vue.set方法: 当需要向数组中添加新元素时,可以使用Vue.set方法,这样可以确保新元素是响应式的。
Vue.set(vm.items, index, newValue)
- 使用
splice方法: 通过splice方法可以在数组中插入或删除元素,并且会触发视图更新。
vm.items.splice(index, 0, newValue) // 插入新元素
vm.items.splice(index, 1) // 删除元素
通过以上方式,可以在 Vue 2 中实现对数组的监听,并确保数组的变更能够触发视图更新。
Vue3实现数组的监听的原理
在 Vue 3 中,数组的监听是通过 Proxy 对象来实现的。Proxy 可以直接监听数组的变化,并且可以监听动态添加的属性,这解决了 Vue 2 无法检测数组和对象新增属性的问题。
实现原理:
-
Proxy 对象: Vue 3 使用
Proxy对象来代理数组,通过Proxy可以拦截数组的各种操作,如读取、设置、删除等。 -
捕获器(Traps):
Proxy提供了多种捕获器(traps),如get、set、deleteProperty等,这些捕获器可以在数组操作时执行特定的逻辑。 -
响应式系统: 当数组发生变化时,Vue 3 的响应式系统会通知所有依赖该数组的订阅者进行更新,从而实现视图的自动更新。
示例代码:
import { reactive } from 'vue'
const state = reactive({
items: [1, 2, 3]
})
// 触发视图更新
state.items.push(4)
通过以上方式,Vue 3 可以高效地监听数组的变化,并确保数组的变更能够触发视图更新。
vue 的 props,data,computed,watch,生命周期钩子函数生效的先后顺序
在 Vue.js 中,组件的各个属性和生命周期钩子函数的生效顺序如下:
- props:首先初始化
props,从父组件传递的属性。 - data:然后初始化
data,组件自身的状态数据。 - computed:接着初始化
computed属性,基于data和props计算得出的属性。 - watch:初始化
watch选项,监听data和props的变化。 - 生命周期钩子函数:
beforeCreate:实例初始化之后,数据观测和事件配置之前调用。created:实例创建完成后调用,此时可以访问数据和事件,但组件还未挂载。beforeMount:在挂载开始之前调用,相关的render函数首次被调用。mounted:实例被挂载后调用,此时el被新创建的vm.$el替换。beforeUpdate:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。updated:由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。beforeDestroy:实例销毁之前调用,此时实例仍然完全可用。destroyed:实例销毁后调用,调用后,Vue 实例指示的所有东西都会解除绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
通过以上顺序,可以更好地理解 Vue 组件的初始化和更新过程。
vue3 对于 vue2 在性能上的优化(从 compile 和 runtime 两方面)
Vue 3 在性能上相较于 Vue 2 有了显著的优化,主要体现在编译(compile)和运行时(runtime)两个方面:
编译方面的优化:
- 模板编译优化:
- Vue 3 的编译器在编译模板时会进行更多的静态分析,将静态节点和动态节点分开处理,减少运行时的开销。
- 编译器会标记静态节点,使得这些节点在后续的渲染过程中不需要重新计算和更新,从而提升渲染性能。
- Tree-shaking 支持:
- Vue 3 的编译器支持 Tree-shaking,可以在打包时移除未使用的代码,减小打包体积,提高加载速度。
运行时的优化:
- Proxy 代替 Object.defineProperty:
- Vue 3 使用
Proxy对象代替了 Vue 2 中的Object.defineProperty,Proxy可以直接监听对象和数组的变化,并且可以监听动态添加的属性,这解决了 Vue 2 无法检测数组和对象新增属性的问题。 Proxy的使用使得响应式系统的性能有了显著提升,初始化速度更快,内存占用更低。
- 更高效的虚拟 DOM:
- Vue 3 对虚拟 DOM 进行了重写,采用了基于 Block Tree 的优化策略,可以更高效地进行节点的更新和对比。
- 通过静态提升和缓存事件处理函数等手段,减少了不必要的重新渲染和计算,提高了运行时的性能。
- 更小的打包体积:
- Vue 3 的核心库经过优化,移除了不常用的功能,使得打包体积更小,加载速度更快。
- 通过模块化设计,可以按需引入需要的功能,进一步减小打包体积。
- Composition API:
- Vue 3 引入了 Composition API,使得逻辑复用更加灵活,减少了代码冗余,提高了代码的可维护性和性能。
通过以上优化,Vue 3 在编译和运行时的性能上都有了显著提升,使得开发者可以构建更高效、更快速的应用。
vue 的 diff 算法思路,怎么对比节点
Vue 的 diff 算法是基于虚拟 DOM 的,它通过对比新旧虚拟 DOM 树,找出需要更新的部分,从而高效地更新真实 DOM。其核心思路如下:
-
同层比较:Vue 的 diff 算法只比较同一层级的节点,不会跨层级比较。这样可以减少比较次数,提高性能。
-
双端比较:Vue 采用双端比较算法,同时从新旧虚拟 DOM 的两端开始比较,直到两端相遇。具体步骤如下:
- 比较新旧虚拟 DOM 的头部节点,如果相同,则继续比较下一个节点。
- 比较新旧虚拟 DOM 的尾部节点,如果相同,则继续比较前一个节点。
- 如果头部和尾部节点都不相同,则将旧虚拟 DOM 中的节点移动到新虚拟 DOM 中对应的位置。
-
节点复用:如果新旧虚拟 DOM 中的节点相同,则复用旧节点,避免重新创建节点,减少性能开销。
-
标记静态节点:在编译阶段,Vue 会标记静态节点,静态节点不会在后续的更新中重新渲染,从而提高性能。
-
最小化更新范围:Vue 的 diff 算法会尽量减少需要更新的节点范围,只更新发生变化的部分,避免不必要的 DOM 操作。
通过以上思路,Vue 的 diff 算法可以高效地对比新旧虚拟 DOM,找出需要更新的部分,从而实现高性能的 DOM 更新。
vue 的 compile 实现
Vue 的编译过程主要分为三个阶段:解析、优化和代码生成。
- 解析(Parse):
- 将模板字符串解析成抽象语法树(AST),这个过程会进行词法分析和语法分析。
- 词法分析将模板字符串拆分成一个个的 Token,语法分析则根据这些 Token 构建 AST。
- 优化(Optimize):
- 对 AST 进行静态节点标记,找出模板中的静态部分。
- 静态节点在后续的渲染过程中不会改变,因此可以跳过这些节点的对比,提升渲染性能。
- 代码生成(Codegen):
- 将优化后的 AST 转换成渲染函数的字符串表示。
- 渲染函数在运行时会被转换成虚拟 DOM 节点,从而更新真实 DOM。
通过以上三个阶段,Vue 将模板字符串编译成高效的渲染函数,从而实现高性能的视图更新。
// 示例代码
const template = `<div>{{ message }}</div>`
const { render } = Vue.compile(template)
new Vue({
data: {
message: 'Hello, Vue!',
},
render,
}).$mount('#app')
以上代码展示了 Vue 的编译过程,将模板字符串编译成渲染函数,并在 Vue 实例中使用该渲染函数进行视图更新。
vue 如何自定义指令
在 Vue.js 中,可以通过 directive 选项来自定义指令。自定义指令可以在元素绑定到 DOM 时执行特定的行为。以下是自定义指令的基本步骤:
-
定义指令: 使用
Vue.directive全局定义指令,或者在组件的directives选项中局部定义指令。 -
钩子函数: 自定义指令可以包含多个钩子函数,例如
bind、inserted、update、componentUpdated和unbind,这些钩子函数会在指令生命周期的不同阶段被调用。
示例代码:
<template>
<div v-focus>这个元素会在插入到 DOM 时自动获取焦点</div>
</template>
<script>
export default {
directives: {
focus: {
// 指令绑定到元素时调用
bind(el) {
el.focus()
},
// 元素插入到 DOM 时调用
inserted(el) {
el.focus()
},
},
},
}
</script>
在上面的示例中,自定义了一个 v-focus 指令,当元素插入到 DOM 时,该元素会自动获取焦点。
通过自定义指令,可以在 Vue.js 中实现更灵活的 DOM 操作和行为控制。
用过 TypeScript 吗? 有什么优点,为什么用? 具体的场景,使用 TypeScript 进行类型定义。
答:vue 项目多, ts 用的少,也用过,写前端监控 sdk 时,对接口进行类型校验,它像一个文档,每一个接口都有定义,后面再翻看瞬间理解意思。(强类型好处还有很多,但是个人觉得写起来超级麻烦,当然有人很喜欢很爽。)
vue 的 keep-alive 使用场景,以及实现原理
keep-alive 是 Vue 提供的一个内置组件,用于对动态组件进行缓存。它可以在组件切换过程中将状态保留在内存中,避免重复渲染,提高性能。
使用场景:
- 需要在组件切换时保留组件的状态或避免重新渲染的场景。
- 例如:在多标签页切换、表单填写过程中切换页面等场景中使用
keep-alive可以提升用户体验。
实现原理:
keep-alive通过缓存已经创建的组件实例,并在组件切换时复用这些实例。- 当组件被包裹在
keep-alive中时,第一次渲染时会创建组件实例并缓存起来,后续切换到该组件时会直接从缓存中获取实例,而不是重新创建。 keep-alive还提供了include和exclude属性,可以根据条件决定哪些组件需要被缓存,哪些不需要。
<template>
<div>
<keep-alive>
<component :is="currentView"></component>
</keep-alive>
</div>
</template>
<script>
export default {
data() {
return {
currentView: 'MyComponent',
}
},
components: {
MyComponent: () => import('./MyComponent.vue'),
},
}
</script>