前言
自己总结的关于vue2/vue3,react的高频面试内容记录,其中不乏自己被面试过问到的,其中包括部分js,ts,css,promise,axios,webpack,redux,浏览器等内容
文章目录
- 前言
- 一、关于vue2和vue3
- 1.vue2和vue3的区别
- 2.vue2中data为什么是一个函数
- 3.vue3中依然可以使用data吗?setup和data的执行顺序是如何的?如果setup与data变量重名,执行谁?
- 4.vue框架下的watch和computed的区别
- 5.vue2中组件通信方式
- 6.vue中的key作用与原理,为什么不建议用index做为key?为什么不建议用随机数作为 key?
- 7.vue中的mixin是什么?与vuex有何区别?
- 8.vue中组件和mixin中的属性使用区别
- 9.vue中组件和mixin执行顺序
- 10.你使用过vuex吗?什么是vuex,它包含哪些部分?
- 11. vue3中的reactive和ref的区别,为什么reactive不能定义基本数据类型?
- 12.vue父组件套子组件之后父子组件的生命周期的运行顺序
- 13.解释vue3的api。如watchEffect,toValue
- 二、关于Axios
- 三、关于HTTP
- 四、关于web
- 五、关于Promise
- 六、关于CSS
- 六、JS(重中之重!)
- 七、TS
- 八、React
- 九、uniApp
- 十、移动端和小程序
一、关于vue2和vue3
1.vue2和vue3的区别
-
双向绑定原理的不同:
vue2是使用的es5的api,Object.defineProperty劫持数据,然后再结合发布订阅者模式进行数据绑定的;
vue3是使用的es6的api,proxy进行双向绑定的,这样相比vue2有几个优势:
1)defineProperty只能监听某个属性,不能全对象监听
2)可以省去for in,闭包等内容来提高效率(直接绑定整个对象即可)
3)可以监听数组,不用在对数组做特异性操作,vue3可以直接监听数组数据的变化 -
vue2不支持碎片(Fragment),而vue3支持碎片,也就是vue3可以拥有有多个根结点
-
API类型不同。
vue2:选项式API,选项型api在代码里分割了不同的属性:data,computed,methods等;而vue3
vue3:合成式API,新的合成型api能让我们使用方法来分割(雷士于react,需要那种属性就引入) -
定义数据变量和方法不同。
vue2中定义数据变量,需要在data()的return{}对象进行定义,方法需要在methods:{}中编写;
而vue3则直接将两项进行组合,使用了一种新的方法setup(){},可以把定义数据变量和操作方法都写入其中,当然vue3支持setup放入script标签中,这样可以更加简洁。 -
生命周期钩子函数不同
vue2中的生命周期:
beforeCreate 组件创建之前
created 组件创建之后
beforeMount 组价挂载到页面之前执行
mounted 组件挂载到页面之后执行
beforeUpdate 组件更新之前
updated 组件更新之后vue3中的生命周期:
setup 开始创建组件
onBeforeMount 组价挂载到页面之前执行
onMounted 组件挂载到页面之后执行
onBeforeUpdate 组件更新之前
onUpdated 组件更新之后 -
父子传参不同
vue2:父传子,用props,子传父用事件 Emitting Events。在vue2中,会调用this$emit然后传入事件名和对象。vue3:父传子,用props,子传父用事件 Emitting Events。在vue3中的setup()中的第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。
-
指令与插槽不同
vue2:vue2中使用slot可以直接使用slot;v-for与v-if在vue2中优先级高的是v-for指令,而且不建议一起使用。vue3:vue3中必须使用v-slot的形式;vue3中v-for与v-if,只会把当前v-if当做v-for中的一个判断语句,不会相互冲突;vue3中移除keyCode作为v-on的修饰符,当然也不支持config.keyCodes;vue3中移除v-on.native修饰符;vue3中移除过滤器filter。
-
mian.js文件不通过
vue2:vue2中我们可以使用pototype(原型) 的形式去进行操作,引入的是构造函数。vue3:vue3中需要使用结构的形式进行操作,引入的是工厂函数;vue3中app组件中可以没有根标签。
2.vue2中data为什么是一个函数
官方文档说明:当一个组件被定义,data 必须申明为返回一个初始数据的函数,因为组件可能被用来创建多个实例。
当我们给组件中的data写成一个函数时,数据以函数返回值形式定义,这样每服用一次组件,就返回一个新的data,每个data有各自的作用域,保证各个组件的数据不被污染;
如果我们把data写成对象形式,那么组件所用的实例都用的同一个构造函数,由于javaScript特性,实际组件实例共用了一个data,就会造成一个变了全都会变的结果。
3.vue3中依然可以使用data吗?setup和data的执行顺序是如何的?如果setup与data变量重名,执行谁?
1)vue3虽然时合成式api,生命周期上把vue2中created及之前面的部分都合成setup,但是依然能使用vue2的配置项,比如data,methods,created等,也就是vue3中setup和data可以同时存在,
2)执行顺序:
setup执行早于data,传统配置项中,可以调用到setup中的数据,也就是data可以调用setup中的数据;反过来,setup中,调用不到传统配置项中的数据。
因为setup执行的时机,在data配置项之前,所以在data配置项中读取数据时,setup数据已经加载完毕,可以读取到。反之则不行。(注:setup中,this值为undefined)
3)如果setup配置项和传统配置项中有重名情况,setup优先。例如:两个都存在同一个变量名,不同的变量值时,取setup中的变量值。
4.vue框架下的watch和computed的区别
computed和watch都是vue框架中用于监听数据变化的属性
- 功能:watch监听一个值的变化而执行对应的回调,computed是计算属性。
- 是否调用缓存:computed函数所依赖的属性不变的时候会调用缓存;watch每次监听的值发生变化时候都会调用回调
- 是否调用return:computed必须有;watch可以没有
- 使用场景:computed当一个属性受多个属性影响的时候;例如购物车商品结算;watch当一条数据影响多条数据的时候,例如搜索框
- 是否支持异步:computed函数不能有异步;watch可以
- 第一次加载式是否监听:computed默认第一次加载的时候就监听,但是watch默认第一次加载不监听,如果需要第一次加载就监听,则需要添加immediate属性,并设置为true。
5.vue2中组件通信方式
Vue 组件间通信只要指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信
1. props / $emit 适用 父子组件通信
2. ref 与 $parent / $children适用 父子组件通信
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
$parent / $children:访问父 / 子实例
3. EventBus ($emit / $on)适用于 父子、隔代、兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
4.
a
t
t
r
s
/
attrs/
attrs/listeners适用于 隔代组件通信
a
t
t
r
s
:包含了父作用域中不被
p
r
o
p
所识别
(
且获取
)
的特性绑定
(
c
l
a
s
s
和
s
t
y
l
e
除外
)
。当一个组件没有声明任何
p
r
o
p
时,这里会包含所有父作用域的绑定
(
c
l
a
s
s
和
s
t
y
l
e
除外
)
,并且可以通过
v
−
b
i
n
d
=
"
attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="
attrs:包含了父作用域中不被prop所识别(且获取)的特性绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v−bind="attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。
l
i
s
t
e
n
e
r
s
:包含了父作用域中的
(
不含
.
n
a
t
i
v
e
修饰器的
)
v
−
o
n
事件监听器。它可以通过
v
−
o
n
=
"
listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on事件监听器。它可以通过 v-on="
listeners:包含了父作用域中的(不含.native修饰器的)v−on事件监听器。它可以通过v−on="listeners" 传入内部组件
6. provide / inject适用于 隔代组件通信
祖先组件中通过 provide 来提供变量,然后在子孙组件中通过 inject 来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
7. Vuex适用于 父子、隔代、兄弟组件通信
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation
6.vue中的key作用与原理,为什么不建议用index做为key?为什么不建议用随机数作为 key?
官方关于key的解释:
key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。
而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
简单来说:key 的作用主要是为了高效的更新虚拟 DOM。首先根据vue的diff算法生成对应的vNode,再用patch函数对比新旧vNode,更新DOM。
用index作为key会出现什么问题:
一般情况下,只是展示list,没有太大问题;如果list会动态删除、添加、排序等操作,就会出现错乱,比如你你明明删除第一行,但是视图却删除了第二行吗,问题解析就是因为key的重复,当你删除第一行时,第二行的key也变成第一行的key ,这两个key是相同的
不用随机数作为 key,是因为diff算法执行后会把,旧节点会被全部删掉,新节点重新创建,浪费性能
7.vue中的mixin是什么?与vuex有何区别?
官方解释:
混入(mixin)提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
mixin与vuex区别:
Vuex公共状态管理,如果在一个组件中更改了Vuex中的某个数据,那么其它所有引用了Vuex中该数据的组件也会跟着变化。
Mixin中的数据和方法都是独立的,组件之间使用后是互相不影响的。
8.vue中组件和mixin中的属性使用区别
data
computed
methods
watch
props
provide和inject
以上属性和方法会被合并成一个新对象,如果出现相同的属性,组件中的属性会覆盖mixin中的属性。
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
activated
deactivated
beforeDestroy
destroyed
以上属性和方法会被合并成一个数组,如果出现相同的属性,mixin中的属性会排在组件中的属性前面。
9.vue中组件和mixin执行顺序
生命周期函数,先执行mixin里面的,再执行组件里面的
10.你使用过vuex吗?什么是vuex,它包含哪些部分?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态,解决多组件数据通信
state: 统一定义公共数据(类似于data(){return {a:1, b:2,xxxxxx}})
mutations : 使用它来修改数据(类似于methods,这里必须是同步函数)
getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )
actions: 发起异步请求
modules: 模块拆分
使用方式:
通过this.
s
t
o
r
e
.
s
t
a
t
e
来获取公共数据,通过
t
h
i
s
.
store.state 来获取公共数据,通过this.
store.state来获取公共数据,通过this.store.commit(‘mutation名’, 实参)调用mutation中的同步函数
11. vue3中的reactive和ref的区别,为什么reactive不能定义基本数据类型?
reactive和ref都是vue3中提供的响应式API,用于定义响应式数据的
reactive通常用于定义对象数据类型,其本质是基于 Proxy 实现对象代理,所以reactive不能用于定义基本类型数据
ref通常是用于定义基本数据类型,取值要跟.value,其本质是基于 Object.defineProperty() 重新定义属性的方式实现,vue3源码中是基于类的属性访问器实现(本质也是 defineProperty )
12.vue父组件套子组件之后父子组件的生命周期的运行顺序
加载渲染过程
父级beforeCreate=>父级created=>父级befroeMount=>子beforeCreate=>子created=>子beforeMounted=>父mounted
销毁过程
父beforeDestorty=>子beforeDestory=>子destoryed=>父destoryed
13.解释vue3的api。如watchEffect,toValue
watchEffect()立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
而watch是变量变化的时候才执行。
toValue()将值、refs 或 getters 规范化为值。toValue(ref(1))就可以直接拿到值1。
toRefs()将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。
二、关于Axios
1. 关于axios你知道那些?
axios是一个基于pormise的网络请求库
this.
a
x
i
o
s
.
i
n
t
e
r
c
e
p
t
o
r
s
.
r
e
q
u
e
s
t
.
u
s
e
/
/
封装请求
t
h
i
s
.
axios.interceptors.request.use //封装请求 this.
axios.interceptors.request.use//封装请求this.axios.interceptors.response.use//响应拦截
三、关于HTTP
1. HTTP与HTTPS的区别?
HTTPS:
是以安全为目标的 HTTP 通道,是 HTTP 的安全版。HTTPS 的安全基础是 SSL。SSL 协议位于 TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持.
区别:
HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
HTTP和HTTPS 使用完全不同的连接方式,所用的端口不同,前者是80 端口,后者是 443端口
2. 常见的HTTP状态码?
200 – 请求成功
301 – 资源(网页等)被永久转移到其它URL
302 – 资源(网页等)被临时转移到其它URL
304 – 自从上次请求后,请求的网页未修改过, 服务器返回此响应时,不会返回网页内容。
400 – 语法错误,服务器无法识别
401 – 请求需要认证
403 – 请求的对应资源禁止被访问
404 – 请求的资源(网页等)不存在
500 – 内部服务器错误
503 – 服务器正忙
3. HTTP1.0和HTTP2.0的区别
- HTTP2使用的是二进制传送,HTTP1.X是文本(字符串)传送。
HTTP1.X使用的是明文的文本传送,而HTTP2使用的是二进制传送,二进制传送的单位是帧和流。帧组成了流,同时流还有流ID标示 - HTTP2支持多路复用
http1一个连接只能提交一个请求,而http2可以同时处理多个请求,实现多路复用,每个请求是通过流ID去进行标识的。这样http2可以降低连接的占用数量,从而提高网络的吞吐量。 - HTTP2头部压缩
http2相对http1通过gzip与compress对头部进行了压缩,且在客户端与服务端各自维护一份头部索引表,后面的传输可以根据索引Id进行头部信息的传输,缩小头部容量,间接提高了传输效率s - HTTP2支持服务器推送
http1是只能从客户端发起,服务器响应的,而http2可以服务端进行推送。
四、关于web
1. web缓存有哪些
- HTTP缓存:HTTP缓存是Web开发中最重要的缓存机制之一。HTTP协议支持多种缓存策略(强制缓存,协商缓存),其中 缓存控制 是控制浏览器缓存的最基本、最重要的机制。通过在HTTP响应头中设置Cache-Control和Expires等相关指令,可以让浏览器有效地缓存资源,提高响应速度。另外,ETag和Last-Modified是两种验证缓存是否过期的机制,但Last-Modified只能精确到秒,但是我们前端都是精确到毫秒级的,我们应该优先使用Etag。
- 浏览器缓存:所谓的浏览器缓存指的是浏览器将用户请求过的静态资源,存储到本地内存和磁盘中,
- Service Worker:Service Worker是一种Web Worker,能够拦截网络请求,并根据定义的策略和缓存逻辑,返回缓存中的资源或者向服务器发起未缓存的网络请求。通过使用Service Worker来实现离线缓存,并将资源放到本地
- Web Storage缓存:Web Storage是HTML5提供的浏览器本地存储API,包含了localStorage和sessionStorage两种方式。
- 内存缓存:内存缓存是指将某些数据暂时放入内存中,以便在需要的时候能够快速地读取。
五、关于Promise
1. 简单说一下Promise,谈谈你对Promise的理解
Promise是ES6新增的语法,是一种异步编程的一种解决方案,Promise本质上是一个绑定了回调的对象。 Promise在一定程度上解决了回调函数的书写结构问题,解决了回调地狱的问题。Promise可以看作是一个状态机,它有三种状态:pending,fulfilled,rejected,其中初始状态是pending,可以通过函数resolve(表示成功)把状态变为fulfilled,或者通过函数reject(表示失败)把状态变为rejected,状态一经改变就不能再次变化。
2.Promise有哪些方法
三个实例方法: then/catch/finally
六个静态方法: resolve/reject/all/allSettled/race/any
- then :方法是整个 Promise 解决的核心内容,同时因为回调函数和返回一个新的 Promise 实例
- catch:如果上面没有定义 reject 方法或者在抛出错误,那么所有的异常会走向 catch 方法,而 catch 可以复用 then 方法。
- finally :不管是 resolve 还是 reject 都会调用 finally 。那么相当于 fianlly 方法替使用者分别调用了一次 then 的 resolved 和 rejected 状态回调。
- Promise.all:Promise.all() 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。所有参数数组 Promise 实例执行 resolve 回调后,新实例执行 resolve 回调;如果中间有任何一个 Promise 实例执行 reject 回调,那么新实例就直接执行 reject 回调了。
- Promise.race:返回最快完成那一个 Promise 实例。只要参数数组中有一个 Promise 实例执行 resolve 回调或 reject 回调后,新实例就直接返回结果。
- Promise.allSettled:只有等到参数数组的所有 Promise 实例都发生状态变更,返回的 Promise 实例才会发生状态变更,无论是执行 resolve 回调还是 reject 回调的状态。
- Promise.any:返回任意一个最快执行 resolve 回调的 Promise 实例。
- Promise.resolve:返回一个以给定值解析后的 Promise 实例。相当于执行 then 方法里面的 _resolvePromise。
- Promise.reject:返回一个带有拒绝原因的 Promise 实例。
六、关于CSS
1. 什么是BFC ?
BFC(块级格式化上下文)是指浏览器中创建了一个独立的渲染区域,BFC可以让元素成为隔离独立的容器,且容器内的子元素不会影响到外面的布局。
2. BFC 有什么用?
- 防止外边距重叠
BFC导致的属于同一个BFC中的子元素的margin重叠。(Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠) - 清除浮动的影响
块级子元素浮动,如果块级父元素没有设置高度,其会有高度塌陷的情况发生。
原因:子元素浮动后,均开启了BFC,父元素不会被子元素撑开。
解决方法:由第六条原理得,计算BFC的高度时,浮动元素也参与计算。所以只要将父容器设置为BFC,就可以把子元素包含进去:这个容器将包含浮动的子元素,它的高度将扩展到可以包含它的子元素,在这个BFC4 - 防止文字环绕
3. 如何创建 BFC ?
- (子)float:left/right
- (子)position:absolute/fixed。
- (子)display:inline-block;
- (父)display:flex;
- (父)overflow:hidden/scroll/auto
4. 垂直居中方法(至少四种)?
- position定位+transform:translate()
.box{
position:absolute;
width:100px
height:100px;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
- text-align + line-height实现行内元素垂直居中
.box{
height:100px;
text-align:center;
line-height:100px;
}
- 定位top、left、right、bottom:0+margin: auto
.box{
position:absolute;
width:100px;
height:100px;
top:0;
right:0;
bottom:0;
left:0;
margin: auto;
}
- flex布局,justify和align
.box{
display:flex;
justify-content:center;
align-items:center;
}
- flex布局加上margin
.fatherbox{
display:flex;
}
.box{
margin:auto;
width:100px;
height:100px;
}
5. 盒模型
盒子模型分为两种:
- W3C 标准的盒子模型(标准盒模型)
- IE 标准的盒子模型(怪异盒模型)
标准盒模型与怪异盒模型的表现效果的区别之处:
- 标准盒模型中 width 指的是内容区域 content 的宽度
height 指的是内容区域 content 的高度。标准盒模型下盒子的大小 = content + border + padding + margin - 怪异盒模型中的 width 指的是内容、边框、内边距总的宽度(content + border +padding);height 指的是内容、边框、内边距总的高度。怪异盒模型下盒子的大小=width(content + border + padding) + margin
6. CSS选择器的优先级及CSS权重如何计算?
!important>行内样式>ID 选择器>类选择器>标签>通配符>继承>浏览器默认属性
7. CSS 单位中 px、em 和 rem 的区别?
- px 像素(Pixel),绝对单位。像素 px 是相对于显示器屏幕分辨率而言的,是一个虚拟长度单位,是计算机系统的数字化图像长度单位。
- em 是相对长度单位,相对于当前对象内文本的字体尺寸。如当前对行内文本的 体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。它会继承父级元素的字体大小(也就是相对于父级元素) 因此并不是一个固定的值。
- rem是 CSS3 新增的一个相对单位(root em,根 em),使用 rem 为元素设定字体大小时,仍然是相对大小,但相对的只是 HTML 根元素
区别:
IE 无法调整那些使用 px 作为单位的字体大小,而 em 和 rem 可以缩放,rem 相对的只是 HTML 根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通 过它 既可 以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐 层复合的连锁反应。目前,除了 IE8 及更早版本外,所有浏览器均已支持 rem。
8. 使用 CSS 怎么让 Chrome 支持小于 12px 的文字比如 10px?
针对谷歌浏览器内核,加 webkit 前缀,用 transform:scale() 这个属性进行缩放!
9. 谈谈你对重绘和回流(重排)的理解?
- 重排(重新排列): 布局引擎会根据所有的样式计算出盒模型在页面上的位置和大小。
常见的重排因素(元素宽高变化,display:none,节点内容发生变化,浏览器窗口发生变化,内容改变等都会发生重排—重排必重绘) - 重绘(重新绘制): 计算好盒模型的位置、大小和其他一些属性之后,浏览器会根据每个盒模型的特性进行绘制。
常见的重绘的因素(颜色,透明度,transform)
六、JS(重中之重!)
0. js的数据类型和引用类型
基本类型: null,undefined,boolean,number,string,symbol
引用类型:Object, Array ,Function, Date, RegExp等
//这里很多人会忘记引用类型是那些
1. 关于深浅拷贝你知道那些,有没有手写过深拷贝的一些方法?
深拷贝(深拷贝后的对象与原来的对象是完全隔离的,互不影响)
:JSON.parse(JSON.stringify(obj)),递归函数
浅拷贝(当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。)
:for in、 Object.assign、 扩展运算符 … 、Array.prototype.slice()、Array.prototype.concat()
手写深拷贝方法:
- JSON.parse(JSON.stringify(obj))
但是注意一些缺陷:
对象的属性值是函数时,无法拷贝。
原型链上的属性无法拷贝
不能正确的处理 Date 类型的数据
不能处理 RegExp
会忽略 symbol
会忽略 undefined - 递归函数,比如自己封装一个deepClone函数用于深拷贝
function deepClone(obj){
// obj = null 并且不是对象或数组的时候直接返回为空
if (typeof obj !== 'object' || obj == null) {
return obj;
}
let newObj = obj instanceof Array ? [] : {}
for(let k in obj){
if(typeof obj[k]==”object”){
newObj[k]=deepClone(obj[k])
}else{
newObj[k]=obj[K]
}
}
return newObj
}
2. 多维数组扁平化方法
- 递归函数
function getAtter(arr){
let newArr=[]
function toArr(newArr){
arr.forEach(item=>{
item.instenseof Array? toArr(item):newArr.push(item)
)}
}
toArr()
rerturn neArr
}
- flat()函数
Array.prototype.flat()
//使用Infinity,展开任意深度的数组
let newArr=arr.flat(Infinity)
3. js事件循环原理
而js任务包含了同步任务和异步任务
浏览器事件循环
1.浏览器会率先执行同步代码,将异步代码放入消息队列(任务队列)中,待主线程任务完成后执行
2.而异步代码又分为宏任务和微任务,在同步代码全部执行完成后会先执行异步微任务再执行异步宏任务,如果异步任务中仍有异步任务,会继续放入消息队列(任务队列),以此类推,便形成了一个事件循环。(另外还需要分清楚事件循环是问的浏览器还是node的,两者不一样)
在NodeJS中使用libuv实现了Event Loop。
宏任务(macro task): 宏任务是由宿主环境(浏览器、Node)发起的,常见宏任务如下
setTimeout()
setInterval()
setImmediate()(Node.js 环境)
script( 整体代码)
I/O
UI 交互事件
特点:
(1) 不唯一,存在一定的优先级(用户I/O部分优先级更高)
(2) 异步执行,同一事件循环中,只执行一个
微任务(micro task): 微任务是由JS发起的任务,常见微任务如下:
promise.then()
promise.catch()
new MutaionObserver()
object.observe
Async/Await
process.nextTick()(Node.js 环境)
注:promise本身同步,then/catch的回调函数是异步的
特点:
(1) 唯一,整个事件循环当中,仅存在一个;
(2) 执行为同步,同一个事件循环中的microtask会按队列顺序,串行执行完毕;
4. js事件捕获和冒泡
js事件流
js中事件执行的整个过程称之为事件流,分为三个阶段:事件捕获阶段,处于目标阶段、事件冒泡阶段。
事件捕获:当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件。
处于目标阶段:传播到事件触发处,触发注册的事件。
事件冒泡阶段:与事件捕获阶段相反,由内到外进行事件传播,直到根节点。
5. 什么是堆(heap)和栈(stack)内存
1、堆和栈的概念
在JS钟变量都存放在内存中,而内存给变量开辟了两块区域,分别为栈区域和堆区域
栈(stack):是栈内存的简称,栈是自动分配相对固定大小的内存空间,并由系统自动释放,栈数据结构遵循FILO(first in last out)先进后出的原则
堆(heap):是堆内存的简称,堆是动态分配内存,内存大小不固定,也不会自动释放,堆数据结构是一种无序的树状结构,同时它还满足key-value键值对的存储方式;我们只用知道key名,就能通过key查找到对应的value。
2、数据类型
在JS中说到堆和栈就离不开普通数据类型和引用数据类型。
在JS中普通数据类型它是在栈内存在创建的,而引用数据类型则是在堆内存中创建的。
基本类型:采用的是值传递。
引用类型:则是地址传递。
6. 防抖和节流
相同点:防抖(Debounce)和节流(Throttle)都是用来控制某个函数在一定时间内触发次数,两者都是为了减少触发频率,以便提高性能以及避免资源浪费
不同点:节流是第一个说了算,后续都会被节流阀屏蔽掉,防抖是最后一个说了算,前面启用的都会被清除
防抖:防止重复触发事件。用户在短时间内频繁触发事件时,定时器会不断清空,直到指定时间后才执行回调函数,
所以在用户在频繁触发事件过程中,只会执行一次回调函数。
应用场景:搜索,表单提交等
function debounce(func, interval) {
let timer;
return function() {
timer && clearTimeout(timer)
let args = arguments;
timer = setTimeout(() => {
func.apply(this, args)
timer = null;
}, interval)
}
}
节流:在规定时间内只执行一次,也就是把在定时器事件结束时销毁定时器,执行回调函数
应用场景:onscroll滚动,鼠标的跟随动画实现,scroll,resize, touchmove, mousemove等极易持续性促发事件
// 定时器方式
function throttle1(func, interval) {
let sign = true;
return function() {
// 在函数开头判断标志是否为 true,不为 true 则中断函数
if (!sign) return;
// sign 设置为 false,防止执行之前再被执行
sign = false;
setTimeout(() => {
func.apply(this, arguments)
// 执行完事件之后,重新将这个标志设置为 true
sign = true;
}, interval)
}
}
7. 有关事件循环的代码,让你说出执行顺序
- 例题1
new Promise(resolve => {
console.log('promise');
resolve(5);
}).then(value=>{
console.log('then回调', value)
})
function func1() {
console.log('func1');
}
setTimeout(() => {
console.log('setTimeout');
});
func1();
答案 :
promise
func1
then回调5
setTimeout
- 例题2
setTimeout(function () {
console.log("set1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
new Promise(function (resolve) {
console.log("pr1");
resolve();
}).then(function () {
console.log("then1");
});
setTimeout(function () {
console.log("set2");
});
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1")
});
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});
答案:
pr1
2
then1
queueMicrotask1
then3
set1
then2
then4
set2
- 例题3
例题3
async function async1 () {
console.log('async1 start')
await async2();
console.log('async1 end')
}
async function async2 () {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise (function (resolve) {
console.log('promise1')
resolve();
}).then (function () {
console.log('promise2')
})
console.log('script end')
结果
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout3
8. 变量提升和函数提升总结(包括立即执行函数)
函数提升会放在变量提升之前,变量提升和函数提升都只是提升它的声明,不会提升赋值和函数调用语句。比如
a = 1;
fn(); // 函数调用
var a = 2; // 变量声明+赋值
function() { // 函数声明
console.log(3);
}
// 上面代码真实执行顺序
function fn() { // 函数声明
console.log(3)
}
var a; // 变量声明,a = undefined
a = 1; // a = 1
fn(); // 函数调用,打印出3
a = 2; // 变量赋值,a = 2
1. 变量提升
只有var声明的变量提升能被成功执行,let和const虽然有提升,但是存在暂时性死区,不能被成功执行
2. 函数提升
在js中,函数分为:
函数声明:function fn(){}
函数表达式(字面量):let fn = function(){}
立即执行函数(匿名函数,2中的也是):(function(){})()
其中只有函数声明即function fn(){}这种形式才会进行函数提升。另外两种在代码中都不会被提升。当然,通过上面这些方式声明的函数的内部也都存在变量和函数提升。比如:
function fn() {
var a=b=2
console.log(a)
console.log(b)
}
fn()
//那么其中a=undefind,b=2, 因为a在function内,是局部变量;b是全局变量
//因为变量提升实际转为如下形式
function fn(){
var a
a=b
b=2
}
fn()
另外注意:
对于同名的变量声明,Javascript采用的是忽略原则。后声明的变量声明会被忽略。
对于同名的函数声明,Javascript采用的是覆盖原则。
经典例题
// a
function Foo () {
getName = function () {
console.log(1);
}
return this;
}
// b
Foo.getName = function () {
console.log(2);
}
// c
Foo.prototype.getName = function () {
console.log(3);
}
// d
var getName = function () {
console.log(4);
}
// e
function getName () {
console.log(5);
}
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3
解析:
**Foo.getName(),**Foo为一个函数对象,对象都可以有属性,b 处定义Foo的getName属性为函数,输出2;
**getName(),**这里看d、e处,d为函数表达式,e为函数声明,两者区别在于变量提升,函数声明的 5 会被后边函数表达式的 4 覆盖;
**Foo().getName(),**这里要看a处,在Foo内部将全局的getName重新赋值为 console.log(1) 的函数,执行Foo()返回 this,这个this指向window,Foo().getName() 即为window.getName(),输出 1;
**getName(),**上面3中,全局的getName已经被重新赋值,所以这里依然输出 1;
**new Foo.getName(),**这里等价于 new (Foo.getName()),先执行 Foo.getName(),输出 2,然后new一个实例;
**new Foo().getName(),**这里等价于 (new Foo()).getName(), 先new一个Foo的实例,再执行这个实例的getName方法,但是这个实例本身没有这个方法,所以去原型链__protot__上边找,实例.protot === Foo.prototype,所以输出 3;
**new new Foo().getName(),**这里等价于new (new Foo().getName()),如上述6,先输出 3,然后new 一个 new Foo().getName() 的实例。
9.new关键字都做了什么
1.创建一个空对象:new 操作符会创建一个空对象,这个对象会继承自构造函数的原型对象。
2.设置原型链关系:新创建的对象的 _ Prototype _ 属性会被设置为构造函数的 prototype 属性,从而建立起对象与构造函数原型之间的链接。
3.绑定 this 指向:new 操作符会将构造函数内部的 this 关键字绑定到新创建的对象上,使构造函数内部的代码可以访问和操作该对象的属性和方法。
4.执行构造函数代码:new 操作符会调用构造函数,并传入任何参数。构造函数内部的代码会被执行,可以用来初始化对象的属性和方法。
5.返回新对象:如果构造函数没有显式地返回其他对象,那么 new 操作符会隐式地返回新创建的对象实例;否则,如果构造函数返回了一个非原始值的对象,则该对象会成为 new 表达式的结果,而新创建的对象实例会被丢弃。
function Foo(name) {
this.name = name;
return this;
}
var obj = {};
obj.__proto__ = Foo.prototype; // Foo.call(obj, 'mm');
var foo = Foo.call(obj, 'mm');
console.log(foo);
10.经典例题
- 爬楼梯问题
题目描述: 爬楼梯需要 n (n为正整数)阶才能到达楼顶。每次可以爬 1 或 2 个台阶。求有多少种不同的方法可以爬到楼顶。
思路:
1、分析题意不难发现:
爬第 n 阶楼梯的方法数量等于 2 部分之和
即爬上 n-1 阶楼梯和爬上 n-2 阶楼梯的方法数量之和
2、定义容器数组存放爬第 n 阶楼梯的方法数量数组
(其实该数组元素为斐波那契数列)
题解:
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
let fibArr = [];
fibArr[0] = fibArr[1] = 1;
for(let i = 2; i <= n; i++) {
fibArr[i] = fibArr[i - 1] + fibArr[i - 2];
}
return fibArr[n];
};
七、TS
1.TypeScript 与 JavaScript 有何不同?
TypeScript 是 JavaScript 的超集,这意味着所有有效的 JavaScript 代码也是有效的 TypeScript 代码。然而,TypeScript 增加了 JavaScript 所没有的特性,例如静态类型和基于类的面向对象编程。
TypeScript 还具有更严格的类型系统,允许在编译时而不是运行时检测到错误。
2. TypeScript 中如何定义和使用泛型?
TypeScript 中的泛型是在函数、类和接口声明中使用方括号 <> 定义的,带有类型的占位符。并且可以在使用函数、类或接口时指定形状。
这是一个例子。
function identity<T>(arg: T): T {
return arg;
}
const result = identity<string>('Hello');
console.log(result); // Hello
3.什么是TS中的元组?
TypeScript中的元组类型允许你表达一个固定数量的元素的数组,其中每个元素都有已知的类型,而这些类型不必相同。
在TypeScript中,你可以这样定义一个元组:
let myTuple: [number, string] = [1, "Hello"];
1
这里,myTuple被定义为一个元组,它包含一个number类型的元素和一个string类型的元素,且元素的顺序是固定的。
4.Ts中的as和is是什么?
1、as 关键字用于类型断言,它用于告诉编译器一个值的类型,即强制把某个值当做特定类型来处理,如下所示:
const myString: any = "hello";
const lengthOfString: number = (myString as string).length;
在这个例子中,我们使用 as 关键字将 myString 声明为一个字符串类型,以便我们可以安全地使用 length 属性来获取字符串的长度。
2、is 关键字用于类型保护,它用于在运行时检查一个值是否符合某个类型,如下所示:
function isString(value: any): value is string {
return typeof value === "string";
}
function logIfString(value: any) {
if (isString(value)) {
console.log(value);
}
}
在这个例子中,我们定义了一个 isString 函数来检查一个值是否为字符串类型,如果是字符串类型,它会返回 true。然后我们在 logIfString 函数中使用 isString 函数来检查传入的参数是否为字符串类型,如果是,我们就打印这个字符串。
八、React
1.类组件和函数组件之间的区别是什么?
语法:类组件是使用 ES6 的类语法来定义的,而函数式组件是使用 JavaScript 函数来定义的。
生命周期:类组件可以使用生命周期方法(如 componentDidMount、componentDidUpdate 等)来处理组件的状态和行为。而函数式组件通过使用 React Hooks(如 useEffect、useState 等)来实现类似的功能。
组件状态和上下文:类组件可以使用 state 属性来管理组件的内部状态,并且可以使用 this 关键字访问组件实例和其他方法。函数式组件通过使用 useState Hook 来管理状态,并且没有实例或者其他类方法。
性能:由于函数式组件没有实例化过程,渲染时的性能通常比类组件更高效。
可读性和简洁性:函数式组件相对于类组件来说更加简洁,代码量更少,并且更易于阅读和维护。它们通常只关注数据的输入和输出,而不需要处理复杂的生命周期方
2.React中super(props)和super()以及不写super()的及ES6和ES5的区别
- constructor和super的基本含义
constructor() – 构造方法
这是es6中的类的默认方法,通过new命令生成对象实例自动调用的方法。
并且,该方法是类中必须要有的,如果没有显示定义,则会默认添加空的constructor()方法。
super() – 继承
在class方法中,继承是使用extends关键字来实现继承的。
子类必须在constructor()中调用super()方法,否则新建实例时会报错。
报错的原因是,子类是没有自己的this对象的,它只能继承父类的this对象,然后对其进行加工,而super()就是将父类中的this对象继承给子类的。
没有super,子类就得不到this对象。
- ES5和ES6关于继承的实现不同之处
在ES5中,当一个构造函数前面加上new的时候,其实一共做了四件事:
1.生成一个空的对象并将其作为this
2.将空对象的__proto__指向构造函数的prototype
3.运行该构造函数
4.如果构造函数没有return或者return一个返回this值是基本类型,则返回this,如果return一个引用类型,则返回这个引用类型
简单解释,就是在ES5的继承中,先创建子类的实例对象this,然后再将父类的方法添加到this上,而ES6采用的是先创建父类的实例this(故要先调用super()方法),然后再用子类的构造函数修改this。
- super(props) —— super() —— 以及不写super()的区别
如果你用到了constructor就必须写super(),是用来初始化this的,可以绑定事件到this上
如果你在constructor中要使用this.props,就必须给super加参数,super(props)
(注意: 无论有没有constructor,在render中this.props都是可以使用的,这是react自动附带的)
如果没用到constructor,是可以不写的,react会默认添加一个空的constructor
九、uniApp
0. UniApp 中的生命周期钩子函数及其执行顺序。
在 UniApp 中,每个页面和组件都有一系列的生命周期钩子函数,用于在特定的时机执行代码。以下是 UniApp 中常用的生命周期钩子函数及其执行顺序:
onLoad:页面/组件加载时触发。
onShow:页面/组件显示在前台时触发。
onReady:页面/组件初次渲染完成时触发。
onHide:页面/组件被隐藏在后台时触发。
onUnload:页面/组件被销毁时触发。
执行顺序为:onLoad -> onShow -> onReady -> onHide -> onUnload。
1.uniapp应用的生命周期、页面的生命周期、组件的生命周期
一、应用的生命周期
1.onLaunch——当uni-app 初始化完成时触发(全局只触发一次)
2.onShow——当 uni-app 启动,或从后台进入前台显示
3.onHide——当 uni-app 从前台进入后台
4.onError——当 uni-app 报错时触发
5.onUniNViewMessage——对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯
6.onUnhandledRejection——对未处理的 Promise 拒绝事件监听函数(2.8.1+)
7.onPageNotFound——页面不存在监听函数
8.onThemeChange——监听系统主题变化
二、页面的生命周期
1.onInit——监听页面初始化,其参数同 onLoad 参数,为上个页面传递的数据,参数类型为 Object(用于页面传参),触发时机早于 onLoad
2.onLoad——监听页面加载,其参数为上个页面传递的数据,参数类型为 Object(用于页面传参),参考示例
3.onShow——监听页面显示。页面每次出现在屏幕上都触发,包括从下级页面点返回露出当前页面
4.onReady——监听页面初次渲染完成。注意如果渲染速度快,会在页面进入动画完成前触发
5.onHide——监听页面隐藏
6.onUnload——监听页面卸载
7.onResize——监听窗口尺寸变化
三、组件的生命周期
uni-app 组件支持的生命周期,与vue标准组件的生命周期相同
1.beforeCreate——在实例初始化之后被调用。
2.created——在实例创建完成后被立即调用。
3.beforeMount——在挂载开始之前被调用。
4.mounted——挂载到实例上去之后调用。详见 注意:此处并不能确定子组件被全部挂载,如果需要子组件完全挂载之后在执行操作可以使用$nextTickVue官方文档
5.beforeUpdate——数据更新时调用,发生在虚拟 DOM 打补丁之前。
6.updated——由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
7.beforeDestroy——实例销毁之前调用。在这一步,实例仍然完全可用。
8.destroyed——Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
2.uniapp中如何实现页面的下拉刷新和上拉加载更多?
可以使用uni.onPullDownRefresh方法实现页面的下拉刷新,使用uni.onReachBottom方法实现页面的上拉加载更多。
// 在页面的onPullDownRefresh方法中实现下拉刷新
onPullDownRefresh() {
// 执行刷新操作
console.log('下拉刷新');
// 刷新完成后调用uni.stopPullDownRefresh()方法停止刷新
uni.stopPullDownRefresh();
}
// 在页面的onReachBottom方法中实现上拉加载更多
onReachBottom() {
// 执行加载更多操作
console.log('上拉加载更多');
}
3.uniApp中如何获取设备信息?
可以使用uni.getSystemInfo方法获取设备信息,包括设备型号、操作系统版本等。
uni.getSystemInfo({
success: (res) => {
console.log(res.model, res.system);
},
fail: (err) => {
console.error(err);
}
});
4.uniApp中如何进行微信支付
可以使用uni.requestPayment方法进行微信支付,通过设置支付参数来实现支付功能。
uni.requestPayment({
provider: 'wxpay',
timeStamp: '1234567890',
nonceStr: 'abcdefg',
package: 'prepay_id=1234567890',
signType: 'MD5',
paySign: 'abcdefg',
success: (res) => {
console.log(res);
},
fail: (err) => {
console.error(err);
}
});
5.uniApp中如何获取地理位置
可以使用uni.getLocation方法获取用户的地理位置信息。
uni.getLocation({
success: (res) => {
console.log(res.latitude, res.longitude);
},
fail: (err) => {
console.error(err);
}
});
5.uniApp中路由和页面跳转
1.uni.navigateTo(OBJECT):
保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。
uni.navigateTo({
url: 'test?id=1&name=uniapp'
});
2.uni.reLaunch(OBJECT):
关闭所有页面,打开到应用内的某个页面。
3.uni.redirectTo(OBJECT):
关闭当前页面,跳转到应用内的某个页面。
4.uni.switchTab(OBJECT):
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
//page.json中
{
"tabBar": {
"list": [{
"pagePath": "pages/index/index",
"text": "首页"
},{
"pagePath": "pages/other/other",
"text": "其他"
}]
}
}
//other.vue中
uni.switchTab({
url: '/pages/index/index'
});
5.uni.navigateBack(OBJECT):
关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。
/ 注意:调用 navigateTo 跳转时,调用该方法的页面会被加入堆栈,而 redirectTo 方法则不会。见下方示例代码
// 此处是A页面
uni.navigateTo({
url: 'B?id=1'
});
// 此处是B页面
uni.navigateTo({
url: 'C?id=1'
});
// 在C页面内 navigateBack,将返回A页面
uni.navigateBack({
delta: 2
});
6.uniApp中数据缓存
uni.setStorage(OBJECT)
将数据存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个异步接口。
uni.setStorage({
key: 'storage_key',
data: 'hello',
success: function () {
console.log('success');
}
});
uni.setStorageSync(KEY,DATA)
将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。
try {
uni.setStorageSync('storage_key', 'hello');
}
catch{
}
获取缓存对应uni.getStorage(OBJECT)和uni.setStorageSync(KEY,DATA)
删除缓存对应uni.removeStorage(OBJECT)和uni.removeStorageSync(KEY,DATA)
清除本地缓存对应uni.clearStorage(OBJECT)和uni.clearStorageSync(KEY,DATA)
7.uniApp中web-view通信
web-view 是一个 web 浏览器组件,可以用来承载网页的容器,会自动铺满整个页面(nvue 使用需要手动指定宽高)。
uni.postMessage(OBJECT)
网页向应用发送消息,在 的 message 事件回调 event.detail.data 中接收消息。
App端web-view的扩展
每个vue页面,其实都是一个webview,而vue页面里的web-view组件,其实是webview里的一个子webview。这个子webview被append到父webview上。
通过以下方法,可以获得这个web-view组件对应的js对象,然后参考https://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject,可以进一步重设这个web-view组件的样式,比如调整大小
<template>
<view>
<web-view src="https://www.baidu.com"></web-view>
</view>
</template>
<script>
var wv;//计划创建的webview
export default {
onReady() {
// #ifdef APP-PLUS
var currentWebview = this.$scope.$getAppWebview() //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效
setTimeout(function() {
wv = currentWebview.children()[0]
wv.setStyle({top:150,height:300})
}, 1000); //如果是页面初始化调用时,需要延时一下
// #endif
}
};
</script>
8.uniApp运行在vscode
vue create -p dcloudio/uni-preset-vue uni_vue2_cli创建项目,然后用默认模板
十、移动端和小程序
1.请谈谈wxml与标准的html的异同?
wxml 是微信小程序的一种页面渲染语言,类似于 HTML,但也有一些不同之处。
以下是 wxml 与标准的 HTML 的异同:
相同点:
两者都是页面渲染语言,用于描述网页的结构和内容。
两者都使用标签来组织内容。
两者都支持使用 CSS 样式表来控制页面的外观和布局。
两者都支持事件处理,可以通过绑定事件来响应用户的操作。
不同点:
标签不同:wxml 中的标签更多地与微信小程序的 API 相关,比如 、
属性不同:wxml 的标签属性与 HTML 的标签属性也有一些不同,比如 wxml 中的 wx:if、wx:for、{{}} 表达式 等属性是专门为微信小程序开发设计的,而 HTML 中则没有这些属性。
样式不同:wxml 中的样式是使用 wxss(微信小程序样式表) 来定义的,而 HTML 中则是使用标准的 CSS 样式表来定义的。
盒子模型不同:wxml 中的盒子模型与标准的 HTML 盒子模型也略有不同,主要体现在盒子的宽度和高度的计算方式上。
小程序运行在JS Core内,没有DOM树和windiw对象,小程序中无法使用window对象和document对象。
总的来说,wxml 和 HTML 相似,但也有自己的特点和差异,需要根据具体的开发需求来选择使用哪种语言。
2.请谈谈WXSS和CSS的异同?
WXSS(WeChat Style Sheet)是微信小程序的样式表语言,它与标准的 CSS(Cascading Style Sheets)有以下异同:
相同点:
两者都用于定义页面元素的样式,包括颜色、字体、布局、边框等方面。
两者都支持选择器、属性、值等基本语法。
两者都支持继承、层叠等特性。
不同点:
单位不同:CSS 使用像素(px)、百分比(%)等单位来表示长度或大小,而 WXSS 使用 rpx(微信小程序专用的长度单位),rpx 会根据屏幕宽度进行自适应调整,适应不同设备的屏幕尺寸。
可用属性不同:WXSS 与 CSS 支持的属性并不完全一致,例如 WXSS 中有专门针对微信小程序的一些属性,如 text-decoration-line(下划线)、-webkit-line-clamp(文本行数)等。
属性值不同:WXSS 与 CSS 中某些属性的取值方式有所不同,例如 WXSS 中的 color 属性可以使用全局变量 $color 来表示颜色,而 CSS 中没有这样的机制。
选择器不同:WXSS 中的选择器与 CSS 中的选择器有所不同,例如 WXSS 中的 ::after 伪元素不支持,但是支持一些特定的微信小程序的选择器,如 page、view 等。
总的来说,WXSS 与 CSS 在使用上有一些不同,但是基本的语法和概念都是相似的。如果你已经熟悉了 CSS,那么上手 WXSS 也应该相对容易。
3.bindtap和catchtap的区别?
bind事件绑定不会阻止冒泡事件向上冒泡
catch事件绑定可以阻止冒泡事件向上冒泡
在微信小程序中,bindtap 和 catchtap 都是用来绑定点击事件的属性,它们的主要区别在于事件冒泡和阻止冒泡的处理方式。
bindtap 属性用于绑定一个点击事件处理函数,当点击事件发生时,该处理函数会被触发执行。如果在事件处理函数中调用 event.stopPropagation() 方法来阻止事件冒泡,则该事件不会向父级元素传递。
catchtap 属性也用于绑定一个点击事件处理函数,但与 bindtap 不同的是,当点击事件发生时,该处理函数先于父级元素的事件处理函数执行,如果在事件处理函数中调用 event.stopPropagation() 方法来阻止事件冒泡,则该事件不会向父级元素传递。
因此,bindtap 和 catchtap 的主要区别在于事件冒泡和阻止冒泡的处理方式,如果希望点击事件能够向上冒泡并被父级元素捕获处理,则应该使用 bindtap,如果希望阻止点击事件冒泡,则应该使用 catchtap。
4.小程序和Vue写法的区别?
遍历的时候:小程序 wx:for=“list” ,而Vue是 v-for=“item in list”
调用data模型(赋值)的时候:
小程序:this.data.item // 调用,this.setData({item:1})//赋值
Vue:this.item //调用,this.item=1 //赋值
小程序和Vue在开发模式、语法、组件化等方面有一定的区别,具体如下:
开发模式:小程序需要使用微信开发者工具进行开发和调试,而Vue可以在浏览器中使用webpack等工具进行开发和调试。
语法:小程序使用WXML和WXSS语言,而Vue使用HTML、CSS和JavaScript等技术。小程序的WXML和WXSS语言是为了方便小程序的开发而设计的,它们与HTML、CSS等语言有一些区别,比如标签和属性的命名、样式的定义方式等。
组件化:小程序和Vue都支持组件化的开发方式,但两者的组件化方式有所不同。小程序的组件化主要是通过Component方法进行定义和注册,而Vue则是通过Vue.component方法进行定义和注册。在使用组件时,小程序需要使用组件的名称进行调用,而Vue则是通过组件的标签名称进行调用。
状态管理:在状态管理方面,小程序使用的是原生的数据绑定方式,即通过setData方法进行数据的修改和更新。而Vue使用的是Vue.js提供的响应式数据绑定和Vuex状态管理机制。
总的来说,小程序和Vue在开发模式、语法、组件化等方面有一定的区别,开发者需要根据不同的需求选择合适的技术方案。
5.微信小程序可以进行dom操作吗?
微信小程序中的WXML语言与HTML语言类似,但并不是真正的HTML语言。WXML是一种轻量级的标记语言,它只能用于描述小程序页面的结构,不能进行像HTML一样的DOM操作。
微信小程序的视图层和逻辑层是分离的,WXML负责视图层的渲染,而逻辑层使用JavaScript来处理数据和业务逻辑。逻辑层可以通过setData方法修改视图层中的数据,从而实现动态渲染页面。但是,不能通过JavaScript直接操作DOM元素,因为微信小程序的视图层并没有提供像Web中的document、window等对象,无法直接操作DOM元素。
5.px、rpx、em、rem、rem布局原理
px:Pixel 像素,相对长度单位。像素是相对于显示器分辨率而言。
rpx:单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应。
em:em是一个相对的长度单位,跟随父级的大小而变化。
rem:rem 也是一个相对的单位,仍是相对大小,但相对的只是HTML根元素。通过rem,既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。
6.如何解决 Android浏览器查看背景图片模糊的问题?
这个问题是 devicePixelRatio的不同导致的,因为手机分辨率太小,如果按照分辨率来显示网页,字会非常小,所以苹果系统当初就把 iPhone4的960×640像素的分辨率在网页里更改为480×320像素,这样 devicePixelRatio=2。
而 Android的 device PixelRatio比较乱,值有1.5、2和3。
为了在手机里更为清晰地显示图片,必须使用2倍宽高的背景图来代替img标签(一般情况下都使用2倍)。
例如一个div的宽高是100px×100px,背景图必须是200px×200px,然后设置 background-size;contain样式,显示出来的图片就比较清晰了。
7.如何解决移动端 click事件有300ms延迟的问题?
300ms延迟导致用户体验不好。为了解决这个问题,一般在移动端用 touchstart、 touchend、 touchmove、tap(模拟的事件)事件来取代 click事件
8.如何解决移动端 click事件有300ms延迟的问题?
可以用正则表达式去掉空格。
this .value =this .value .replace ( / \u2006/g,' ')
8.如何解决移动端HTML5音频标签audio的 autoplay属性失效问题?
因为自动播放网页中的音频或视频会给用户带来一些困扰或者不必要的流量消耗,所以苹果系统和 Android系统通常都会禁止自动播放和使用 JavaScript的触发播放,必须由用户来触发才可以播放。
解决这个问题的代码如下。
document addEventListener (' touchstart', function( ) {
//播放音频
document .getElementsByTagName ('audio ) [0]. play ( );
//暂停音频
document getElementsByTagName ('audio) [0]. pause ( );
});