1、CSS选择器样式优先级 2、CSS实现三列布局(左右固定宽度,中间自适应) 在 CSS 中,实现一个三列布局,其中左右两列宽度固定,中间列自适应,通常使用 或者 布局可以轻松完成。这里分别给出两种方法:
方法一:Flexbox布局
HTML 示例:
方法二:Grid布局
HTML 示例:
3、如果要做优化,CSS提高性能的方法有哪些? 内联首屏关键CSS 异步加载CSS 资源压缩 合理使用选择器 减少使用昂贵的属性 不要使用@import
1、防抖和节流,应用场景 防抖和节流都是防止某一时间频繁触发,但是原理却不一样。 防抖是将多次执行变为只执行一次,节流是将多次执行变为每隔一段时间执行。 防抖(debounce): search搜索联想,用户在不断输入值时,用防抖来节约请求资源。 window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次 节流(throttle): 鼠标不断点击触发,mousedown(单位时间内只触发一次) 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断 2、什么是闭包 「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。 3、继承有哪些方法 原型链继承 借用构造函数继承(伪造对象、经典继承) 实例继承(原型式继承) 组合式继承 寄生组合继承 es6继承 extends 4、什么是深/浅拷贝,有哪些实现方式 基本数据类型:string、number、boolean、undefined、null、Symbol(ES6,符号类型) 引用数据类型:object、array、function JS数据类型分为基本数据类型和引用数据类型,基本数据类型保存的是值,引用类型保存的是引用地址(this指针)。浅拷贝共用一个引用地址,深拷贝会创建新的内存地址。 JSON字符串转换为JSON对象:
将JSON对象转化为JSON字符串:
:对象的合并 (第一级属性深拷贝,第一级以下的级别属性浅拷贝。) ES6中的 ,第一个参数必须是个空对象。 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
1.splice改变原数组,slice不改变原数组。2.splice除了可以删除之外,还可以插入。3.splice可传入3个参数,slice接受2个参数。
Promise.all()可以将多个实例组装个成一个新实例,成功的时候返回一个成功的数组;失败的时候则返回最先被reject失败状态的值。 适用场景:比如当一个页面需要在很多个模块的数据都返回回来时才正常显示,否则loading。 promise.all中的子任务是并发执行的,适用于前后没有依赖关系的。Promise.race()意为赛跑的意思,也就是数组中的任务哪个获取的块,就返回哪个,不管结果本身是成功还是失败。一般用于和定时器绑定,比如将一个请求和三秒的定时器包装成Promise实例,加入到Promise队列中,请求三秒中还没有回应时,给用户一些提示或相应的操作。
1.宏任务:当前调用栈中执行的代码成为宏任务。(主代码快,定时器等等)。 2.微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。(promise.then,proness.nextTick等等)。 3. 宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。 微任务:process.nextTick、MutationObserver、Promise.then catch finally 宏任务:I/O、setTimeout、setInterval、setImmediate、requestAnimationframe
适用父子组件通信 适用父子组件通信 适用于隔代组件通信 适用于父子、隔代、兄弟组件通信 slot插槽方式
v-show是css切换,v-if是完整的销毁和重新创建,如果频繁切换时用v-show,运行时较少改变用v-if
做一个唯一标识, Diff 算法就可以正确的识别此节点。作用主要是为了高效的更新虚拟 DOM。
computed: 支持缓存,数据变,直接会触发相应的操作; 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值; 当一个属性发生变化时,需要执行对应的操作;即一个属性受多个属性影响,多对一或者一对一的关系; 监听的是这个属性自身的变化,且不会操作缓存 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数, 是一个计算属性,类似于过滤器,对绑定到view的数据进行处理 当一个属性受多个属性影响的时候就需要用到computed 最典型的例子: 购物车商品结算的时候 watch: 1.是观察的动作, 2.应用:监听props,$emit或本组件的值执行异步操作 3.无缓存性,页面重新渲染时值不变化也会执行 watch是一个观察的动作 当一条数据影响多条数据的时候就需要用watch 例子:搜索数据
1.全局导航钩子:router.beforeEach(to,from,next)作用:跳转前进行判断拦截、组件内的钩子、单独路由独享组件 2、路由独享钩子可以在路由配置上直接定义 beforeEnter 3、组件内的导航钩子有三种: beforeRouteEnter 在进入当前组件对应的路由前调用 beforeRouteUpdate 在当前路由改变,但是该组件被复用时调用 beforeRouteLeave 在离开当前组件对应的路由前调用=
Vue实例从创建到销毁的过程,就是生命周期。 也就是:开始创建->初始化数据->编译模板->挂载dom->数据更新重新渲染虚拟 dom->最后销毁。这一系列的过程就是vue的生命周期。所以在mounted阶段真实的DOM就已经存在了。 beforeCreate:vue实例的挂载元素el和数据对象data都还没有进行初始化,还是一个 undefined状态 created: 此时vue实例的数据对象data已经有了,可以访问里面的数据和方法, el还没有,也没有挂载dom beforeMount: 在这里vue实例的元素el和数据对象都有了,只不过在挂载之前还是虚拟的dom节点 mounted: vue实例已经挂在到真实的dom上,可以通过对 dom操作来获取dom节点 beforeUpdate: 响应式数据更新时调用,发生在虚拟dom打补丁之前,适合在更新之前访问现有的 dom,比如手动移除已添加的事件监听器 updated: 虚拟dom重新渲染和打补丁之后调用,组成新的 dom已经更新,避免在这个钩子函数中操作数据,防止死循环。 activated: 当组件keep-alive激活时被调用 deactivated:当组件keep-alive停用时被调用 beforeDestroy: vue实例在销毁前调用,在这里还可以使用,通过this也能访问到实例,可以在这里对一些不用的定时器进行清除,解绑事件。 destroyed:vue实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁。
vuex是一个专门为vue.js开发的状态管理模式,每一个vuex应用核心就是store(仓库)。store基本上就是一个容器,它包含着你的应用中大部分的state(状态) vuex的状态存储是响应式的,当 vue组件中store中读取状态时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新。 改变store中的状态的唯一途径就是显示 commit(提交)mutation,这样使得我们可以方便地跟踪每一个状态的变化。 State: 定义了应用状态的数据结构,可以在这里设置默认的初始状态 Getter: 允许组件从Stroe中获取数据, mapGetters辅助函数仅仅是将store中的getter映射到计算属性。 Mutation: 唯一更改store中状态的方法,且必须是同步函数。 Action: 用于提交muatation, 而不是直接变更状态,可以包含任意异步操作。 Module: modules,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理;如果所有的状态或者方法都写在一个store里面,将会变得非常臃肿,难以维护。
12、vuex中state存储的数据如果页面刷新此时数据还会有吗?(刷新之后销毁了)
v-bind用来绑定数据和属性以及表达式 v-model使用在表单中,实现双向数据绑定的。
v-text/v-html/v-for/v-show/v-if/v-else/v-cloak/v-bind/v-on/v-model/v-slot…
前两个可以自动执行,bind不会自动执行,需要手动调用 call、bind与apply区别:前两个都有无数个参数,apply只有两个参数,而且第二个参数为数组
1.hash模式 特点:在url地址上有#号 实现的原理:原生的hasChange事件来实现,来监听hash值的变化 window.onhaschange=function(){} 刷新页面的时候:不会去发送请求,页面不会有任何问题,不需要后端来配合
2.history模式 特点:在url地址上没有#号,比较与hash模式看起来好看一些 实现的原理:利用的是history的api 来实现的 popState() 来实现的 刷新页面的时候:会去发送请求然后会导致页面出现找不到的情况,需要后端来配合解决
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 数据劫持,来劫持各个属性的setter,getter,在数据更新时发布消息给订阅者,触发相应监听回调。
当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty() 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),
最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
怪异盒模型的宽度变小 标准盒大小计算公式:width(content) + padding + border + margin 怪异盒大小的计算公式:width(content + padding + border) + margin
默认插槽,具名插槽,作用域插槽 vue中的插槽,指的是子组件中提供给父组件使用的一个占位符; 用标签表示,父组件可以在这个占位符中填充任何模板代码,比如HTML、组件等,填充的内容会替换掉子组件的标签(替换占位符)。
自定义指令通常包含两个部分:前缀和指令名称,它们分别用于标记指令的使用和指令本身的定义。
-
v-指令前缀:这是 Vue 的标志,告诉 Vue 这是一个自定义指令,Vue 将会解析并处理这个前缀。
-
指令名称:是你为这个特殊行为起的名字,比如 。
-
指令实现:通常分为两个部分:
- 指令表达式():这里定义了当指令被激活时关联的计算属性或方法。
- 指令选项(如 ):可以提供额外配置,例如是否双向绑定数据、触发哪个方法等。 在Vue.js中,声明一个自定义指令可以帮助你在模板中添加更丰富的功能,比如处理元素的交互或修改数据。以下是在Vue中声明一个自定义指令的基本步骤:
1. 定义指令:
- 使用方法创建一个指令对象。这个对象包含两个属性:和(可选),分别表示指令被绑定到元素上和元素的数据变化时的钩子。
2. 指令绑定:
- 在模板中使用自定义指令,使用v-前缀加上自定义指令名称,后跟属性名(通常是表达式)。
3. 示例中的参数:
- :被指令作用的DOM元素。
- :一个对象,包含了指令相关的配置信息,如、等。
- :虚拟节点,提供了更多关于组件的信息。
使用字符串的 split() 方法可以根据指定的分隔符把字符串切分为数组。 如果使用数组的 join() 方法,可以把数组元素连接为字符串。
把对象直接转换成字符串
当js试图得到一个对象的属性时,会先去这个对象的本身去寻找,如果这个对象本身没有找到这个属性,那么js就会去它构造函数的’prototype’属性中去寻找,也就是去’proto‘中寻找,如果’prototype’属性本身中依旧没有找到,’prototype’中依旧有一个‘proto’。
原型可以解决什么问题: 对象共享属性和方法 谁有原型: 函数拥有:prototype 对象拥有:proto 对象查找属性或者方法的顺序: 先在对象本身查找–>构造函数中查找–>对象的原型中查找–>构造函数的原型中查找–>当前原型中查找 原型链的最顶端是null
闭包就是指有权访问另一个函数作用域中的变量的函数 MDN 上面这么说:闭包是一种特殊的对象。 闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域。闭包的注意事项 通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。 我们首先知道闭包有3个特性: ①函数嵌套函数 ②函数内部可以引用函数外部的参数和变量 ③参数和变量不会被垃圾回收机制回收 优点: ①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突 ②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存) ③匿名自执行函数可以减少内存消耗 闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。 如果不是因为某些特殊任务而需要闭包,在没有必要的情况下,在其它函数中创建函数是不明智的,因为闭包对脚本性能具有负面影响,包括处理速度和内存消耗。
1、rem的大小是根据html根目录下的字体大小进行计算的。 2、当我们改变根目录下的字体大小的时候,下面字体都改变。 3、rem不仅可以设置字体的大小,也可以设置元素宽、高等属性。
浏览器发起请求-> 解析域名得到ip进行TCP连接 ->浏览器发送HTTP请求和头信息发送->服务器对浏览器进行应答,响应头信息和浏览器所需的内容-> 关闭TCP连接或保持-> 浏览器得到数据数据进行操作。
当一个请求 url 的协议、域名、端口三者之间任意一个与当前页面 url 不同即为跨域 出于浏览器的同源策略限制。 同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。 1.JSONP原理 利用script元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 数据。 但是JSONP请求一定需要对方的服务器做支持才可以。 JSONP优点是兼容性好,可用于解决主流浏览器的跨域数据访问的问题。 缺点是仅支持get方法具有局限性。 2.CORS原理 实现CORS通信的关键是服务器,需要在服务器端做一些小小的改造。 只要服务器实现了CORS接口,就可以跨源通信。 在响应头上添加Access-Control-Allow-Origin属性,指定同源策略的地址。同源策略默认地址是网页的本身。只要浏览器检测到响应头带上了CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。 3.Nginx 浏览器在访问受限时,可通过不受限的代理服务器访问目标站点。 proxy代理是前端用的最多的解决跨域的方法。 即配置一台和浏览器相同端口的服务器,浏览器访问代理服务器,代理服务器向目标服务器发送请求,由于服务器之间不存在跨域问题,代理服务器就可以拿到请求数据,而后因为浏览器和代理服务器端口号一致,不存在跨域问题,因此浏览器不会拦截从代理服务器收到的数据,顺利拿到请求数据。 例如:浏览器端口号8080,目标服务器端口号5000,在vue中配置代理服务器来访问目标服务器
keep-alive 是 vue 中的内置组件,能够在组件切换过程中将状态保留在内存中,防止重复的渲染 DOM; keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们; 设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activated 和 deactivated )
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。 使用:
什么时候需要用的Vue.nextTick()? 1、Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。 2.vue改变dom元素结构后使用vue.$nextTick()方法来实现dom数据更新后延迟执行后续代码
1、字体大小是根据父元素字体大小设置的。 四、综合 1、前端工程化理解(模块化、组件化、规范化、自动化) JS的模块化、css的模块化、资源的模块化 从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元 HTML规范、CSS规范、JS规范、图片规范、命名规范 图标合并、持续集成、自动化构建、自动化部署、自动化测试
Javascript的事件循环(Event Loop)是其异步执行的核心机制之一,用于处理非阻塞I/O操作和回调函数。简单来说,它是浏览器或Node.js环境中的一个重要调度器,负责监听并管理任务队列。
-
任务队列:分为两种类型:宏任务(macro-task)和微任务(micro-task)。宏任务包括setTimeout、setInterval、DOM操作、网络请求等;微任务如Promise.resolve、MutationObserver等。
-
执行栈:当前正在运行的同步代码所构成的栈。
-
事件循环过程:
- 执行栈中的同步代码执行完毕后,会检查是否有微任务,如果有则先执行微任务直到队列为空。
- 接着,执行下一个宏任务。这个过程中如果遇到新的微任务,会插入到微任务队列中,并继续执行当前宏任务。
- 当宏任务完成,再次检查微任务队列,如有微任务,则执行它们,如此反复。
-
轮询检测:事件循环不是被动等待,而是通过定期的轮询检查是否有可执行的任务。
了解了事件循环机制有助于优化异步代码,避免阻塞UI线程,提高应用性能。相关问题: