一篇由简到难的 Vue 面试题+详解答案,2024年最新被面试官怼了还有戏吗

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Web前端全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

// src/obserber/array.js

// 先保留数组原型

const arrayProto = Array.prototype;

// 然后将arrayMethods继承自数组原型

// 这里是面向切片编程思想(AOP)–不破坏封装的前提下,动态的扩展功能

export const arrayMethods = Object.create(arrayProto);

let methodsToPatch = [

“push”,

“pop”,

“shift”,

“unshift”,

“splice”,

“reverse”,

“sort”,

];

methodsToPatch.forEach((method) => {

arrayMethods[method] = function (…args) {

//   这里保留原型方法的执行结果

const result = arrayProto[method].apply(this, args);

// 这句话是关键

// this代表的就是数据本身 比如数据是{a:[1,2,3]} 那么我们使用a.push(4)  this就是a  ob就是a.ob 这个属性就是上段代码增加的 代表的是该数据已经被响应式观察过了指向Observer实例

const ob = this.ob;

// 这里的标志就是代表数组有新增操作

let inserted;

switch (method) {

case “push”:

case “unshift”:

inserted = args;

break;

case “splice”:

inserted = args.slice(2);

default:

break;

}

// 如果有新增的元素 inserted是一个数组 调用Observer实例的observeArray对数组每一项进行观测

if (inserted) ob.observeArray(inserted);

// 之后咱们还可以在这里检测到数组改变了之后从而触发视图更新的操作–后续源码会揭晓

return result;

};

});

复制代码

数组的观测原理详解 传送门[4]

12 vue3.0 用过吗 了解多少
  • 响应式原理的改变 Vue3.x 使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty

  • 组件选项声明方式 Vue3.x 使用 Composition API setup 是 Vue3.x 新增的一个选项, 他是组件内使用 Composition API 的入口。

  • 模板语法变化 slot 具名插槽语法 自定义指令 v-model 升级

  • 其它方面的更改 Suspense 支持 Fragment(多个根节点)和 Protal(在 dom 其他部分渲染组建内容)组件,针对一些特殊的场景做了处理。基于 treeshaking 优化,提供了更多的内置功能。

Vue3.0 新特性以及使用经验总结 传送门[5]

13 Vue3.0 和 2.0 的响应式原理区别

Vue3.x 改用 Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达 13 种拦截方法。

相关代码如下

import { mutableHandlers } from “./baseHandlers”; // 代理相关逻辑

import { isObject } from “./util”; // 工具方法

export function reactive(target) {

// 根据不同参数创建不同响应式对象

return createReactiveObject(target, mutableHandlers);

}

function createReactiveObject(target, baseHandler) {

if (!isObject(target)) {

return target;

}

const observed = new Proxy(target, baseHandler);

return observed;

}

const get = createGetter();

const set = createSetter();

function createGetter() {

return function get(target, key, receiver) {

// 对获取的值进行放射

const res = Reflect.get(target, key, receiver);

console.log(“属性获取”, key);

if (isObject(res)) {

// 如果获取的值是对象类型,则返回当前对象的代理对象

return reactive(res);

}

return res;

};

}

function createSetter() {

return function set(target, key, value, receiver) {

const oldValue = target[key];

const hadKey = hasOwn(target, key);

const result = Reflect.set(target, key, value, receiver);

if (!hadKey) {

console.log(“属性新增”, key, value);

} else if (hasChanged(value, oldValue)) {

console.log(“属性值被修改”, key, value);

}

return result;

};

}

export const mutableHandlers = {

get, // 当获取属性时调用此方法

set, // 当修改属性时调用此方法

};

复制代码

14 Vue 的父子组件生命周期钩子函数执行顺序
  • 加载渲染过程

父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount->子 mounted->父 mounted

  • 子组件更新过程

父 beforeUpdate->子 beforeUpdate->子 updated->父 updated

  • 父组件更新过程

父 beforeUpdate->父 updated

  • 销毁过程

父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed

15 虚拟 DOM 是什么 有什么优缺点

由于在浏览器中操作 DOM 是很昂贵的。频繁的操作 DOM,会产生一定的性能问题。这就是虚拟 Dom 的产生原因。Vue2 的 Virtual DOM 借鉴了开源库 snabbdom 的实现。Virtual DOM 本质就是用一个原生的 JS 对象去描述一个 DOM 节点,是对真实 DOM 的一层抽象。

「优点:」

  1. 保证性能下限:框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;

  2. 无需手动操作 DOM:我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;

  3. 跨平台:虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。

「缺点:」

  1. 无法进行极致优化:虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。

  2. 首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,会比 innerHTML 插入慢。

16 v-model 原理

v-model 只是语法糖而已

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;

  • checkbox 和 radio 使用 checked property 和 change 事件;

  • select 字段将 value 作为 prop 并将 change 作为事件。

注意:对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。

在普通标签上

  //这一行等于下一行

复制代码

在组件上

Vue.component(‘currency-input’, {

template: `

<input

ref=“input”

:value=“value”

@input=“ e m i t ( ′ i n p u t ′ ,   emit('input',  emit(input, event.target.value)”

`,

props: [‘value’],

})

复制代码

17 v-for 为什么要加 key

如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速

「更准确」:因为带 key 就不是就地复用了,在 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。

「更快速」:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快

相关代码如下

// 判断两个vnode的标签和key是否相同 如果相同 就可以认为是同一节点就地复用

function isSameVnode(oldVnode, newVnode) {

return oldVnode.tag === newVnode.tag && oldVnode.key === newVnode.key;

}

// 根据key来创建老的儿子的index映射表  类似 {‘a’:0,‘b’:1} 代表key为’a’的节点在第一个位置 key为’b’的节点在第二个位置

function makeIndexByKey(children) {

let map = {};

children.forEach((item, index) => {

map[item.key] = index;

});

return map;

}

// 生成的映射表

let map = makeIndexByKey(oldCh);

复制代码

diff 算法详解 传送门[6]

18 Vue 事件绑定原理

原生事件绑定是通过 addEventListener 绑定给真实元素的,组件事件绑定是通过 Vue 自定义的 $on 实现的。如果要在组件上使用原生事件,需要加.native 修饰符,这样就相当于在父组件中把子组件当做普通 html 标签,然后加上原生事件。

、 emit 是基于发布订阅模式的,维护一个事件中心,on 的时候将事件按名称存在事件中心里,称之为订阅者,然后 emit 将对应的事件进行发布,去执行事件中心里的对应的监听器

手写发布订阅原理 传送门[7]

19 vue-router 路由钩子函数是什么 执行顺序是什么

路由钩子的执行流程, 钩子函数种类有:全局守卫、路由守卫、组件守卫

「完整的导航解析流程:」

  1. 导航被触发。

  2. 在失活的组件里调用 beforeRouteLeave 守卫。

  3. 调用全局的 beforeEach 守卫。

  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

  5. 在路由配置里调用 beforeEnter。

  6. 解析异步路由组件。

  7. 在被激活的组件里调用 beforeRouteEnter。

  8. 调用全局的 beforeResolve 守卫 (2.5+)。

  9. 导航被确认。

  10. 调用全局的 afterEach 钩子。

  11. 触发 DOM 更新。

  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

20 vue-router 动态路由是什么 有什么问题

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const User = {

template: “

User
”,

};

const router = new VueRouter({

routes: [

// 动态路径参数 以冒号开头

{ path: “/user/:id”, component: User },

],

});

复制代码

问题:vue-router 组件复用导致路由参数失效怎么办?

解决方法:

1.通过 watch 监听路由参数再发请求

watch: { //通过watch来监听路由变化

“$route”: function(){

this.getData(this.$route.params.xxx);

}

}

复制代码

2.用 :key 来阻止“复用”

复制代码

21 谈一下对 vuex 的个人理解

vuex 是专门为 vue 提供的全局状态管理系统,用于多个组件中数据共享、数据缓存等。(无法持久化、内部核心原理是通过创造一个全局实例 new Vue)

主要包括以下几个模块:

  • State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。

  • Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。

  • Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。

  • Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。

  • Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

22 Vuex 页面刷新数据丢失怎么解决

需要做 vuex 数据持久化 一般使用本地存储的方案来保存数据 可以自己设计存储方案 也可以使用第三方插件

推荐使用 vuex-persist 插件,它就是为 Vuex 持久化存储而生的一个插件。不需要你手动存取 storage ,而是直接将状态保存至 cookie 或者 localStorage 中

23 Vuex 为什么要分模块并且加命名空间

「模块」:由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。

「命名空间」:默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

24 使用过 Vue SSR 吗?说说 SSR

SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。

「优点:」

SSR 有着更好的 SEO、并且首屏加载速度更快

「缺点:」 开发条件会受到限制,服务器端渲染只支持 beforeCreate 和 created 两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于 Node.js 的运行环境。

服务器会有更大的负载需求

25 vue 中使用了哪些设计模式

1.工厂模式 - 传入参数即可创建实例

虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode

2.单例模式 - 整个程序有且仅有一个实例

vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉

3.发布-订阅模式 (vue 事件机制)

4.观察者模式 (响应式数据原理)

5.装饰模式: (@装饰器的用法)

6.策略模式 策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略

…其他模式欢迎补充

26 你都做过哪些 Vue 的性能优化

这里只列举针对 Vue 的性能优化 整个项目的性能优化是一个大工程 可以另写一篇性能优化的文章 哈哈

  • 对象层级不要过深,否则性能就会差

  • 不需要响应式的数据不要放到 data 中(可以用 Object.freeze() 冻结数据)

  • v-if 和 v-show 区分使用场景

  • computed 和 watch 区分使用场景

  • v-for 遍历必须加 key,key 最好是 id 值,且避免同时使用 v-if

  • 大数据列表和表格性能优化-虚拟列表/虚拟表格

  • 防止内部泄漏,组件销毁后把全局变量和事件销毁

  • 图片懒加载

  • 路由懒加载

  • 第三方插件的按需引入

  • 适当采用 keep-alive 缓存组件

  • 防抖、节流运用

  • 服务端渲染 SSR or 预渲染


困难

27 Vue.mixin 的使用场景和原理

在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立,可以通过 Vue 的 mixin 功能抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用 mergeOptions 方法进行合并,采用策略模式针对不同的属性进行合并。当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

相关代码如下

export default function initMixin(Vue){

Vue.mixin = function (mixin) {

//   合并对象

this.options=mergeOptions(this.options,mixin)

};

}

};

// src/util/index.js

// 定义生命周期

export const LIFECYCLE_HOOKS = [

“beforeCreate”,

“created”,

“beforeMount”,

“mounted”,

“beforeUpdate”,

“updated”,

“beforeDestroy”,

“destroyed”,

];

// 合并策略

const strats = {};

// mixin核心方法

export function mergeOptions(parent, child) {

const options = {};

// 遍历父亲

for (let k in parent) {

mergeFiled(k);

}

// 父亲没有 儿子有

for (let k in child) {

if (!parent.hasOwnProperty(k)) {

mergeFiled(k);

}

}

//真正合并字段方法

function mergeFiled(k) {

if (strats[k]) {

options[k] = stratsk;

} else {

// 默认策略

options[k] = child[k] ? child[k] : parent[k];

}

}

return options;

}

复制代码

Vue.mixin 原理详解 传送门[8]

28 nextTick 使用场景和原理

nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法

相关代码如下

let callbacks = [];

let pending = false;

function flushCallbacks() {

pending = false; //把标志还原为false

// 依次执行回调

for (let i = 0; i < callbacks.length; i++) {

callbacksi;

}

}

let timerFunc; //定义异步方法  采用优雅降级

if (typeof Promise !== “undefined”) {

// 如果支持promise

const p = Promise.resolve();

timerFunc = () => {

p.then(flushCallbacks);

};

} else if (typeof MutationObserver !== “undefined”) {

// MutationObserver 主要是监听dom变化 也是一个异步方法

let counter = 1;

const observer = new MutationObserver(flushCallbacks);

const textNode = document.createTextNode(String(counter));

observer.observe(textNode, {

characterData: true,

});

timerFunc = () => {

counter = (counter + 1) % 2;

textNode.data = String(counter);

};

} else if (typeof setImmediate !== “undefined”) {

// 如果前面都不支持 判断setImmediate

timerFunc = () => {

setImmediate(flushCallbacks);

};

} else {

// 最后降级采用setTimeout

timerFunc = () => {

setTimeout(flushCallbacks, 0);

};

}

export function nextTick(cb) {

// 除了渲染watcher  还有用户自己手动调用的nextTick 一起被收集到数组

callbacks.push(cb);

if (!pending) {

// 如果多次调用nextTick  只会执行一次异步 等异步队列清空之后再把标志变为false

pending = true;

timerFunc();

}

}

复制代码

nextTick 原理详解 传送门[9]

29 keep-alive 使用场景和原理

keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

  • 常用的两个属性 include/exclude,允许组件有条件的进行缓存。

  • 两个生命周期 activated/deactivated,用来得知当前组件是否处于活跃状态。

  • keep-alive 的中还运用了 LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰。

相关代码如下

export default {

name: “keep-alive”,

abstract: true, //抽象组件

props: {

include: patternTypes, //要缓存的组件

exclude: patternTypes, //要排除的组件

max: [String, Number], //最大缓存数

},

created() {

this.cache = Object.create(null); //缓存对象  {a:vNode,b:vNode}

this.keys = []; //缓存组件的key集合 [a,b]

},

destroyed() {

for (const key in this.cache) {

pruneCacheEntry(this.cache, key, this.keys);

}

},

mounted() {

//动态监听include  exclude

this.$watch(“include”, (val) => {

pruneCache(this, (name) => matches(val, name));

});

this.$watch(“exclude”, (val) => {

pruneCache(this, (name) => !matches(val, name));

});

},

render() {

const slot = this.$slots.default; //获取包裹的插槽默认值

const vnode: VNode = getFirstComponentChild(slot); //获取第一个子组件

const componentOptions: ?VNodeComponentOptions =

vnode && vnode.componentOptions;

if (componentOptions) {

// check pattern

const name: ?string = getComponentName(componentOptions);

const { include, exclude } = this;

// 不走缓存

if (

// not included  不包含

(include && (!name || !matches(include, name))) ||

// excluded  排除里面

(exclude && name && matches(exclude, name))

) {

//返回虚拟节点

return vnode;

}

const { cache, keys } = this;

const key: ?string =

vnode.key == null

? // same constructor may get registered as different local components

// so cid alone is not enough (#3269)

componentOptions.Ctor.cid +

(componentOptions.tag ? ::${componentOptions.tag} : “”)

: vnode.key;

if (cache[key]) {

//通过key 找到缓存 获取实例

vnode.componentInstance = cache[key].componentInstance;

// make current key freshest

remove(keys, key); //通过LRU算法把数组里面的key删掉

keys.push(key); //把它放在数组末尾

} else {

cache[key] = vnode; //没找到就换存下来

keys.push(key); //把它放在数组末尾

// prune oldest entry  //如果超过最大值就把数组第0项删掉

if (this.max && keys.length > parseInt(this.max)) {

pruneCacheEntry(cache, keys[0], keys, this._vnode);

}

}

vnode.data.keepAlive = true; //标记虚拟节点已经被缓存

}

// 返回虚拟节点

return vnode || (slot && slot[0]);

},

};

复制代码

扩展补充:LRU 算法是什么?

lrusuanfa.png

LRU 的核心思想是如果数据最近被访问过,那么将来被访问的几率也更高,所以我们将命中缓存的组件 key 重新插入到 this.keys 的尾部,这样一来,this.keys 中越往头部的数据即将来被访问几率越低,所以当缓存数量达到最大值时,我们就删除将来被访问几率最低的数据,即 this.keys 中第一个缓存的组件。

30 Vue.set 方法原理

了解 Vue 响应式原理的同学都知道在两种情况下修改数据 Vue 是不会触发视图更新的

1.在实例创建之后添加新的属性到实例上(给响应式对象新增属性)

2.直接更改数组下标来修改数组的值

Vue.set 或者说是 $set 原理如下

因为响应式数据 我们给对象和数组本身都增加了__ob__属性,代表的是 Observer 实例。当给对象新增不存在的属性 首先会把新的属性进行响应式跟踪 然后会触发对象__ob__的 dep 收集到的 watcher 去更新,当修改数组索引时我们调用数组本身的 splice 方法去更新数组

相关代码如下

export function set(target: Array | Object, key: any, val: any): any {

// 如果是数组 调用我们重写的splice方法 (这样可以更新视图)

if (Array.isArray(target) && isValidArrayIndex(key)) {

target.length = Math.max(target.length, key);

target.splice(key, 1, val);

return val;

}

// 如果是对象本身的属性,则直接添加即可

if (key in target && !(key in Object.prototype)) {

target[key] = val;

return val;

}

const ob = (target: any).ob;

// 如果不是响应式的也不需要将其定义成响应式属性

if (!ob) {

target[key] = val;

return val;

}

// 将属性定义成响应式的

defineReactive(ob.value, key, val);

// 通知视图更新

ob.dep.notify();

return val;

}

复制代码

响应式数据原理详解 传送门[10]

31 Vue.extend 作用和原理

官方解释:Vue.extend 使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

其实就是一个子类构造器 是 Vue 组件的核心 api 实现思路就是使用原型继承的方法返回了 Vue 的子类 并且利用 mergeOptions 把传入组件的 options 和父类的 options 进行了合并

相关代码如下

export default function initExtend(Vue) {

let cid = 0; //组件的唯一标识

// 创建子类继承Vue父类 便于属性扩展

Vue.extend = function (extendOptions) {

// 创建子类的构造函数 并且调用初始化方法

const Sub = function VueComponent(options) {

this._init(options); //调用Vue初始化方法

};

Sub.cid = cid++;

Sub.prototype = Object.create(this.prototype); // 子类原型指向父类

Sub.prototype.constructor = Sub; //constructor指向自己

Sub.options = mergeOptions(this.options, extendOptions); //合并自己的options和父类的options

return Sub;

};

}

复制代码

Vue 组件原理详解 传送门[11]

32 写过自定义指令吗 原理是什么

指令本质上是装饰器,是 vue 对 HTML 元素的扩展,给 HTML 元素增加自定义功能。vue 编译 DOM 时,会找到指令对象,执行指令的相关方法。

自定义指令有五个生命周期(也叫钩子函数),分别是 bind、inserted、update、componentUpdated、unbind

1. bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  1. inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  2. update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。

  3. componentUpdated:被绑定元素所在模板完成一次更新周期时调用。

  4. unbind:只调用一次,指令与元素解绑时调用。

复制代码

「原理」

1.在生成 ast 语法树时,遇到指令会给当前元素添加 directives 属性

2.通过 genDirectives 生成指令代码

3.在 patch 前将指令的钩子提取到 cbs 中,在 patch 过程中调用对应的钩子

4.当执行指令对应钩子函数时,调用对应指令定义的方法

33 Vue 修饰符有哪些

「事件修饰符」

  • .stop 阻止事件继续传播

  • .prevent 阻止标签默认行为

  • .capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理

  • .self 只当在 event.target 是当前元素自身时触发处理函数

  • .once 事件将只会触发一次

  • .passive 告诉浏览器你不想阻止事件的默认行为

对象篇

模块化编程-自研模块加载器

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  1. update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。

  2. componentUpdated:被绑定元素所在模板完成一次更新周期时调用。

  3. unbind:只调用一次,指令与元素解绑时调用。

复制代码

「原理」

1.在生成 ast 语法树时,遇到指令会给当前元素添加 directives 属性

2.通过 genDirectives 生成指令代码

3.在 patch 前将指令的钩子提取到 cbs 中,在 patch 过程中调用对应的钩子

4.当执行指令对应钩子函数时,调用对应指令定义的方法

33 Vue 修饰符有哪些

「事件修饰符」

  • .stop 阻止事件继续传播

  • .prevent 阻止标签默认行为

  • .capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理

  • .self 只当在 event.target 是当前元素自身时触发处理函数

  • .once 事件将只会触发一次

  • .passive 告诉浏览器你不想阻止事件的默认行为

对象篇

模块化编程-自研模块加载器

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-ld9D2hzl-1713055700849)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值