js 面试题总结(持续更新)
js 面试题总结
1、实现 子元素 在父元素中垂直居中的方式
有多种方法可以实现子元素在父元素中垂直居中的方式,以下是其中几种常用的方法:
- 使用 Flexbox 布局:
父元素设置为 flex 容器,并使用 align-items 属性将子元素垂直居中。
.parent {
display: flex;
align-items: center; /* 子元素垂直居中 */
}
- 使用表格布局:
将父元素设置为 table,子元素设置为 table-cell,并使用 vertical-align 属性将子元素垂直居中。
.parent {
display: table;
}
.child {
display: table-cell;
vertical-align: middle; /* 子元素垂直居中 */
}
- 使用绝对定位和 transform:
使用绝对定位将子元素相对于父元素居中,结合 transform 属性进行位移变换。
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 子元素垂直居中 */
}
- 使用 Grid 布局:
父元素设置为 grid 容器,并使用 place-items 属性将子元素垂直居中。
.parent {
display: grid;
place-items: center; /* 子元素垂直居中 */
}
以上是常用的几种方法,选择适合你项目需求和浏览器兼容性的方式来实现子元素在父元素中垂直居中。
2、实现 子元素 在父元素中水平 垂直居中的方式
1.可以使用 Flexbox 布局。以下是一种基本的方法:
.parent {
display: flex;
justify-content: center; /* 子元素水平居中 */
align-items: center; /* 子元素垂直居中 */
}
以上代码将父元素设置为 flex 容器,使用 `justify-content` 属性将子元素水平居中,使用 `align-items` 属性将子元素垂直居中。
2.使用绝对定位和 transform:
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 子元素水平垂直居中 */
}
3.使用表格布局:
将父元素设置为 table,子元素设置为 table-cell,并使用 vertical-align 和 text-align 属性控制对齐方式。
.parent {
display: table;
width: 100%;
height: 100%;
}
.child {
display: table-cell;
vertical-align: middle; /* 子元素垂直居中 */
text-align: center; /* 子元素水平居中 */
}
4.使用 Grid 布局:
.parent {
display: grid;
}
.child {
justify-self: center; /* 子元素水平居中 */
align-self: center; /* 子元素垂直居中 */
}
3、描述 Keepealive 的作用,有哪些钩子函数,如何控制组件级存列表?
KeepAlive 组件是 Vue.js 中的一个内置组件,用于缓存和复用组件实例。它可以将动态组件进行缓存,在组件切换时保留其状态,提高应用性能。
作用:
- 缓存组件状态:使用 KeepAlive 包裹的组件在切换时会被缓存,保留组件的状态,包括数据、DOM 状态以及生命周期状态。
- 复用组件实例:每次切换到被 KeepAlive 包裹的组件时,并不会重新创建组件实例,而是直接使用之前缓存的组件实例。
常用的钩子函数:
- activated:在组件被激活时调用,每次切换到该组件时都会触发。可以用来执行组件激活时需要进行的逻辑操作,例如数据加载或动画效果的启动。
- deactivated:在组件失活时调用,每次从该组件切换出去时都会触发。可以用来执行组件失活时需要进行的清理操作,例如取消定时器或停止正在进行的动画。
控制组件级存储:
可以通过 <keep-alive>
的特殊属性 include
和 exclude
控制具体哪些组件需要被缓存,以及哪些组件不需要被缓存。
-
include
:指定要缓存的组件名称数组,只有包含在该数组中的组件才会被缓存。 -
exclude
:指定不需要缓存的组件名称数组,这些组件将不会被缓存。
示例如下:
<keep-alive :include="['ComponentA', 'ComponentB']" :exclude="['ComponentC']">
<router-view></router-view>
</keep-alive>
以上代码中,只有名为 “ComponentA” 和 “ComponentB” 的组件会被缓存,而名为 “ComponentC” 的组件不会被缓存。其他组件则按需创建和销毁。
使用 include
和 exclude
可以灵活地控制组件级别的缓存策略,根据具体需求来决定哪些组件需要保持状态并进行复用。
4、请写出判断对象是数组的三个方法
判断对象是否为数组的三个常用方法如下:
- 使用
Array.isArray()
方法:
if (Array.isArray(obj)) {
// obj 是一个数组
}
- 使用
instanceof
运算符:
if (obj instanceof Array) {
// obj 是一个数组
}
- 使用
Object.prototype.toString.call()
方法:
if (Object.prototype.toString.call(obj) === '[object Array]') {
// obj 是一个数组
}
这些方法都可以判断给定的对象是否为数组。对于这三种方法,推荐使用 Array.isArray()
,因为它是专门用于判断对象是否为数组的方法,且在不支持ES5的环境中也能正常工作。
5、请说出下面代码的执行结果
var myObj1 = {
name: '小王',
myAge: this.age,
sayName: function(add, front) {
console.log(this.name + '今年' + this.age + '在' + add + '做' + front);
}
};
var heros = {
name: '小张',
age: '20'
};
myObj1.sayName.call(heros, '上海', '前端');
myObj1.sayName.apply(heros,['上海','前端']);
myObj1.sayName.bind(heros)('上海','前端');
myObj1.sayName.bind(heros,'上海','前端')();
myObj1.sayName.bind(heros,['上海','前端'])()
小张今年20在上海做前端
小张今年20在上海做前端
小张今年20在上海做前端
小张今年20在上海做前端
小张今年20在上海,前端做undefined
考察的
下面是对每个调用方法的说明:
1、 `myObj1.sayName.call(heros, '上海', '前端')`:使用 `call` 方法调用 `sayName` 方法,并将 `heros` 对象作为方法的上下文(`this`)绑定,同时传递 `'上海'` 和 `'前端'` 作为参数。 立即执行
2 `myObj1.sayName.apply(heros, ['上海', '前端'])`:使用 `apply` 方法调用 `sayName` 方法,并将 `heros` 对象作为方法的上下文(`this`)绑定,同时以** 数组 **形式传递 `['上海', '前端']` 作为参数。 立即执行
3、myObj1.sayName.bind(heros)('上海','前端'); 将 heros 作为参数 传入 bind 方法,然后在后面的调用中又依次传入 上海、前端
4、、 `myObj1.sayName.bind(heros, '上海', '前端')()`:使用 `bind` 方法创建一个新的函数,并将 `heros` 对象作为方法的上下文(`this`)绑定,同时传递 `'上海'` 和 `'前端'` 作为参数。然后立即调用新创建的函数。
5、myObj1.sayName.bind(heros,['上海','前端'])() 将heros 作为改变this 指向的值传入,再把 ['上海','前端'] 这个数组作为第一个替换值传入, 所以 add =‘上海,前端’ ,front =undefined
知识点:
在 JavaScript 中,`call`、`apply` 和 `bind` 都是用于改变函数的执行上下文(即函数内部的 `this` 指向)的方法。它们的主要区别在于参数的传递方式和是否立即执行函数。
1. `call` 方法:
- 语法:`function.call(thisArg, arg1, arg2, ...)`。
- 作用:`call` 方法调用一个函数,并将指定的对象作为函数的执行上下文(`this`)。可以通过 `call` 方法实现继承、借用其他对象的方法或更改函数内部的上下文。
- 参数:
- `thisArg`:被绑定到函数的执行上下文(`this`)的对象。
- `arg1`, `arg2`, ...:函数调用时所需的参数列表。
- 返回值:函数的返回结果。
2. `apply` 方法:
- 语法:`function.apply(thisArg, [argsArray])`。
- 作用:`apply` 方法调用一个函数,并将指定的对象作为函数的执行上下文(`this`)。与 `call` 方法类似,不同之处在于参数的传递方式,`apply` 使用 ·数组·来传递参数。
- 参数:
- `thisArg`:被绑定到函数的执行上下文(`this`)的对象。
- `[argsArray]`:一个包含函数调用时所需参数的数组。
- 返回值:函数的返回结果。
3. `bind` 方法:
- 语法:`function.bind(thisArg, arg1, arg2, ...)`。
- 作用:`bind` 方法.创建. 一个新的函数,该函数和原来的函数具有相同的函数体,但执行上下文(`this`)永久地被绑定到 `bind` 方法的第一个参数指定的对象。
- 参数:
- `thisArg`:被绑定到新函数的执行上下文(`this`)的对象。
- `arg1`, `arg2`, ...:在调用新函数时要传递给原函数的固定参数。
- 返回值:返回一个绑定了执行上下文和固定参数的新函数,并不会立即执行。
在给定的代码示例中,我们使用了 `call`、`apply` 和 `bind` 来改变 `myObj1.sayName` 函数的执行上下文,并传递了额外的参数。
- `myObj1.sayName.call(heros, '上海', '前端')`:调用 `sayName` 函数,使其以 `heros` 对象作为执行上下文(`this`),并传递 `'上海'` 和 `'前端'` 作为参数。结果会打印出类似于 "小张今年20在上海做前端" 的内容。
- `myObj1.sayName.apply(heros, ['上海', '前端'])`:类似于 `call` 方法,但是参数通过数组进行传递。
- `myObj1.sayName.bind(heros, '上海', '前端')()`:创建一个新的函数,并将 `heros` 对象作为执行上下文(`this`),同时传递 `'上海'` 和 `'前端'` 作为参数。由于使用了括号 `()`,新函数会立即执行,并打印出相应的内容。
需要注意的是,在使用 `call`、`apply` 和 `bind` 时,要确保参数和参数列表的正确配对,并根据具体需求选择合适的方法来改变函数的执行上下文。
6、过滤器如何使用? 请写一个数字保两个小数的过滤器
在 JavaScript 中,你可以使用过滤器(Filter)来对数据进行格式化和处理。过滤器通常用于将原始数据转化为需要的形式,比如在显示数据时对数字进行格式化。
下面是一个示例代码,实现了一个保留两位小数的数字过滤器:
// 定义数字保留两位小数的过滤器
function twoDecimalFilter(value) {
if (typeof value !== 'number') return value; // 非数字类型直接返回
return value.toFixed(2); // 使用toFixed方法保留两位小数
}
// 示例使用
let number1 = 12.3456;
let number2 = 3.7;
let string = 'abc';
console.log(twoDecimalFilter(number1)); // 输出 "12.35"
console.log(twoDecimalFilter(number2)); // 输出 "3.70"
console.log(twoDecimalFilter(string)); // 输出 "abc"
上述代码中,twoDecimalFilter
是一个自定义的过滤器函数。它接受一个参数 value
,判断该值是否为数字类型,如果是,则使用 toFixed
方法将其保留两位小数并返回;如果不是数字,则直接返回原值。
在使用过滤器时,只需调用过滤器函数并传入要格式化的数据即可。在上面的示例中,我们分别对 number1
、number2
和 string
进行过滤,并输出结果。
请注意,在实际开发中,可能会使用框架或库来提供更便捷和灵活的过滤器机制,比如在 Vue.js 中使用过滤器。以上示例仅演示了一个简单的自定义过滤器的实现方式。
上述要求用vue的过滤器实现
使用 Vue 的过滤器可以更方便地对数据进行格式化和处理。下面是一个使用 Vue 过滤器的示例,实现保留两位小数的数字过滤器:
html复制代码<!-- 在 Vue 模板中定义过滤器 -->
<div id="app">
<p>{{ number1 | twoDecimal }}</p>
<p>{{ number2 | twoDecimal }}</p>
<p>{{ string | twoDecimal }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script>
// 创建 Vue 实例
new Vue({
el: '#app',
data: {
number1: 12.3456,
number2: 3.7,
string: 'abc'
},
filters: {
twoDecimal(value) {
if (typeof value !== 'number') return value;
return value.toFixed(2);
}
}
});
</script>
在上述代码中,我们创建了一个 Vue 实例,并在该实例中定义了一个过滤器 twoDecimal
。在模板中,通过使用管道操作符 |
将要过滤的数据与过滤器名称相连,在输出时会自动应用过滤器。
在这个示例中,number1
、number2
和 string
是 Vue 实例的数据属性,分别代表要过滤的数字和字符串。通过 {{ number | twoDecimal }}
的形式,将数值绑定到对应的模板插值处,同时应用名为 twoDecimal
的过滤器,从而实现保留两位小数的效果。
运行以上代码,你将看到页面上输出的数值已按照过滤器的设定进行了格式化。
7、在vue里面 什么是自定义指令,请注册一个全局的自定义指令。
在 Vue 中,自定义指令(Custom Directive)是一种扩展 Vue 的能力,用于对 DOM 元素进行低层次的操作和交互。通过自定义指令,我们可以直接操作 DOM、添加事件监听器、进行样式操作等。
要注册一个全局的自定义指令,你可以使用 Vue.directive
方法。下面是一个示例代码,演示如何注册一个名为 my-directive
的全局自定义指令:
<div id="app">
<input v-my-directive />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script>
// 注册全局自定义指令
Vue.directive('my-directive', {
bind: function(el, binding, vnode) {
// 指令绑定时的处理逻辑
el.style.backgroundColor = 'yellow';
el.addEventListener('focus', function() {
el.style.color = 'red';
});
},
inserted: function(el, binding, vnode) {
// 指令插入到 DOM 中的处理逻辑
},
update: function(el, binding, vnode, oldVnode) {
// 组件更新时的处理逻辑
},
unbind: function(el, binding, vnode) {
// 指令解绑时的处理逻辑
el.removeEventListener('focus');
}
});
// 创建 Vue 实例
new Vue({
el: '#app',
});
</script>
在上述代码中,我们使用 Vue.directive
方法注册了一个名为 my-directive
的全局自定义指令。该指令包含了几个生命周期钩子函数,例如 bind
、inserted
、update
和 unbind
,你可以根据需要实现相应的逻辑。
在示例代码中,bind
钩子函数用来在指令绑定时设置元素的背景颜色为黄色,并添加一个焦点事件监听器,当聚焦到输入框时,将文字颜色设置为红色。
在 Vue 实例的模板中,我们通过 v-my-directive
指令将这个自定义指令应用到了一个 <input>
元素上。当 Vue 渲染该模板时,my-directive
指令就会被触发,执行对应的逻辑。
请注意,以上示例代码是注册一个全局自定义指令的基本用法,你可以根据实际需求进行扩展和修改。
8、请说出下面代码的输出结果
const arr1 =[
{
id:1,
name:'name1
},{
id:2
name:'name2
}
]
const arr2 =[...arr1] // 复制数组,浅拷贝
arr1[0].name='namel-undate' // 会改变复制后的数组
console.log(arr2[0].name) //
const obj ={
a:'aa'
b:bb'
}
const obj2 = {...obj} // 复制对象形成新对象
obj.a='aa-update' // 不会影响新对象
console.log(obj.a)
console.log(obj2.a)
对于更新后的代码如下:
const arr1 = [{
id: 1,
name: 'name1'
}, {
id: 2,
name: 'name2'
}];
const arr2 = [...arr1];
arr1[0].name = 'namel-update';
console.log(arr2[0].name);
与之前相同,arr1
是一个包含两个对象元素的数组。通过扩展运算符[...arr1]
将arr1
数组的元素复制给了新数组arr2
。同样地,这仍然是浅拷贝,意味着修改arr1
中的第一个对象的name
属性会影响到arr2
中的对应元素。因此,console.log(arr2[0].name)
将输出namel-update
。
const obj = {
a: 'aa',
b: 'bb'
};
const obj2 = {...obj};
obj.a = 'aa-update';
console.log(obj.a);
console.log(obj2.a);
在这段代码中,我们使用了对象展开语法{...obj}
来将obj
对象进行复制。这种方式会创建一个新的对象,并将原始对象中的属性复制到新的对象中。因此,obj2
是一个独立的对象,其属性与原始对象obj
相同但值不共享。
由于我们将obj
对象的a
属性值修改为'aa-update'
,所以console.log(obj.a)
将输出'aa-update'
。而console.log(obj2.a)
将输出原始的属性值'aa'
,因为obj2
是在修改之前复制的对象。
综上所述,使用对象展开语法{...obj}
可以实现对象的浅拷贝,并且复制后的对象与原始对象的属性值不共享。
9、介绍下浅拷贝和深拷贝
浅拷贝和深拷贝是两种常用的对象或数组复制方法,它们在复制过程中处理引用类型数据的方式不同。
- 浅拷贝:
- 浅拷贝是指创建一个新对象或数组,将原始对象或数组的值复制到新对象或数组中。当复制引用类型数据时,只复制了引用地址,而不是创建新的独立副本。
- 浅拷贝后的新对象或数组与原始对象或数组共享相同的引用值,修改其中任何一个的属性或元素会影响到另一个。
- 常见的浅拷贝方式包括扩展运算符
[...arr]
或{...obj}
、Object.assign()
等。
- 深拷贝:
- 深拷贝是指完全复制一个对象或数组及其所有嵌套的对象或数组,得到一个全新且独立的副本。这样两个对象/数组互不干扰,修改其中一个不会影响另一个。
- 深拷贝复制了所有层级的数据,包括基本类型和引用类型数据,递归地遍历复制每个对象或数组的属性或元素。
- 常见的实现深拷贝的方式包括循环递归、JSON序列化与反序列化、使用第三方库(如Lodash或深拷贝工具函数)等。
在选择使用浅拷贝还是深拷贝时,需要根据具体需求和数据结构来决定。如果对象/数组的属性值不包含引用类型数据、或者对共享值的修改无影响,那么可以使用浅拷贝;如果需要完全独立且不受影响地操作复制后的对象/数组,那么应该使用深拷贝。
10、websocket 如何监听心跳
WebSocket 是一种基于 HTTP 协议进行双向通信的协议,通信的两端可以同时发送和接收数据。在 WebSocket 连接中,心跳包用于维持连接的存活状态,可以通过定时发送特定格式的数据包来检测连接是否处于正常工作状态。
具体地,可以通过在服务器端设置一个定时器,在一定时间间隔内发送心跳包。客户端也可以实现类似的逻辑,在一定时间内没有收到服务端的消息,则认为连接出现了问题需要重新连接或重连。WebSocket 还支持 PING 和 PONG 控制帧,可以使用这些帧来检测连接是否存活。当客户端发送 PING 帧时,如果服务端成功接收到,则会回复一个 PONG 帧,客户端可以通过检查是否收到 PONG 帧来判断连接状态。在大部分情况下,开启心跳机制是很重要的,因为它可以避免因长时间没有通信而导致的连接中断,保持 WebSocket 的稳定性和可靠性。
前端在监听 WebSocket 心跳时,可以通过在客户端实现定时器来检测连接是否存活。具体地,可以在连接建立成功后,设置一个定时器,定期发送心跳包到服务器,并在服务器端回复的限定时间内未收到相应的数据包,则认为连接异常,需要重新连接或重连。
同时,WebSocket 还提供了 onclose 事件和 onerror 事件,用于监听连接的关闭和错误。当 WebSocket 断开连接或发生错误时,这两个事件都会触发,可以在事件回调中实现自定义逻辑,比如进行重新连接或提示用户等。需要注意的是,在监听 WebSocket 事件时,也要考虑到接口文档中相关的限制条件,避免违反相关法律法规
11、前端 http 如何转 https
在前端应用中,可以通过以下步骤将 HTTP 转换为 HTTPS:
获取 SSL 证书:获取可信的 SSL 证书是使用 HTTPS 的前提条件。可以通过商业 CA 颁发或自签署证书的方式获得 SSL 证书。
在服务器上部署 SSL 证书:一旦 SSL 证书准备好了,就需要在 HTTP 服务器(如 Nginx、Apache 等)上部署证书。这里假设已经正确部署了 SSL 证书。
修改源代码:在 Web 应用程序的源代码中,需要将所有 http:// 替换为 https://。可以使用全局搜索替换的方法,也可以在部分需要保护的地方手动修改。
重定向 HTTP 请求到 HTTPS:使用服务器级别的 URL 重定向,可以将未加密的请求强制重定向到 HTTPS URL。例如,在 Nginx 中,可以在 server block 中添加以下配置段:
server {
listen 80;
server_name example.com;
rewrite ^(.*)$ https://$server_name$1 permanent;
}
这些配置将启用监听80端口,并将所有HTTP流量重定向到匹配的 HTTPS地址。
测试 HTTPS 连接:完成前面的步骤后,应该测试 Web 应用程序是否正确地使用 HTTPS 实现形式。通常,HTTPS 的开发和调试可能会遇到各种问题,包括混合内容、证书错误等。
需要注意的是,对于某些特殊情况,比如不想购买 SSL 证书、只需要加密部分内容等情况,也可以使用一些其它方法来实现 HTTPS 化。但无论使用何种方法,都应该遵循安全性最佳实践并谨慎处理您的用户数据。
12、前端 同步可以调用异步吗,异步调异步呢
前端同步代码是会阻塞 UI 线程的,如果在同步 JavaScript 代码中调用异步函数,由于异步函数通常需要等待返回结果,那么可能会使页面长时间无响应。因此,在同步 JavaScript 代码中调用异步函数会导致页面卡死甚至崩溃,不可取。
同时,在异步 JavaScript 代码中调用异步函数也需要小心。虽然异步函数通常会使用 Promise 或回调方式来处理异步操作,并且在执行时不会阻塞 UI 线程,但是在多层嵌套异步调用时,可能会出现回调地狱问题,通过 async / await 方式可以有效解决这个问题。
为了避免上述问题,建议在编写JavaScript 代码时,谨慎考虑同步和异步调用的方式,尽量避免长时间阻塞UI线程,并通过适当的方式来处理异步回调嵌套和错误捕获等相关问题。
13、视频在安卓可以正常播放在 ios 无法正常播放?
视频在安卓可以正常播放而在iOS上无法正常播放,这可能是由于使用了一种不受 iOS 设备支持的视频编解码格式所致。
iOS 上支持播放的视频编解码格式包括 H.264、HEVC(H.265)、MPEG-4 Part 2 和 Motion JPEG 等。而在 Android 上,通常支持更多的视频编解码格式,包括 VP9、AV1 等开源编解码格式。因此,如果使用了 iOS 不支持的视频编解码格式,将导致视频无法在 iOS 设备上正常播放。
为了确保视频能够在所有设备上正常播放,建议尽可能使用受广泛支持的视频编解码格式。如果需要使用某些特定编解码格式,则需要进行额外处理,例如,在视频上传时,将其转换为不同的格式以适应不同的设备。
同时,也可以考虑使用跨平台的视频播放库,例如 Video.js 或 Jwplayer 等,它们通常会自动检测设备并使用相应的编解码格式进行播放,从而最大限度地提高视频的兼容性。
14、前端 如何对后台接口进行封装
在前端进行后台接口封装可以提高代码的可读性、稳定性和重用性,同时也能更好地维护后台接口,降低与后端的耦合度。以下是一些推荐的封装方式:
1。封装 Ajax 请求函数:将常见的 Ajax 请求封装成函数,在函数内部处理请求、响应错误和数据转换等逻辑,以减少冗余代码和复杂度。
2。封装 API 接口对象:将后端 API 接口封装到一个对象中,每个接口用一个方法表示,并统一处理请求和响应。这种方式方便集中管理所有 API 接口,易于调用和测试。
3.封装数据模型类:将后端的接口数据结构封装为一个前端数据模型类,提供相应的方法进行数据操作和业务处理。这种方式可以有效抽象出基础业务逻辑和处理过程,并实现数据缓存、数据加工等功能。
4.中间件封装:使用中间件框架如 axios-interceptors 等,对 HTTP 请求和响应进行拦截和处理,实现许多共同的需求,例如鉴权、数据缓存和统一错误处理等。
5.Hook 封装:使用 React 的 Hook 监听组件生命周期或者自定义 Hook,对接口进行处理,使 Hooks 像普通函数一样调用接口,并且 Hooks 也可以处理接口并返回值。
15、promise 原理
Promise 是 ES6 新增的一种异步编程方式,它是一种对象,用于表示异步操作的最终完成(或失败)及其结果值。Promise 的核心理念是将异步操作放入 Promise 中,并返回一个代表着该异步操作结果的 Promise 对象,以便在异步操作完成时进行处理。
Promise 的基本原理如下:
Promise 对象有三种状态:pending、fulfilled 和 rejected。初始状态为 pending,待执行完成后会变成 fulfilled(已解决)或 rejected(已拒绝)。
Promise 对象通过 then 方法注册回调函数,当异步操作执行完毕后通过 resolve 方法或 reject 方法确定最终状态,并将结果作为参数传给回调函数。
then 方法可以链式调用,每个 then 方法中的回调函数都会接受上一个 then 方法中回调函数返回值作为参数。
如果在 Promise 构造函数中发生错误,Promise 对象就会立即进入被拒绝(rejected)状态,并且抛出异常。
基本语法:
js
new Promise((resolve, reject) => {
// 执行异步操作
if (/* 异步操作成功 */) {
resolve(result); // 将结果传递给回调
} else {
reject(error); // 将错误信息传递给回调
}
}).then(result => { // 注册回调函数
// 处理异步操作成功后的结果
}).catch(error => { // 捕捉 Promise 抛出的异常
// 处理异步操作失败后的错误
});
该 Promise 对象会调用一个函数,该函数有两个参数:resolve 和 reject。执行结果成功时调用 resolve 方法将结果传递给 then 函数回调,执行结果失败调用 reject 方法向 catch 函数传递错误信息。then 函数中接收到上一个 promise 函数的执行结果,回调处理该结果,catch 函数接收前面抛出的错误,并进行处理。
以上方式都能有效封装前端与后端之间的接口,提升开发效率与维护便利性,根据实际项目需求进行选择即可。
16、uniapp 如何自动化打包
UniApp 提供了通过命令行自动化构建打包的方式。具体步骤如下:
1.在项目根目录下,使用命令行进入到 HBuilderX 安装目录中的 uni-cli/bin 目录下。
2.运行以下命令行,安装打包所需依赖:
npm install
3.在 uniapp 项目目录下,修改 package.json 文件的 scripts 字段,添加如下脚本代码:
“scripts”: {
“build:h5”:“cross-env NODE_ENV=production uni-build --h5”
}
4.修改完 package.json 后,在命令行运行以下命令:
npm run build:h5
此时会在项目根目录的 dist 目录下生成 h5 平台所需的文件。其它平台的操作方法与 h5 平台类似,在 scripts 中添加对应的命令即可。
需要注意的是,在使用自动化构建打包前,需要先进行配置相关打包参数等内容,例如 app 配置及 manifest.json 配置等。此外,若需要生成离线包,则需要在 HBuilderX 的菜单栏中选择 「发行」-「云端打包」,登录后按照页面的提示操作即可。
17、微信小程序凭证?
在微信小程序中,每个小程序必须拥有自己的 AppID 和 AppSecret,这两个参数被称为小程序的凭证,用于进行认证和接口调用。
*AppID:是一个字符串,是小程序的唯一标识符,与开发者帐号相关联。
*AppSecret:是一个字符串,是小程序的加密密钥,与App ID相关联。App Secret用来进行小程序后端的身份验证,如果泄露此密码,可能会导致恶意用户获取您小程序的数据或者搞乱各种API等操作。
AppID 是小程序的唯一标识符,可通过微信公众平台申请获得。而 AppSecret 则是用于对接口进行签名的密钥,需要开发者在开发者中心中手动设置。
在使用微信小程序的开放接口时,需要使用小程序的凭证进行接口调用,同时还需要针对不同的接口填写相应的参数。具体接口调用方法可以参考微信小程序开发文档,文档中提供了详细的接口说明和调用示例。
18、公众号怎么实现微信支付
要在公众号中实现微信支付,需要进行以下步骤:
1.在微信商户平台注册账号并进行实名认证,获取商户号和密钥等信息。
2.使用商户号和密钥申请微信支付接口的api密钥和证书。
3.在公众号开发者后台中,设置支付授权目录和JSAPI支付安全域名,并开通JSAPI支付功能。
4.实现支付功能:使用微信支付接口的统一下单 API,向微信支付服务器发起请求获取预支付交易会话标识(prepay_id)。
5.客户端调用JSAPI方法,拉起微信支付界面,用户确认支付后完成支付过程。
具体的步骤和操作细节可以参考微信官方文档中提供的支付接口开发指南,以及相关的示例代码和接口文档。在实现支付功能时还需要注意数据加密和处理异常情况等问题。另外建议开发者严格按照微信支付平台的标准接入流程进行开发和测试,并在审核前仔细检查相关功能是否符合规范要求。
19、前端 实现支付宝支付
在前端实现支付宝支付,需要进行以下步骤:
1.在支付宝开发者平台创建应用并进行认证,获取应用ID和密钥等信息。
2.采用支付宝提供的SDK或接口,将应用与支付宝账号关联。
3.实现支付功能,使用支付宝提供的统一收单下单并支付页面接口,向支付宝服务器发送下单请求,并获得一个唯一的订单号和支付宝跳转链接。
4.将跳转链接进行二维码生成或者页面渲染,展示给用户以完成支付过程。
具体的步骤和操作细节可以参考支付宝官方文档中提供的支付接口开发指南,以及相关的示例代码、接口文档。在实现支付功能时还需要注意数据加密和处理异常情况等问题。另外建议开发者严格按照支付宝平台的标准流程进行开发和测试,并在审核前仔细检查相关功能是否符合规范要求。
20、前端如何识别 后端返回链接 是否是图片
- 前端可以通过以下方式判断后端返回的链接是否是有效的图片链接:
利用JavaScript的Image对象进行预加载,如果加载成功,则说明该链接是有效的图片链接。
function checkImage(url, success, error) {
var img = new Image();
img.onload = success;
img.onerror = error;
img.src = url;
}
checkImage(‘https://example.com/image.jpg’, function() {
console.log(‘Valid image URL’);
}, function() {
console.log(‘Invalid image URL’);
});
2.判断链接是否以常见的图片格式结尾,例如.jpg、.png、.gif等。
function isImageUrl(url) {
return (url.match(/\.(jpeg|jpg|gif|png)$/) != null);
}
console.log(isImageUrl(‘https://example.com/image.jpg’)); // true
以上两种方式都可以判断链接是否是有效的图片链接,同时建议在展示图片前对数据进行合法性检查和类型判断。另外需要注意的是,由于网络原因或服务器问题等,链接可能会返回404或其他错误码,因此就算链接是有效的图片链接也不能100%保证一定能够展示出来,请开发者在使用时进行细致的测试和异常处理。
21、前端怎么解决页面白屏
检查网络连接是否正常,确保 CDN 或静态资源能够正常加载。
检查代码中是否有语法错误、逻辑错误或其他代码问题,可以使用开发者工具进行调试,并检查控制台报错信息。
确认浏览器版本是否支持所使用的技术,如是否支持 ES6、CSS Grid等。如果不支持,建议降级或用 polyfill 处理。
预加载相关资源,例如预加载 HTML、CSS、JS 文件。
将关键 CSS 和 JS 文件放在 head 标签中,以便在文档加载时就能够渲染。
合理、简化页面结构和样式,尽量减少 HTTP 请求次数和响应容量。
使用浏览器工具对页面加载过程进行分析,找到具体瓶颈并进行优化。
22、dom树加载机制
DOM(文档对象模型)树是浏览器解析 HTML 文档后所形成的一种树形结构,表示页面中所有 HTML 元素及其层级关系。浏览器在加载页面时会先经过以下阶段:
解析 HTML 文件:当浏览器请求一个 HTML 页面时,它会读取并解析文件内容,构建出 DOM 树。
构建 DOM 树:解析 HTML 文件时,遇到标签、属性和文本节点等元素,都会在内存中创建相应的节点对象,并按照层级关系构建 DOM 树,节点对象具有父子关系,DOM 树是由多个节点所组成的树形结构。
生成 Render Tree:浏览器在解析 DOM 树时,会将 CSS 样式与每个节点(除非该节点对应的 CSS 尚未下载)结合起来,生成一个带有样式信息的 Render 树,该树表示了网页的渲染结构。
布局(Layout):最终的Render树事先排版布局,即确定每个节点在屏幕上的准确位置和大小。同时,还需要确定节点的颜色、字体、边框、背景色、图像等外观效果,以便后续的绘制工作。布局过程会根据盒模型、文档流等特性进行计算。
绘制(Painting):在已经确定好的节点位置上进行绘制,即显示出文本、图片、背景等视觉效果。
以上就是浏览器加载页面时DOM树的加载机制涉及的一系列流程和步骤。
23、前端页面渲染机制
前端页面渲染机制主要涉及的是浏览器如何对网页进行解析、构建和渲染的过程。具体来说,它通常包括以下几个阶段:
构建 DOM 树:当浏览器接收到 HTML 页面时,会按照标签的层次关系依次解析文件内容,并根据标签生成对应的 DOM 元素节点。
解析 CSS 样式:在 CSS 阶段中,浏览器会处理样式表信息,解析出每个元素所对应的应用样式,并将其合并组成一个规则列表。
生成 Render 树:Render 树是一个包含每个节点和其对应样式属性信息的树形结构,与 DOM 树类似。它的每个节点都代表了文档中相应的可视化元素。
布局(Layout):在 Render 树构建完成后,浏览器会进入布局阶段,计算出每个节点的位置和尺寸信息,并确定它们在屏幕上的呈现方式。
绘制(Painting):布局完成后,浏览器就可以进入绘制阶段,将页面内容绘制到屏幕上。
总的来说,浏览器在渲染页面时,会从 DOM 树、CSS 样式、JavaScript 脚本等多个方面对页面进行处理。在实际应用中,为了提高页面的性能,还需要注意避免网络请求、资源重复加载等问题。
25、介绍下http\https 协议
HTTP(Hypertext Transfer Protocol)是一种应用层协议,它是 Web 技术的基础之一。通过 HTTP 协议,客户端和服务端之间可以有效地传输数据和通信。HTTP 协议支持多种请求方法,如 GET、POST 等,同时还定义了可接受的请求头域以及状态码等规范。
HTTPS(HyperText Transfer Protocol Secure)是在 HTTP 协议之上添加了加密和认证机制的协议。在 HTTPS 中,服务器需要使用 SSL 或 TLS 协议对数据进行加密处理,并通过数字证书验证身份,保证服务器和客户端之间的通信安全性。
具体来说,简单介绍一下 HTTP 和 HTTPS 的区别:
安全性:HTTP 是明文传输协议,不提供任何加密方法。而 HTTPS 利用加密技术保证信息传输过程中的机密性和完整性,更为安全。
数据传输方式:HTTP 以明文方式传输数据,所有数据都可以在网络上被监听和窃取。而 HTTPS 则通过 SSL/TLS 加密来保障数据的安全传输。
默认端口:HTTP 默认使用端口号为80,HTTPS 默认使用端口号为443。
证书要求:HTTPS 涉及到证书的验证和签发,在使用 HTTPS 前需要申请SSL证书,并且要求使用 HTTPS 的网站必须拥有有效的数字证书。
综上所述,HTTP 协议是一种常用的协议,在访问普通网站的过程中使用较多;而对于数据传输要求更高、安全性更为重要的网站,则选择使用 HTTPS 协议。
26、get、post怎么传参
无论是 GET 还是 POST 请求方式都可以通过参数来传递数据。一般来说,GET 请求方式适合请求简单的数据,而 POST 适合提交复杂数据或者包含文件上传等操作。
GET 请求方式传参 在 GET 请求方式中,参数一般写在 URL 的末尾,使用 ? 来分隔 URL 和参数,多个参数之间使用 & 符号来连接。例如:
http://example.com/path/to/file?key1=value1&key2=value2
在实际代码中,可以使用 JavaScript 中的 fetch 函数(客户端)或者 PHP 中的 $_GET (服务端获取 GET 参数)进行数据的传递和获取。
POST 请求方式传参 在 POST 请求方式中,参数不会跟在 URL 后面像 GET 方式一样,而是作为数据在请求体中进行提交。提交的数据可以是字符串、JSON 对象、FormData 对象等。例如:
const data = {
key1: ‘value1’,
key2: ‘value2’
};
fetch(‘http://example.com/path/to/file’, {
method: ‘POST’,
body: JSON.stringify(data),
headers: {
‘Content-Type’: ‘application/json’
}
})
在 PHP 中,可以使用 $_POST (服务端获取 POST 参数) 或 file_get_contents(‘php://input’) 等方法获取 POST 数据。
需要注意的是,GET 方法提交的数据长度有限制,且数据会直接暴露在 URL 上,不适合传输敏感信息;而 POST 方法提交的数据可以存储大量数据,也更为安全,但是需要服务器进行处理。因此,在实际开发中,需要根据具体情况合理选择 GET 或 POST 方式来传递参数。
27、2023/6/8 20:30:09
vuex 数据传参导致白屏
Vuex 是 Vue.js 的一个状态管理库,主要用于 Vue 应用中的数据共享问题。Vuex 存放在集中式存储中的状态是响应式的,能够做到在组件间传递和共享数据。
关于你提到的“Vuex 数据传参导致白屏”的问题,可能存在以下原因:
Vuex 数据传递出现了循环依赖,导致系统进入死循环,最终导致白屏。可以通过检查数据流向来判断是否有这种情况。
在使用 Vuex 进行数据传递时,没有及时调用异步操作需要的命令,导致白屏。这种情况下需要检查代码,确保异步操作的正确执行。
由于异步操作或其他原因,Vuex 中的数据未成功加载,但系统却尝试渲染视图,导致出现白屏。此时需要确保数据正常加载以后再进行视图渲染。
针对以上问题,可以针对具体的情况分别处理。例如,在处理循环依赖的问题时,可以修改代码结构、减少数据依赖关系等方式来解决;在处理异步操作相关问题时,需要仔细考虑应该何时调用异步操作,并且要编写良好的错误处理机制,避免出现无法处理的异常情况;对于数据加载问题,可以使用 Vue.js 提供的生命周期函数来确保数据加载完成后再进行视图渲染。
28、WebSocket 线程过多,通常是因为服务器无法在实时处理所有客户端请求所致。想要解决这个问题,可以尝试以下几种方法:
-
调整 WebSocket 同时连接的数量限制:我们可以调整 WebSocket 的同时连接数。例如,如果服务器只支持 1000 个连接,并且正在处理第 1001 个连接,则新的连接会被拒绝。通过调整同步连接数的限制,可以降低线程并发量和资源消耗。
-
根据消息的价值和重要性进行数据分类和筛选:服务器可以根据不同类型的消息内容,将其分配到不同的线程中进行处理,以避免单一线程处理太多数据导致负载过大。这可以通过使用消息队列等技术实现。
-
水平扩展服务器:如果以上两种方法无法解决问题,则可以使用水平扩展服务器的方法来增加系统的集群节点。这种方法可以通过添加更多服务器同时处理客户端请求来提高服务器的吞吐量和并发性能。
总之,处理 WebSocket 过多线程的方法有很多,具体取决于您的应用场景和实际需求。
29、在 Canvas 中处理音频通常需要结合 Web Audio API 来实现。Web Audio API 是一个用于处理和控制音频的高级 API,它提供了许多函数和接口,可以很容易地在 JavaScript 中创建音频模型并控制其行为。
下面是展示如何使用 Web Audio API 在 Canvas 上处理音频的基本步骤:
-
加载音频文件:使用 JavaScript 的 Audio 对象来加载音频文件。
-
创建音频上下文对象:创建一个 AudioContext 对象。该对象将被用于从音频文件中读取数据并传递到 Web Audio API。
-
解码音频数据:调用 AudioContext 对象的 decodeAudioData() 方法解码音频数据。
-
创建音频节点:根据需要创建各种类型的音频节点,例如 SourceNode、GainNode、DestinationNode 等。节点将构成一个音频处理图谱,每个节点都会执行一些特定的音频操作。
-
将音频节点连接起来:使用 connect() 方法将音频节点与其他节点连接起来形成所需的音频处理图谱。由此形成的处理图可以通过简单的组合来实现从音频文件读取数据并对其进行处理。
-
开始播放音频:调用 start() 方法启动音频轨道中的播放或停止音频播放 。
在 Canvas 中处理音频的能力不仅限于上述步骤。实际上, Canvas 有一些内置功能可用于处理和操作音频,例如使用图形来控制音频播放、操纵声音的可视化效果和创建有趣的交互式体验。具体取决于您的需求和想要实现的功能。
30、
想要在 Webpack 中配置 rem,可以采用以下步骤:
- 安装 postcss-loader 和 postcss-pxtorem 插件
在终端中输入以下命令安装相关插件:
npm install postcss-loader postcss-pxtorem -D
- 配置 postcss-loader
在 webpack.config.js 文件中的 module.rules 数组中添加 postcss-loader,如下所示:
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
}
};
- 配置 postcss-pxtorem
在项目根目录创建 postcss.config.js 文件,并配置 postcss-pxtorem 插件,如下所示:
module.exports = {
plugins: [
require('postcss-pxtorem')({
rootValue: 75, // 根字体大小
propList: ['*'], // 全部选择器都需要转换
mediaQuery: false // 是否开启媒体查询模式
})
]
};
- 设置 HTML 文档的 font-size
在 index.html 的 head 标签内设置 HTML 文档的 font-size,如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Webpack Project</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<style>
html {
font-size: 100px; /* 此处设置为100px,与 rootValue 相同 */
}
</style>
</head>
<body>
<!-- ... -->
</body>
</html>
最后,重新运行 Webpack 即可实现在 CSS 中使用 rem。
31、
为了解决样式兼容问题,可以考虑在 Webpack 中配置 PostCSS 插件 Autoprefixer,它可以自动添加浏览器前缀,从而简化前端编写 CSS 样式时的兼容性处理工作。
使用 Autoprefixer 需要以下步骤:
- 安装 postcss-loader 和 autoprefixer
执行以下命令来安装所需依赖:
npm install postcss-loader autoprefixer -D
- 在 webpack.config.js 配置文件中添加 loader
在 module.rules 数组中添加处理 CSS 文件的 loader,连同 Autoprefixer 插件一起使用。下面是示例代码:
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')]
}
}
]
}
]
}
};
- 在 package.json 文件中添加 browerslist 配置
建议将 Autoprefixer 和 Babel 一起配合使用来兼容更多 JavaScript 特性和一些旧版浏览器。将目标浏览器放在项目根目录的 package.json 文件的 browserslist 配置项中。例如:
"browserslist": [
"> 1%",
"last 2 versions"
]
这条指令的意思是我们需要支持全球占有率 1% 及以上的浏览器,并且支持最新的两个主要浏览器版本。
经过上述步骤,就完成了 Autoprefixer 的配置。在接下来开发和打包过程中,Autoprefixer 将自动解析 CSS,并根据你的 browserslist 配置添加相应的前缀,从而帮助解决跨浏览器兼容性问题。
32、
Vite 是 Vue.js 创始人尤雨溪开发的一款面向现代浏览器的轻量级前端开发服务器和构建工具。它提供了快速的冷启动,内置开箱即用支持 Vue 单文件组件 (SFC) 的 devServer,并能够在开发期间基于 ES Module 进行非常快速的模块热更新 (HMR),从而解决了 Webpack 打包重启时间过长的问题。
下面是 Vite 的主要特点:
-
快速冷启动:通过 ES Module 的特性,在服务启动时只需要编译当前需要的文件,而不需要像 Webpack 那样一次性编译整个项目,从而提升了冷启动速度。
-
实时模块热替换:基于 Vue 3 的 Reactivity API 实现,可以更精准地定位需要替换的模块,同时也提供了对 CSS 和自定义模块类型的支持,可以加快前端开发的速度。
-
内置优化插件:通过内置的预处理插件以及针对生产环境的打包优化,可以帮助用户轻松地实现优化产品代码的目的。
-
零配置:默认配置下就可以直接使用,无需进行额外的配置。
-
可扩展性:Vite 提供了 API 和插件体系,方便用户根据需求扩展、优化相关功能。
使用 Vite 可以轻松实现项目开发和构建,其兼容多种框架 (Vue / React / Preact / LitElement),支持 TypeScript、SCSS、LESS 等多个前端开发技术栈,并且提供了快速开发、更佳的开发体验和更快的构建效率。
33、vite 的基本使用
使用 Vite 是非常简单的,下面介绍如何使用 Vite 来搭建 Vue.js 应用程序。
- 安装
首先需要全局安装 @vite/cli:
npm install -g vite 或者 yarn global add vite
- 创建项目
使用以下命令创建一个新的 Vue 项目:
npm init vite-app my-project 或者 yarn create vite-app my-project
- 安装依赖
进入项目目录并安装依赖:
cd my-project
npm install 或者 yarn
- 运行项目
执行以下命令运行项目:
npm run dev 或者 yarn dev
然后打开浏览器访问 http://localhost:3000 即可查看应用程序。
- 构建项目
使用以下命令构建项目:
npm run build 或者 yarn build
构建完成后,所有打包好的文件都会生成在 dist 目录下。
以上就是使用 Vite 搭建 Vue.js 应用程序的基本流程。同时 Vite 也支持其他前端框架,只需按照相应文档进行相应设置即可。
34、vue 的 object.prototype 为什么监听不到数组 (对象) 里面变化?
Vue 在实现数据双向绑定时,使用了 Object.defineProperty() 方法来为对象上的属性添加 getter 和 setter,从而实现数据响应式。
但是,Object.defineProperty() 方法只能劫持对象的属性,而不能劫持整个对象或数组。这就意味着当你改变数组中的某一个元素时,它是不会触发响应式更新的,因为 Vue 并没有劫持数组元素本身的 setter。
由于数组是一种比较特殊的对象类型,在 JavaScript 中,最好使用 Array 类型提供的方法对其进行操作。这些数组的方法可以触发响应式更新,例如 push、pop、splice 等等。所以推荐在 Vue 中,我们尽量使用这些数组方法来修改数组中的元素,从而保证数据响应式。
总结一下,Vue 监听不到对象里面的数组变化,是因为 Object.defineProperty() 方法只能劫持对象的属性,而不能劫持整个对象或数组,但是 Vue 提供了一些数组的方法,可以触发响应式更新。因此,我们在Vue使用中,建议使用这些数组方法来修改数组中的元素。
35、那在vue中怎么做到监听数组 (对象) 里面变化呢?
在 Vue 中,要监听数组内部元素的变化,可以使用一个名为 Vue.set 或者 this.$set 的方法来实现。这个方法会将新增的元素转换为响应式数据,并触发界面的重新渲染。
Vue.set(obj, propertyName/index, value) 方法接收 3 个参数:
- obj:需要被添加属性的对象或数组
- propertyName/index:需要添加的属性名或索引值
- value:新添加的属性值
例如:
// 数组增加元素
this.$set(this.itemList, 1, newItem);
// 对象增加属性
this.$set(this.userInfo, 'name', '张三');
除此之外,Vue 还提供了一种 Watch 深度监测的方法,即开启深度监测。开启后,当你改变对象或数组中的属性时,Vue 将递归地遍历对象以追踪所有属性,并绑定Getter和Setter。这个选项默认关闭,由于其性能影响,我们不应该在所有属性都需要检测的情况下开启它,仅在必要时才考虑使用。开启方式如下:
var vm = new Vue({
data: {
users: [{ id: 0, name: 'Peter' }]
},
watch: {
users: {
deep: true,
handler: function(newUsers, oldUsers) {
console.log('users changed!')
}
}
}
})
代码中的 { deep: true } 表示开启深度监测,handler 函数会在 users 数组发生变化时被调用。
总之,使用 Vue.set 和深度监控可以实现数组(对象)的监听,但是开销比较大。建议尽量使用数组提供的方法来代替直接对数组进行操作,以获得更好的性能和用户体验。
35、路由 history 原理,服务端如何配置?
路由 history 模式通过 HTML5 的 History API 实现,它使用 window.history.pushState() 方法动态改变浏览器的当前 url,同时也是监听 popstate 事件来更新页面视图。
与 hash 模式不同,history 模式可以更改 URL 中的 pathname 和 search 字段,而不会在最后添加一个 # 符号。例如,对于 URL http://example.com/path/user,如果用户点击了链接/update,浏览器将会发送一个跳转请求,并把显示路径更改为 http://example.com/path/update。
服务端需要根据实际情况进行配置。当在服务端启用历史模式时,任何链接都应指向主页。否则,当用户在浏览器中输入 URL 时,服务器将返回 404 错误,这是因为服务端不知道如何处理该 URL。
配置方式分为以下两种:
- 使用服务器框架。如果在使用一些服务器框架(例如 Express)来构建你的应用程序,则需要捕获到所有的路由并渲染 index.html 文件。这个文件将包含您的应用程序,当应用程序启动时,它将自动渲染正确的组件作为响应。
const express = require('express')
const path = require('path')
const app = express()
app.use(express.static(path.resolve(__dirname, 'public')))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
app.listen(3000)
- 配置 Nginx 服务器。另一种是使用 Nginx 或其他支持 Rewrite 规则的 web 服务器来配置。
location / {
try_files $uri /index.html;
}
以上示例是在 Nginx 配置文件中添加了一个转发规则,将所有请求重定向到 index.html 文件并让 Vue Router 接管路由。
总之,路由 history 模式通过 HTML5 的 History API 实现,它可以更改 URL 的 pathname 和 search字段。服务端需要根据实际情况进行配置,比如使用服务器框架或 Nginx 等服务器,以捕获到所有的路由并渲染 index.html 文件,并让 Vue Router 接管路由。
36、关于 Tree.js 的教程,以下是一个基本的介绍:
安装和引入 Tree.js 库:
首先需要安装 Tree.js 库并将其引用到你的网站上。可以在官方网站下载最新版的库文件或者使用 NPM 安装,然后在 HTML 页面中添加引用。
创建渲染器(Renderer) 和场景(Scene) 对象:
使用 Tree.js 创建一个 Renderer(渲染器)对象,这个对象将负责把 3D 场景布置在浏览器中。同时创建一个 Scene(场景)对象作为一个容器,把所有需要呈现的 3D 对象都放在其中。
添加相机(Camera):
添加 Camera(相机)对象即可确定场景视角。将相机放置在一个合适的位置以便捕捉想要呈现的场景。
创建和添加几何图形(Geometry):
Tree.js 提供了许多内置几何模型类,例如 BoxGeometry(立方体几何)、SphereGeometry(球体几何)等,您也可以使用自定义几何模型。然后可以使用材质来设置图形的颜色纹理等。
光源和阴影:
在 Tree.js 中,有不同类型的光源,包括环境光、点光源、半球光、方向光、聚光等。在场景中添加适当的光源可以增强图形的真实感,并且还可以使用阴影,让图形看起来更加立体。
动画和交互:
Tree.js 支持各类交互和动画行为,例如旋转、移动、缩放、改变颜色等。同时,还支持事件处理程序,可以监听用户输入、键盘等。
渲染:
最后,调用 Renderer 对象的 Render 方法即可将整个 3D 场景内部渲染出来。
这里只是对 Tree.js 的一个简单介绍,想要深入学习还需要参考相关文档和示例代码。
步骤:
Tree.js 是一个基于 WebGL 的 3D 图形开发的 JavaScript 库。它提供了丰富的工具和函数,使您可以轻松地创建复杂的动画和交互式 3D 应用程序。下面是 Tree.js 的详细教程:
- 安装和引入 Tree.js
首先,在 HTML 文件中引入 Tree.js 库
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
如果您的项目使用 npm 包管理器管理依赖,也可以通过以下命令安装 Three.js:
npm install three
然后在你的项目中,以如下方式引用:
import * as THREE from 'three';
- 创建场景
在开始创建 3D 场景之前,需要先初始化一个 Scene
对象,指定背景颜色等属性。
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf4f6f9);
- 添加相机
相机是观察者看到 3D 场景的窗口。在 Three.js 中有许多类型的相机,例如透视相机、正交相机等,可以根据需求选择一个合适的相机。
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
// 或者使用 OrthographicCamera:
const camera = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, 1, 1000);
camera.position.set(0, 0, 5);
- 添加渲染器
渲染器负责通过 WebGL 技术将场景呈现到作为 HTML 元素的画布中。
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement); // 将 canvas 元素添加到 document.body 中
- 添加几何体和材质
在 Three.js 中创建 3D 对象需要使用 Geometry
(几何体)和Material
(材质),它们决定了对象的形状和外观。
// 创建立方体几何体和基本红色材质
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// 创建网格对象
const cube = new THREE.Mesh(geometry, material);
// 将网格对象添加到场景中
scene.add(cube);
- 添加光源
当场景变得复杂
37、v-model 指令的修饰符
.nummber 自动将用户的输入值转为数值类型
.trim 自动过滤用户输入的首民空白字料
.Lazy 自动过滤用户输入的首民空白字料
38、小程序代码的构成
pages 用来存放所有小程序的页面9
utils 用来存放工具性质的模块 (例如:格式化时间的自定义模块)
app.js 小程序项目的入口文件
app.json 小程序项目的全局配置文件
app.wxss 小程序项目的全局样式文件
project.config.json 项目的配置文件
sitemap.json 用来配置小程序及其页面是否允许被微信索引
39.小程序页面的组成部分
小程序官方建议把所有小程序的页面,都存放在 pages 目录中,以单独的文件夹存在
其中,每个页面由 4 个基本文件组成,它们分别是:
1、js 文件 (页面的脚本文件,存放页面的数据、事件处理函数等)
2、 json 文件(当前页面的配置文件,配置窗口的外观、表现等)
3、.wxml 文件(页面的模板结构文件)
4、.wxss 文件(当前页面的样式表文件)
能够使用WXML模板语法染页面结构
wx:if、wx:elif、wx:else、hidden、wx:for、wx:key
能够使用wXSS样式美化页面结构
rpx 尺寸单位、@import 样式导入、全局样式和局部样式
@能够使用 app.json 对小程序进行全局性配置
pages、window、tabBar、style@
能够使用 page,json 对小程序页面进行个性化配置
对单个页面进行个性化配置、就近原则
能够知道如何发起网络数据请求
wx.request() 方法、onLoad()事件
40、微信小程序开发流程:
注册小程序账号:在微信公众平台注册一个小程序账号,注册完成后,可以获取到 AppID 和 AppSecret,这是后续开发的必备信息。
创建小程序项目:使用微信开发者工具创建一个新的小程序项目,填写小程序的名称、AppID 等基本信息,并选择对应的开发语言(小程序支持多种语言开发)。
开发页面:在微信开发者工具中开发小程序页面,包括页面的布局、样式、交互逻辑等。
开发接口:在服务器端开发小程序需要的接口,比如获取数据、提交表单等功能。
测试和调试:开发完成后需要进行测试和调试,确保功能正常。
提交审核:当开发完成后,需要提交审核,经过审核后即可发布到小程序平台供用户使用。
公众号网页开发流程:
注册公众号账号:在微信公众平台注册一个公众号账号,注册完成后,可以获取到 AppID 和 AppSecret,这是后续开发的必备信息。
开发网页:在本地开发网页,包括页面的布局、样式、交互逻辑等。
接入微信JS-SDK:通过引入微信JS-SDK,可以在网页中调用微信的API,比如获取用户信息、分享等。
进行网页授权:通过网页授权,可以获取用户的微信身份信息,实现个性化的功能。
部署网页:将网页部署到服务器上,并配置服务器地址、令牌(Token)、消息加密密钥(EncodingAESKey)等信息。
验证服务器:配置完成后,微信公众平台会向服务器发送一个验证请求,需要在服务器中进行验证,并返回验证信息。
测试和调试:部署完成后需要进行测试和调试,确保功能正常。
提交审核:当开发完成后,需要提交审核,经过审核后即可发布到公众号中供用户使用。
总体来说,微信小程序开发和公众号网页开发都需要涉及多个方面,包括前端、后端、数据库等,需要开发者具备一定的技术能力和经验。同时,还需要对微信公众平台的规则和限制有一定的了解,确保开发的功能符合相关要求。
41、Vuex:
每一个?Vuex?应用的核心就是?store(仓库),它包含着你的应用中大部分的状态?(state)。 状态管理有5个核心:state、getter、mutation、action、module。
State 1、单一状态树,定义应用状态的默认初始值,页面显示所需的数据从该对象中进行读取。 2、Vuex?使用单一状态树,用一个对象就包含了全部的应用层级状态。它便作为一个“唯一数据源”而存在。这也意味着,每个应用将仅仅包含一个?store?实例。 3、单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。 4、不可直接对?state?进行更改,需要通过?Mutation?方法来更改。 5、由于?Vuex?的状态存储是响应式的,从?store?实例中读取状态最简单的方法就是在计算属性中返回某个状态:
Getter 1、可以认为是?store?的计算属性,对?state?的加工,是派生出来的数据。 2、就像?computed?计算属性一样,getter?返回的值会根据它的依赖被缓存起来,且只有当它的依赖值发生改变才会被重新计算。 3、可以在多组件中共享?getter?函数,这样做还可以提高运行效率。 4、在?store?上注册?getter,getter?方法接受以下参数: state,?如果在模块中定义则为模块的局部状态 5、getters,?等同于?store.getters
Mutation 1、Vuex中store数据改变的唯一方法就是mutation 2、通俗的理解,mutations?里面装着改变数据的方法集合,处理数据逻辑的方法全部放在?mutations?里,使数据和视图分离。
Action action?类似于?mutation?,不同在于: 1、action?提交的是?mutation,通过?mutation?来改变?state?,而不是直接变更状态。 2、action?可以包含任意异步操作。
Module 1、由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store?对象就有可能变得相当臃肿。 2、为了解决以上问题,Vuex?允许我们将?store?分割成模块(module)。每个模块拥有自己的?state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
42、Vuex
四大核心属性,以及一个子模块管理属性,state存放数据,Mutations同步修改state里面的数据,actions异步修改数据,但需要调用Mutations里面的方法修改,getters数据过滤器,对数据进行整理,还有一个modules,当数据过多和复杂时,将数据用模块化分开,在住文件中用modules引用
Leon:
简单回答
store,存储变量 mutation,发起变量更改,记录更改 action,发起异步变量更改,记录更改 getter,计算属性 module,模块划分
43、浏览器中的Event Loop是什么,它有什么作用?
答案:Event Loop是浏览器提供的一种机制,用于执行JavaScript代码。它主要作用在于监听任务队列,将其中挂起的任务分配到可用的线程上去执行。
44、请简述HTML5中nav标签的作用。
答案:nav标签用于定义导航栏,通常包含一个或多个链接,用户通过点击这些链接可以跳转到不同的页面或功能。
45、在Vue.js中,computed与watch有什么区别?
答案:computed属性会在其依赖数据发生改变时自动更新,而watch则需要手动监听数据的变化。computed适用于处理复杂的计算,并且数据源发生变化时需要经过一些额外的操作;而watch则适用于监听某个特定数据的变化,并且需要执行一些副作用操作(如发送网络请求)。
46、请简述React中Virtual DOM的作用。
答案:Virtual DOM是React中的一种机制,它是一个轻量级的JavaScript对象,用于表示真实DOM节点的结构。由于Virtual DOM比真实DOM更容易操作和修改,所以React会首先对Virtual DOM进行操作并计算出最小变化集合,然后再将这些变化同步到真实DOM节点上,从而减少不必要的页面重绘。
47、如何在JavaScript中判断一个变量是否是数组?
答案:可以使用Array.isArray()方法来判断一个变量是否是数组类型:
复制代码
var arr = [];
if (Array.isArray(arr)) {
console.log("arr is an array");
}
48、简述ES6中let和const关键字的作用及区别。
答案:let和const都是块级作用域的声明方式,用于替代var关键字。它们的主要区别在于const声明的变量必须被初始化,并且在后续的操作中不能被重新赋值;而let声明的变量则可以被重新赋值。
49、在JavaScript中,如何遍历一个对象的属性?
答案:可以使用for-in循环来遍历一个对象的所有可枚举属性:
复制代码
var obj = {a: 1, b: 2, c: 3};
for (var prop in obj) {
console.log(prop + ": " + obj[prop]);
}
50、请简述React中props与state的区别。
答案:props和state都是React组件中用于存储组件数据的属性,但它们的作用略有不同。props通常是由父组件向子组件传递的静态数据,子组件无法修改它们,只能读取。而state则是组件内部维护的动态数据,只能通过setState()方法来修改,但这些修改会触发组件的重新渲染。
51、如果希望在React应用中使用Ajax请求,请列出至少两种可以实现该功能的库或插件。
答案:常用于在React应用中进行Ajax请求的第三方库包括Axios、jQuery和Fetch等。
52、如何在JavaScript中创建自定义异常?
答案:通过Error对象可以轻松地创建自定义异常,可以像下面这样定义并抛出一个名为"CustomError"的异常:
复制代码
function CustomError(message) {
this.message = message;
this.name = "CustomError";
}
throw new CustomError("Something went wrong");
53、在JavaScript中如何判断一个变量是否为null或undefined?
答案:需要使用“==null”运算符来检测一个变量是否为null或undefined,代码如下:
复制代码
var a;
if (a == null) {
console.log("a is null or undefined");
}
54、如何让一个DOM元素在点击时触发某个事件?
答案:可以使用addEventListener()方法来在DOM元素上注册事件监听器:
复制代码
var btn = document.querySelector("#myBtn");
btn.addEventListener("click", function() {
// do something
});
55、在React中,shouldComponentUpdate()生命周期方法的作用是什么?
答案:shouldComponentUpdate()方法用于控制组件是否需要重新渲染。如果该方法返回false,则React将不会重新渲染该组件,从而提高页面的性能。
56、如何在JavaScript中判断一个变量是否为NaN?
答案:可以使用isNaN()函数来判断一个变量是否为NaN:
复制代码
var num = NaN;
if (isNaN(num)) {
console.log("num is NaN");
}
57、在CSS中,请简述盒模型(Box Model)的概念。
答案:CSS中所有元素都被视为一个箱子,包含content、padding、border和margin四个部分。盒模型通过这四个部分来定义一个元素的大小、边距和边框等属性。
58、请简述React中的组件生命周期。
答案:React中的组件生命周期包括以下几个阶段:
Mounting(挂载):组件被创建并插入到DOM中;
Updating(更新):组件的state或props发生改变,需要重新渲染;
Unmounting(卸载):组件从DOM中移除;
Error Handling(错误处理):组件在渲染期间发生错误,需要进行错误处理。
59、在JavaScript中如何获取当前时间?
答案:可以使用Date对象来获取当前时间,代码如下:
复制代码
var now = new Date();
console.log(now.toDateString());
60、在React中,请简述Refs的作用。
答案:Refs是用于在React组件中获取DOM节点或组件实例的方法。它可以通过React.createRef()方法或回调函数的方式来创建,并且可以在组件中
61、什么是闭包?请举例说明。
答:闭包是指函数与其相关引用环境组合的一种特殊情况。简单来说,就是一个函数能够访问在函数定义时不在其作用域内的变量。例如:
javascript
复制代码
function outerFunction() {
let number = 10;
function innerFunction() {
console.log(number);
}
return innerFunction;
}
let closure = outerFunction();
closure(); // 输出 10
62、如何判断一个变量是否为数组类型?
答:使用Array.isArray()方法。
61、常见的HTTP状态码有哪些?请分别说明各自的含义。
答:常见的HTTP状态码有以下几个:
200 OK 表示请求成功。
201 Created 表示请求成功并创建了新资源。
204 No Content 表示请求成功但无返回内容。
400 Bad Request 表示客户端发送的请求有误。
401 Unauthorized 表示客户端需要身份验证才能访问该资源。
403 Forbidden 表示服务器拒绝提供该资源。
404 Not Found 表示请求的资源不存在。
500 Internal Server Error 表示服务器发生错误。
62、如何检测一个对象是否包含某个属性?
答:使用in运算符或者Object.hasOwnProperty()方法。
63、解释一下JavaScript中的事件循环。
答:事件循环指的是JavaScript在执行代码时处理异步操作的一种机制。当有异步操作时,它们会被放到事件队列中,等待JavaScript引擎空闲时去处理。事件循环由三个部分组成:调用栈、事件队列和微任务队列。当调用栈为空时,JavaScript开始处理事件队列中的事件。处理完每一个事件后,JavaScript还会执行微任务队列中所有的任务。
64、请说明ES6中let和const关键字的区别。
答:let和const都用于声明变量,但是它们之间有几个重要的区别:
let声明的变量可以修改,const声明的变量不能修改。
let声明的变量在同一个作用域内不能重复定义,const声明的变量也不能重复定义,而且一旦赋值就不能改变。
使用let声明的变量没有定义提升,而使用const声明的变量也没有定义提升,并且必须在声明的同时就进行赋值。
const声明的变量必须在初始化时赋值,否则会抛出异常。
65、jQuery中的on()和bind()方法有什么区别?
答:bind()方法是jQuery早期的事件绑定方法,而on()方法是新版jQuery引入的更强大的事件绑定方法。相比之下,on()方法具有以下优势:
on()方法支持多个事件同时绑定到同一个元素上,而bind()方法只能绑定一个。
on()方法可以为后添加的元素绑定事件,而bind()方法不支持这种方式。
on()方法还可以使用命名空间对事件进行管理。
66、JavaScript中的typeof操作符会返回哪些值?请说明各自的含义。
答:JavaScript中的typeof操作符可以返回以下几种值:
“undefined” 表示该变量未定义。
“boolean” 表示该变量是布尔类型。
“number” 表示该变量是数值类型。
“string” 表示该变量是字符串类型。
“object” 表示该变量是对象类型或null类型(注意,null被认为是一个空对象)。
“function” 表示该变量是函数类型。
67、请解释一下浏览器的同源策略。
答:浏览器的同源策略指的是一个网页的脚本只能读取来自同一来源的数据。同源是指协议、域名和端口号都相同。如果两个页面的URL有任何一个部分不同,就会被视为不同源。同源策略的目的是保护用户隐私和安全。
68、请解释一下JavaScript中的this关键字。
答:在JavaScript中,this关键字引用的是当前执行代码所处的上下文对象。具体来说,this指向的是函数调用时的环境,取决于函数的调用方式。如果在全局作用域中使用this,则它会指向全局对象window;如果在独立的函数中使用this,则它会指向全局对象或undefined;如果在对象的方法中使用this,则它会指向该对象;如果使用call、apply或bind方法,可以手动设置this的值。
69、请解释一下JavaScript中的原型继承。
答:JavaScript中的原型继承是通过原型链实现的一种继承机制。每个JavaScript对象都有一个指向另一个对象的内部链接,这个链接就是该对象的原型。如果在对象上访问一个属性或方法时,如果该对象本身不存在该属性或方法,JavaScript会沿着原型链查找,直到找到具有该属性或方法的对象为止。可以使用Object.create()方法来创建一个新对象并将其原型设为某个现有对象。
70、请解释一下CSS中的盒模型。
答:CSS中的盒模型指的是元素在文档流中所占据的空间,包括元素的内容区域、内边距、边框和外边距等。根据标准盒模型和IE盒模型的区别,盒模型可以分为两种不同的模式,即标准(content-box)和IE(border-box)盒模型。标准盒模型计算元素尺寸时不包含内边距和边框的宽度,而IE盒模型将内边距和边框的宽度纳入了元素的尺寸计算。