总共8家的面试题,太常见的就没有写出来,终于是面完了,入职某二线城市一家自研公司,过程坎坷,就不多BB了,文笔不好,那么直接上干货吧,学起来坤友们,不要在面试时露出你的坤坤脚,顺利拿到offer
1.vue2生命周期
四个阶段:
创建 -> 挂载 -> 更新 -> 销毁
2.created->mounted 父子组件执行顺序
父beforeCreate -> 父 created
子beforeCreate -> 子 created
子beforeMount -> 子 mounted
父beforeMount -> 父 mounted
3.H5 和 Css3 的常用Api
Canvas API
Web Workers API
: 允许在后台线程中运行脚本,从而提高应用程序的性能和响应能力。Web Sockets API
: 允许在浏览器和服务器之间进行实时通信,支持全双工通信。Geolocation API
: 用于获取用户的地理位置信息。
CSS3 API:
Transforms Transitions
Animations Flexbox
Grid`
ES6 新特性:
let
和const
箭头函数 模板字符串 解构赋值 默认参数 展开运算符 类和继承 模块化 Promise Generator
4.Promise源码为什么会有三个状态
Promise 对象的三个状态是为了能够更好地处理异步代码避免回调地狱和异常处理的问题,同时提高了代码的可读性、可维护性和可重用性。
- Pending(进行中)
- Fulfilled(已成功)
- Rejected(已失败)
5.闭包
在一个函数内部定义的变量只能在函数内部访问,外部无法访问。但是,如果将这个函数作为返回值返回,或者作为参数传递给另一个函数,那么这个函数就可以在外部访问到它所定义的变量了。这种情况下,这个函数和它所引用的外部变量组成的整体就称为闭包。
使用闭包可以实现很多有用的功能,例如封装私有变量、模拟块级作用域、延迟执行等。但是,过多地使用闭包也会带来一些问题,例如内存泄漏和性能问题等,因此在使用闭包时需要注意一些细节。
6.原型
为什么使用原型????
- 实现对象的继承
- 共享属性和方法
- 提高代码的性能
- 统一管理属性和方法
7.Class类的概念
组织和管理代码,实现面向对象编程的思想。定义了对象的属性和方法。
类的实现是通过构造函数和原型对象来实现的。
构造函数负责定义对象的属性和方法,而原型对象则负责定义对象的共享属性和方法,通过将构造函数和原型对象结合起来,我们就可以创建多个对象实例,它们共享原型对象中的属性和方法。
可以实现代码的复用和扩展,可以提高代码的可维护性和可读性。
私有属性
私有属性是指只能在类内部访问和修改的属性,它们不能被类外部的代码所访问和修改。
共有属性
共有属性是指可以被类的任何实例对象访问和修改的属性。
getter和Setter
getter 和 setter 方法是一种用于控制属性访问和修改的技术。getter 方法用于获取属性的值,setter 方法用于设置属性的值。
getter 方法用于获取对象属性的值,setter 方法用于设置对象属性的值。这样,我们就可以在获取和设置对象属性时进行一些额外的操作,比如对属性值进行校验、格式化等。
为什么使用setter来修改数据
setter 方法是一个特殊的方法,它允许我们在修改对象属性值时进行额外的操作,比如校验、格式化等。使用 setter 方法,可以使得属性的修改更加灵活和安全。
8.VueX使用
需要在 Vuex 的 Store文件配置对象中添加一个 modules 属性,该属性是一个对象,包含了所有的子模块。每个子模块都是一个对象,包含了 state、mutations、actions 和 getters 属性
import Vuex from 'vuex'
import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'
const store = new Vuex.Store({
modules: {
moduleA,
moduleB
}
})
export default store
a使用b数据方法
- 在 b 模块中定义一个方法并导出:
javascriptCopy code// b.js
export const bMethod = () => {
console.log('This is bMethod in module b')
}
- 在 a 模块中导入 b 模块,并调用 b 模块的方法:
javascriptCopy code// a.js
import { bMethod } from './b.js'
const aMethod = () => {
bMethod() // 调用 b 模块中的方法
}
export default {
actions: {
someAction() {
aMethod() // 在 a 模块中调用 aMethod 方法
}
}
}
在这个例子中,a 模块使用 import
关键字导入了 b 模块中的 bMethod
方法,并在 aMethod
方法中调用了 bMethod
方法。最后,a 模块导出了一个包含 aMethod
方法的 Vuex 模块。
注意,如果 b 模块中定义的方法是一个 action、mutation 或 getter,那么需要在 b 模块的 actions
、mutations
或 getters
中注册这个方法,并使用 mapActions
、mapMutations
或 mapGetters
辅助函数在 a 模块中调用这个方法。
9.Vue-router
###$route控制页面跳转有几种方法
- **
$router.push()
**方法:可以使用$router.push()
方法来实现编程式导航,即通过 JavaScript 代码来触发路由跳转。
javascriptCopy code
this.$router.push('/about')
2.**
r
o
u
t
e
r
.
r
e
p
l
a
c
e
(
)
‘
∗
∗
方法:与
‘
router.replace()` **方法:与 `
router.replace()‘∗∗方法:与‘router.push()方法类似,不同的是
$router.replace()` 方法不会在浏览器历史记录中留下记录。
javascriptCopy code
this.$router.replace('/about')
3.**$router.go()
**方法:可以使用 $router.go()
方法来前进或后退浏览器历史记录中的记录,也可以直接跳转到某个历史记录中的页面。
10.Vue Router
Vue Router 提供了全局守卫、路由独享守卫和组件内守卫三种类型的路由守卫。
-
####全局守卫:可以通过
router.beforeEach()
方法来注册全局前置守卫,该守卫会在每次路由导航之前执行。全局守卫可以用来做登录验证、权限验证等操作。 -
####路由独享守卫:可以在路由配置中使用
beforeEnter
属性来注册路由独享守卫,该守卫只会对当前路由生效。 -
####组件内守卫:可以在组件内部使用
beforeRouteEnter
、beforeRouteUpdate
和beforeRouteLeave
方法来注册组件内守卫,这些方法会在组件导航到不同的路由时被调用。
使用场景
- 登录验证 权限验证 页面切换动画 记录用户访问日志
- 多级嵌套路由 页面缓存 页面数据处理
11.echarts图表激活联动
- 在柱状图和饼状图中都设置 **
legend
**属性,用于展示数据的分类信息。 - 在柱状图和饼状图中分别设置
series
的itemStyle
属性,用于定义选中和非选中状态下的样式。 - 监听柱状图和饼状图的
click
事件,在回调函数中获取当前选中的数据,然后分别更新两个图表的状态。 - 更新柱状图的状态:遍历柱状图中的数据,将当前选中的分类对应的柱子设置为选中状态,其余柱子设置为非选中状态。
- 更新饼状图的状态:遍历饼状图中的数据,将当前选中的分类对应的扇形设置为选中状态,其余扇形设置为非选中状态。
- 更新完两个图表的状态后,调用
echarts
实例的setOption
方法,重新渲染图表。
12.echarts选中高亮api
-
setSelected
:设置单个数据项选中状态,参数为数据项名称或者数据项索引。例如:chart.setOption({series: {selected: {1: true}}})
表示选中第二个系列。 -
toggleSelected
:切换单个数据项选中状态,参数同setSelected
。 -
setSeries
:批量设置多个系列的选中状态,参数为数组,数组元素为数据项名称或索引。例如:chart.dispatchAction({type: 'legendSelect', name: '系列1'})
表示选中名称为“系列1”的系列。 -
toggleSelect
:切换整个图表的选中状态,参数为数据项名称或索引,或者为 ‘all’ 表示全选或全不选。###ECharts 中可以使用
resize
事件来实现页面自适应,具体方法如下:1.监听
resize
事件可以使用
window.addEventListener
方法来监听resize
事件,例如:javascriptCopy codewindow.addEventListener('resize', function () { // ECharts 实例 resize });
2.调用
resize
方法在
resize
事件回调函数中,调用 ECharts 实例的resize
方法,例如:javascriptCopy codewindow.addEventListener('resize', function () { myChart.resize(); });
这样当页面大小改变时,ECharts 实例会自动调整大小以适应页面。
另外,ECharts 还提供了一个
setOption
方法,可以在页面大小改变时重新设置图表的配置项以适应页面大小。具体方法如下:- 在
resize
事件回调函数中,获取新的图表配置项。 - 调用 ECharts 实例的
setOption
方法,并将新的配置项传入。
13.git常用指令
- 在
-
git init
:在当前目录初始化一个 Git 仓库。 -
git clone
:从远程 Git 仓库克隆代码到本地。 -
git add
:将修改过的文件添加到暂存区。 -
git commit
:将暂存区的文件提交到本地仓库。 -
git push
:将本地代码推送到远程 Git 仓库。 -
git pull
:将远程 Git 仓库的最新代码拉取到本地。 -
git branch
:列出所有本地分支。 -
git checkout
:切换到指定分支或者指定的提交。 -
git merge
:将指定分支合并到当前分支。 -
git status
:查看当前 Git 仓库的状态。 -
git log
:查看提交历史记录。拉取指定分支
git clone` 命令加上 `-b //dev为例 git clone -b dev https://github.com/username/repo.git
拉取远程分支失败原因
-
分支名称错误:如果分支名称不正确,Git 就找不到对应的分支,会拉取失败。请检查分支名称是否正确。
-
远程 Git 仓库不存在:如果使用了错误的 Git 仓库地址,或者该仓库已经被删除,那么拉取分支也会失败。请检查 Git 仓库地址是否正确。
-
没有权限:如果你没有权限访问该 Git 仓库,那么就无法拉取分支。请检查你是否有权限访问该仓库,并确保你输入的用户名和密码正确。
-
网络问题:如果网络连接不稳定,那么就可能导致拉取分支失败。请检查你的网络连接,并尝试重新拉取分支。
-
分支已经被删除:如果远程分支已经被删除,那么就无法拉取该分支。请检查分支是否被删除。
-
本地分支已经存在:如果本地已经存在同名分支,那么就无法拉取该分支。请检查本地分支是否存在,并考虑是否需要先删除本地分支再进行拉取
git提交push时怎么修改远程地址
git remote set-url
- 首先,使用
git remote -v
命令查看当前远程 Git 仓库的地址。 - 然后,使用
git remote set-url
命令来修改远程 Git 仓库的地址。例如,如果你需要修改远程 Git 仓库的地址为https://github.com/user/repo.git
,那么可以使用以下命令:
git remote set-url origin https://github.com/user/repo.git
14.img标签一个图片加载失败怎么做处理
当图片资源加载失败时,我们可以通过以下几种方式进行替换:
1.使用备用图片:在 HTML 中,可以使用 onerror
属性来指定当图片加载失败时显示备用图片,例如:
htmlCopy code
<img src="example.jpg" onerror="this.src='backup.jpg'">
这里的 onerror
属性指定了当图片加载失败时,将其 src
属性修改为备用图片的地址。
2.使用 CSS 背景图片:在 CSS 中,可以使用 background-image
属性来指定背景图片,如果加载失败,可以使用备用图片的地址进行替换。
3.使用 JavaScript 替换图片:可以使用 JavaScript 来检测图片是否加载成功,如果失败,则将其 src
属性修改为备用图片的地址。例如:
htmlCopy code<img src="example.jpg" id="example-img">
<script>
const img = document.getElementById('example-img');
img.addEventListener('error', () => {
img.src = 'backup.jpg';
});
</script>
15.递归数组柱状列表
16.阻塞js进程5秒
sleep函数 利用promise+定时器来实现
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function myFunction() {
console.log('开始');
await sleep(5000); // 阻塞进程 5 秒
console.log('5 秒钟过去了');
}
myFunction();
17.reduce使用过么有哪些场景?
reduce()
方法对数组中的所有元素进行累加。在 reduce()
方法中,第一个参数是一个回调函数,该函数将被用于累加数组中的所有元素。该回调函数接收两个参数:accumulator
和 currentValue
,前者表示当前累加器的值,后者表示当前要处理的数组元素的值。
- 计算数组中所有元素的和或平均值。
- 将数组中的字符串连接成一个字符串。
- 将数组中的对象按照某个属性分组。
- 将数组转换成一个对象,对象的键值为数组中的元素。
- 将一个多维数组展开成一个一维数组。
- 按照某个属性进行排序。
- 在数组中查找最大值或最小值。
- 数组去重
18.怎样实现深拷贝?需要考虑什么?
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
// 如果不是复杂数据类型,直接返回
return obj
}
let copy = Array.isArray(obj) ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 递归调用深拷贝函数
copy[key] = deepCopy(obj[key])
}
}
return copy
}
考虑:对于嵌套层次过深或循环引用的对象,可能会导致栈溢出或死循环。为了避免这种情况发生,可以使用一些优化手段,比如在递归调用之前,先判断该对象或数组是否已经被拷贝过,如果是,则直接返回该对象或数组的拷贝。
19.封装按钮组件考虑什么做组建的思路?
-
功能需求 样式设计 交互设计。
-
可配置性 可复用性 性能考虑
-
使用防抖函数来避免频繁点击发送验证码导致的问题。因为防抖函数能够限制在一定时间内只触发一次函数
###如何做倒计时?
- 在 Vue 的 data 中定义一个变量,用于保存倒计时的秒数,比如
countdownSeconds
,并初始化为需要倒计时的秒数。 - 在页面中渲染一个按钮组件,绑定一个点击事件,当点击按钮时开始倒计时。
- 在点击事件中,使用
setInterval()
或者setTimeout()
函数来实现倒计时。每经过一秒钟,将countdownSeconds
减 1,直到倒计时结束。 - 在倒计时过程中,需要禁用按钮,避免用户重复点击。可以使用 Vue 的条件渲染,当
countdownSeconds
大于 0 时,按钮处于禁用状态。 - 当倒计时结束后,需要重置
countdownSeconds
的值,以便用户可以再次点击发送验证码按钮。
###切换页面和刷新
为了防止用户刷新页面或者关闭浏览器后倒计时失效,可以使用浏览器的
localStorage
或者sessionStorage
存储一个时间戳和倒计时的秒数,当用户再次打开页面时,可以根据存储的时间戳和倒计时秒数重新计算倒计时。###使用setTimeout还是setInterval?为什么?
在实现倒计时时,建议使用
setTimeout
而不是setInterval
。-
虽然
setInterval
可以每隔一定时间执行一次回调函数,看似更加符合倒计时的需求。但是setInterval
有一个问题,就是它的回调函数会一直执行,无法控制停止的时间,这可能会导致程序的性能问题。 -
而
setTimeout
则可以设置一个延迟时间,让回调函数在指定时间后执行一次,然后再次设置下一次的执行时间,这样可以避免回调函数一直执行的问题,也可以更加灵活地控制时间间隔。
因此,在实现倒计时时,建议使用
setTimeout
来实现。具体来说,可以使用一个递归函数,每次调用自身时设置一个延迟时间,直到时间为 0。 - 在 Vue 的 data 中定义一个变量,用于保存倒计时的秒数,比如
20.事件委托和事件冒泡
事件冒泡是指当一个元素触发某个事件时,这个事件会先被触发到该元素,然后逐层向上冒泡到它的父元素,直到文档的根元素,期间会依次触发每个元素的事件处理程序
事件委托是指将事件处理程序绑定到某个父元素上,而不是每个子元素都绑定一个事件处理程序。当子元素触发事件时,事件会冒泡到父元素,然后在父元素的事件处理程序中处理事件。通过事件委托,可以减少事件处理程序的数量,提高性能。
21.怎么解决跨域问题
- JSONP CORS 代理 postMessage
22.栅格布局
每个元素可以跨越一定数量的列。这样可以很方便地实现响应式布局,即在不同屏幕尺寸下,元素的位置和大小可以自动调整。
栅格布局通常包括以下几个组成部分:
- 容器(Container):栅格布局的最外层容器,用于包裹整个布局。
- 行(Row):行用于将容器分割成若干个水平行。
- 列(Col):列是行中的一个单元格,用于将行分割成若干列。
在栅格布局中,通常会使用 CSS 的 flex
属性来实现列的对齐和伸缩,以及 media
查询来控制在不同屏幕尺寸下的列数和宽度。常见的栅格布局系统包括 Bootstrap 和 Ant Design 等。
23.vue3和vue2什么区别?
1.数据双向绑定原理
Vue2:使⽤的是Object.defineProperty()进⾏数据劫持,结合发布订阅的⽅式实现。
Vue3:使⽤的是Proxy代理,使⽤ref或者reactive将数据转化为响应式数据。
2.Vue2使用选项API,Vue3使用组合式API
3.defineProperty和proxy区别
区别一:defineProperty
是对属性劫持,proxy
是对代理对象
区别二:defineProperty
无法监听对象新增属性,proxy
可以
区别三:defineProperty
无法监听对象删除属性,proxy
可以
区别四:defineProperty
不能监听数组下标改变值的变化,proxy
可以且不需要对数组的方法进行重载
区别五:defineProperty
是循环遍历对象属性的方式来进行监听,自然会比 proxy
对整个对象进行监听的方式要耗性能。
4.生命周期不一样
Vue2(选项式API) | Vue3(setup) | 描述 |
---|---|---|
beforeCreate | - | 实例创建前 |
created | - | 实例创建后 |
beforeMount | onBeforeMount | DOM挂载前调用 |
mounted | onMounted | DOM挂载完成调用 |
beforeUpdate | onBeforeUpdate | 数据更新之前被调用 |
updated | onUpdated | 数据更新之后被调用 |
beforeDestroy | onBeforeUnmount | 组件销毁前调用 |
destroyed | onUnmounted | 组件销毁完成调用 |
5.组件通信不同
方式 | Vue2 | Vue3 |
---|---|---|
父传子 | props | props |
子传父 | $emit | emits |
父传子 | $attrs | attrs |
子传父 | $listeners | 无(合并到 attrs方式) |
父传子 | provide | provide |
子传父 | inject | inject |
子组件访问父组件 | $parent | 无 |
父组件访问子组件 | $children | 无 |
父组件访问子组件 | $ref | expose&ref |
兄弟传值 | EventBus | mitt |
24.图片懒加载
实现图片懒加载的一般思路如下:
- 在HTML中将要懒加载的图片的
src
属性改为自定义属性(如data-src
)。 - 通过JavaScript获取所有需要懒加载的图片元素,保存它们的
data-src
属性的值。 - 监听滚动事件,在滚动过程中判断每个需要懒加载的图片是否已经进入可视区域。
- 如果某个图片已经进入可视区域,则将其
data-src
属性的值赋给src
属性,从而加载图片。
25.图片预加载
预加载可以通过<link>
标签的rel="preload"
属性来实现。例如:
htmlCopy code
<link rel="preload" href="image.jpg" as="image">
26.路由权限
常见的实现方式是在路由配置中添加一个 meta 字段用于标识该路由需要的权限,同时在路由跳转前使用路由守卫进行权限判断。如果当前用户的角色符合要求,拼接动态路由,挂载到路由实例上,则允许路由渲染跳转等操作,否则进行相应的提示或跳转到错误页面。
按钮权限
27.vue Keep-alive实现原理(理解记忆)
- 当使用 Keep-Alive 包裹的组件被销毁时,将该组件实例缓存到 keep-alive 实例的 cache 对象中。
- 当再次渲染该组件时,如果该组件实例存在于 cache 对象中,那么直接从缓存中读取组件的状态,避免重新渲染。
- 如果该组件实例不存在于 cache 对象中,那么通过 createComponent 创建一个新的组件实例,并将该组件实例加入 cache 对象中。
28.echarts二次封装思路
- 提取公共配置项:把图表中可共用的配置项提取出来,作为公共配置项,可以在二次封装中作为默认配置项使用,也可以在使用时通过参数传入。
- 封装基础方法:将 Echarts 的基础方法封装成可复用的方法,比如渲染图表、更新图表等。
- 封装常用图表类型:将常用的图表类型进行封装,如柱状图、折线图、饼图等。可以考虑将不同类型的图表封装成不同的组件,以便于复用和维护。
- 封装交互事件:将常用的交互事件进行封装,如点击、悬浮等,可以通过参数设置交互事件的回调函数。
- 封装自定义样式:封装自定义样式,使得使用者可以通过参数来控制样式,从而实现自定义图表样式。
- 封装动画效果:Echarts 默认提供了一些动画效果,也可以自定义动画效果,可以将动画效果进行封装,方便使用和维护。
- 封装数据处理:对数据进行处理,使其符合 Echarts 要求的格式。可以通过参数传入原始数据,也可以在封装时对数据进行处理。
29.获取DOM元素方法
document.getElementById():根据元素 ID 获取元素对象,返回一个元素对象或 null。
document.getElementsByTagName():根据标签名获取元素对象集合,返回一个元素对象集合或空集合。
document.getElementsByClassName():根据类名获取元素对象集合,返回一个元素对象集合或空集合。
document.querySelector():根据选择器获取第一个匹配的元素对象,返回一个元素对象或 null。
document.querySelectorAll():根据选择器获取所有匹配的元素对象集合,返回一个元素对象集合或空集合。
document.createElement():创建一个新的元素对象,返回一个元素对象。
element.getElementsByTagName():在元素下根据标签名获取元素对象集合,返回一个元素对象集合或空集合。
element.getElementsByClassName():在元素下根据类名获取元素对象集合,返回一个元素对象集合或空集合。
element.querySelector():在元素下根据选择器获取第一个匹配的元素对象,返回一个元素对象或 null。
element.querySelectorAll():在元素下根据选择器获取所有匹配的元素对象集合,返回一个元素对象集合或空集合。
element.parentNode:获取元素的父元素节点,返回一个元素对象或 null。
element.childNodes:获取元素的所有子节点,返回一个节点集合或空集合。
element.children:获取元素的所有子元素节点,返回一个元素节点集合或空集合。
element.nextSibling:获取元素的下一个兄弟节点,返回一个节点对象或 null。
element.previousSibling:获取元素的上一个兄弟节点,返回一个节点对象或 null。
element.firstChild:获取元素的第一个子节点,返回一个节点对象或 null。
element.lastChild:获取元素的最后一个子节点,返回一个节点对象或 null。
element.getAttribute():获取元素的指定属性的值,返回一个字符串或 null。
element.setAttribute():设置元素的指定属性的值,无返回值。
element.hasAttribute():检查元素是否有指定属性,返回一个布尔值。
element.classList:获取元素的类名集合,返回一个 DOMTokenList 对象。
30.微信分享
微信小程序分享功能的实现方法有两种: 1.在page.js中实现onShareAppMessage,便可在小程序右上角选择分享该页面 (代码)
onShareAppMessage: function () {
return {
title: ‘弹出分享时显示的分享标题’,
desc: ‘分享页面的内容’,
path: ‘/page/user?id=123’ // 路径,传递参数到指定页面。
}
}
31.基础数据类型和引用数据类型的区别
- 基础数据类型与引用数据类型最大的区别在于它们在内存中存储的方式不同。
-
基础数据类型是按值进行存储的,也就是说它们的值直接存储在内存中,可以直接访问,而不需要访问另外的内存地址;
-
而引用数据类型是按引用进行存储的,也就是说存储的是地址,这个地址指向存储在内存中的对象,访问时需要先访问到该地址,然后再通过地址来访问对象。
-
因此,对于基础数据类型的操作会直接操作它们的值,而对于引用数据类型的操作会操作它们在内存中的地址,而不是它们的值。
32.隐式转换的方法
1.字符串拼接:使用加号操作符将字符串和其他数据类型(除了对象)拼接在一起时,会自动将其他数据类型转换为字符串类型。
2.数字运算:在执行数字运算时,如果操作数为其他数据类型(除了布尔值),会自动将其转换为数字类型。
3.布尔值判断:在使用布尔值进行判断时,如果操作数为其他数据类型,会自动将其转换为布尔值类型。undefined、null、NaN、0、‘’(空字符串)和false会被转换为false,其他值都会被转换为true。
4.对象转换:在将对象作为操作数时,会调用对象的toString或valueOf方法进行隐式类型转换。
33.改变this指向的方法
-
使用
call
或apply
方法:call
和apply
方法可以立即调用一个函数,并将this
指向指定的对象。 -
使用
bind
方法:bind
方法会返回一个新函数,并将this
绑定到指定的对象上。 -
使用箭头函数:箭头函数中的
this
是静态的,指向定义时的外层作用域。
34.postation了解过么?有层级问题么?
- static(默认值)
- relative:元素相对于其原始位置进行定位
- absolute:则相对于文档根元素进行定位。会影响其他元素的布局。
- fixed:元素相对于视口进行定位,会影响其他元素的布局。
- sticky:元素在页面滚动到特定位置时定位。sticky类似于relative和fixed的组合,当元素在屏幕内时,按照normal的方式进行布局,当滚动到特定位置时,元素变为fixed的方式进行布局,固定在屏幕上。
- 层级问题:在使用position属性时,会存在层级问题。当元素使用了position属性后,该元素会脱离正常的文档流,其位置不再受到其它元素的影响,因此可能会出现遮挡或者被遮挡的情况。这时可以通过z-index属性来调整层级关系。较大的z-index值会使元素显示在较小的z-index值的元素上面。
35.对Ts的理解
- 相比于JavaScript,TypeScript 增加了一些静态类型检查特性,例如:
- 变量、参数、返回值等数据类型必须声明。
- 变量、参数、返回值等数据类型可以进行类型检查。
- TypeScript 通过类型推断来降低代码中类型注释的冗余度,避免类型错误。
-
优点
增强代码可维护性和可读性,减少编码错误。
支持 ES6+ 新特性,有利于开发更加现代化的 Web 应用程序。
可以在开发阶段发现潜在的运行时错误,减少程序运行时错误。
TypeScript 社区庞大,拥有大量的第三方库,提高开发效率。
36.vue和react有什么区别
- vue和React是两个不同的前端框架,分别使用不同的语法和方式来构建应用程序。Vue是一种基于模板的渐进式框架,而React则是一种基于组件的库。
37.组件和pinia的传递数据界定
可复用性的组件中数据中传递通过父传子,在页面上组件没有复用性只是为了组织代码方便可以使用pinia来存储传递
38.TS的装饰器
在 TypeScript 中,装饰器(Decorator)是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,可以修改类的行为。
装饰器通过 @expression
形式使用,其中 expression
求值后必须为一个函数,它会在运行时被调用,并传入以下三个参数:
- 如果装饰器附加在类上,则是类的构造函数;
- 如果装饰器附加在方法、属性或参数上,则是类的原型对象;
- 如果装饰器附加在方法参数上,则是类的原型对象。
装饰器有多种应用场景,如:
- 类装饰器:用于类的声明,用来监视、修改或替换类定义。
- 方法装饰器:用于方法的声明,用来监视、修改或替换方法定义。
- 访问器装饰器:用于访问器的声明,用来监视、修改或替换访问器的定义。
- 属性装饰器:用于属性的声明,用来监视、修改或替换属性定义。
- 参数装饰器:用于方法参数的声明,用来监视、修改或替换参数定义。
import { defineComponent, Prop } from 'vue'
@Component
export default class MyComponent extends Vue {
@Prop() propA: string | undefined
@Prop({ default: 'default value' }) propB!: string
}
39.小程序路由跳转如何带参数
路由跳转传递参数
let tid = 1;
wx.navigateTo({
url: ‘…/detail/detail?id=’ + tid
})
获取传递过来的参数
onLoad: function (option) {
console.log(‘option—>’, option) //{id:1}
}
40.小程序会出现地图Map视频音频层级过高问题遇到过么?
1.不使用vue,而是使用nvue开发
2.使用原生子窗体subNvue,其实也是类似nvue,只不过是nvue嵌在vue里面而已
nvue比较原生,样式css基于week写起来麻烦,我们可以先vue页面写了map,然后自定义原生子窗体subNvue,位置在页面左上角
41.http和https的区别,定位区别
- HTTP协议是Web应用最为广泛的一种网络传输协议,主要用于Web浏览器和服务器之间的通信。HTTP协议是明文传输的,安全性较低,容易被中间人攻击窃取信息,如用户名、密码等。
- HTTPS协议是在HTTP协议的基础上添加了一层安全层TLS/SSL,使用加密技术保证传输数据的安全性。使用HTTPS协议可以保证数据传输的机密性、完整性和可验证性,从而避免中间人攻击、数据篡改和冒充等问题。
- HTTP协议的URL以"http://"开头,而HTTPS协议的URL以"https://"开头。
- HTTPS协议需要申请SSL证书,而HTTP协议不需要。
- HTTPS协议需要进行加密解密操作,因此相比HTTP协议传输速度较慢。
HTTP和HTTPS的定位是不同的。HTTP主要用于在Web浏览器和Web服务器之间传输数据;而HTTPS主要用于保护在Web浏览器和Web服务器之间传输的数据的安全性。因此,当需要保护敏感数据时,应该使用HTTPS协议。
42.常见的性能优化
- 压缩文件大小:通过压缩文件大小来提高网页的加载速度,如使用压缩图片和使用CSS压缩器和JavaScript压缩器等。
- 缓存数据:利用缓存来提高网站的响应速度,如使用浏览器缓存和CDN缓存等。
- 减少HTTP请求:减少网站的HTTP请求,可以有效提高网站的加载速度,如使用CSS Sprites来合并多张图片等。
- 使用懒加载:懒加载可以使页面在不需要加载所有内容的情况下更快地加载。
- 使用CDN:使用CDN可以让用户更快地加载网页,因为CDN会将网页的静态资源存储在离用户最近的服务器上。
- 前端性能优化:对于前端代码的性能优化,可以使用一些技巧来提高网站的响应速度,如减少重绘和重排、尽量减少DOM操作、使用异步加载等。
- 后端性能优化:对于后端代码的性能优化,可以使用一些技巧来提高服务器的响应速度,如使用缓存、使用异步编程等。
- 数据库优化:对于数据库的性能优化,可以使用一些技巧来提高数据库的查询速度,如创建索引、优化查询语句等。
43.elementUI的table组件长列表渲染会出现卡顿页面崩溃(虚拟滚动)
虚拟滚动是一种优化长列表渲染性能的技术。在传统的滚动列表渲染中,我们通常会将所有的列表项都渲染出来,如果列表非常长,这样会导致性能问题,比如卡顿、页面崩溃等。而虚拟滚动的原理是只渲染当前视口内的列表项和一部分缓冲区域的列表项,其他的列表项则不渲染,这样可以大大减轻浏览器的渲染压力,提升页面性能。
虚拟滚动的实现一般分为两个方面:
1.计算视口内可见区域的起始项和结束项,只渲染这些项以及一部分缓冲区域的项。
2.动态地更新可见区域内的列表项,随着用户的滚动动态地添加或删除列表项,保证性能的同时提供流畅的用户体验。
在实现虚拟滚动时,我们通常需要考虑以下几个方面:
1.计算每个列表项的高度或宽度,以便于计算可见区域内的起始项和结束项。
2.通过监听滚动事件,计算当前滚动位置,从而确定可见区域内的列表项。
3.动态地添加和删除列表项,保证可见区域内的列表项数量不变,从而提高渲染性能。
4.对列表项的缓存管理,及时清除不需要的缓存,避免内存占用过多。
虚拟滚动是一种常见的性能优化方案,在长列表的场景下,可以显著提升页面的渲染性能和用户体验。
44.vue是单页面应用,怎么做多页面应用
通常用于单页面应用(SPA),但是也可以使用Vue构建多页面应用(MPA)。下面是实现多页面应用的一些步骤:
- 配置webpack
在webpack配置中,需要配置多个入口(entry)和输出(output),每个入口都应该对应一个html页面
2.创建html模板
为每个页面创建一个html模板文件,并使用html-webpack-plugin插件来自动生成html文件。
3.配置路由
对于多页面应用,我们需要手动配置路由。可以使用Vue Router或者其他路由库来实现路由功能。在路由配置中,需要将每个页面对应的组件映射到路由上
4.开发页面
总的来说,实现多页面应用需要配置多入口、多出口,手动配置路由等。但是相对于单页面应用,多页面应用的页面独立性更高,每个页面可以使用自己的样式和依赖库,适合一些特定的应用场景。
45.vue 中 keys 的作用是什么?
key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中 会执行patch vnode,patch vnode的过程中会执行updateChildren这个方法【patch.js中 重排算法】。 他会去更新两个新旧的子元素。在这个过程中。通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
原文链接:https://blog.youkuaiyun.com/weixin_44914088/article/details/122119054
46.nextTick
- 每次修改数据后,Vue 会异步地执行更新 DOM 操作。如果我们希望在 Vue 更新 DOM 后获取到最新的 DOM 节点信息或者执行某些操作,需要等到 DOM 更新后再进行。这时就可以使用
Vue.nextTick()
方法。 Vue.nextTick()
是一个全局方法,调用它可以在 DOM 更新完毕之后执行回调函数。Vue 会把这些回调函数存储在一个队列中,当 DOM 更新完成后,逐一执行队列中的回调函数。- 注意,由于
Vue.nextTick()
是异步执行的,因此无法保证回调函数执行的先后顺序。如果需要保证顺序,可以使用 Promise 封装Vue.nextTick()
方法。
47.Ts的as了解过么?
在 TypeScript 中,as
用作类型断言。它可以将一个表达式强制转换为一个特定的类型。语法为:expression as type
。虽然 as
可以帮助我们告诉 TypeScript 变量的类型,但它并不会在运行时进行类型检查。如果我们使用 as
将一个变量强制转换为一个不正确的类型,它仍然会编译通过。
48.动态路由刷新页面路由丢失
ant-design-vue-pro 路由配置
参考:https://github.com/vueComponent/ant-design-vue-pro/tree/master/src
49.vue3修改了那些数组方法那些变动?
Vue3 修改了数组方法的 prop,包括 push、pop、shift、unshift、splice、sort 和 reverse,这是为了更好地支持响应式系统。
- push:在数组末尾添加一个或多个元素,并返回新数组的长度。
- Vue3 的 push 方法会在向数组中添加元素后触发更新。
- pop:从数组末尾删除一个元素,并返回被删除的元素。
- Vue3 的 pop 方法会在删除数组末尾的元素后触发更新。
- shift:从数组开头删除一个元素,并返回被删除的元素。
- Vue3 的 shift 方法会在删除数组开头的元素后触发更新。
- unshift:在数组开头添加一个或多个元素,并返回新数组的长度。
- Vue3 的 unshift 方法会在向数组开头添加元素后触发更新。
- splice:在数组中添加或删除元素,并返回被删除的元素。
- Vue3 的 splice 方法会在添加或删除元素后触发更新。
- sort:对数组元素进行排序,并返回排序后的数组。
- Vue3 的 sort 方法会在对数组元素进行排序后触发更新。
- reverse:颠倒数组中元素的顺序,并返回颠倒后的数组。
- Vue3 的 reverse 方法会在颠倒数组中元素的顺序后触发更新。
50.选项式api和组合式api有哪些区别应用场景是哪些
- 是 Vue.js 2.x 中常用的 API;
- 使用方式为在 Vue 组件的选项中添加相应的属性和方法;
- 它的编写方式类似于 Vue 2.x,主要是以数据和选项为中心进行编写;
- 主要应用场景是适用于小型和简单的应用开发。
组合式 API:
-
是 Vue.js 3.x 中新增的 API;
-
使用方式为通过函数的方式编写 Vue 组件;
-
它的编写方式类似于函数式编程,主要是以功能为中心进行编写;
-
主要应用场景是适用于大型和复杂的应用开发,可以更好地实现代码的可维护性和可重用性。
-
选项式 API 适用于小型和简单的应用开发,可以快速开发并迭代应用;组合式 API 适用于大型和复杂的应用开发,可以更好地实现代码的可维护性和可重用性。开发者可以根据具体的应用场景选择不同的 API 进行开发。
选项式:
1.通过在 Vue 组件选项中添加属性和方法来定义组件。
2.以数据和选项为中心,将组件的数据、计算属性、方法、生命周期等分散在组件选项中进行管理。
3.组件逻辑较为分散,不易于维护和复用。
4.对于新手来说,学习成本较低,易于理解和上手。
5.组件逻辑分散,渲染时需要进行多次响应式的依赖收集和更新。
组合式:
- 通过函数的方式定义组件。
- 以功能为中心,将组件的逻辑封装在单独的函数中,每个函数仅关注特定功能点。
- 逻辑清晰,单一功能点的函数易于维护和复用。
- 函数的结构比较抽象,需要较强的 JavaScript 知识和编程经验。
- 逻辑清晰,每个函数只包含特定的功能,渲染时只需要进行必要的依赖收集和更新。
51.不使用插件或组件实现上传文件?(能说思路考点是对http请求的了解)
在 Vue.js 中,我们可以通过一个 input 元素来实现文件上传的功能。首先,在模板中添加一个 input 元素,设置它的 type 为 file,然后添加一个 change 事件监听器,当用户选择文件后,该事件监听器将会被触发:
html
Copy code
<template>
<div>
<input type="file" @change="handleFileUpload" />
</div>
</template>
接着,在组件中定义一个 handleFileUpload 方法,该方法将会读取用户选择的文件,并将文件内容保存到 data 中:
js
Copy code
export default {
data() {
return {
fileContent: null
};
},
methods: {
handleFileUpload(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
this.fileContent = e.target.result;
};
reader.readAsText(file);
}
}
};
在上面的代码中,我们首先获取用户选择的文件,然后使用 FileReader 对象将文件内容读取为文本。当读取完成后,我们将文件内容保存到组件的 data 中,以便进一步处理。
如果需要上传文件到服务器,我们可以使用 Ajax 或 Fetch API 来实现。例如,在 handleFileUpload 方法中,我们可以添加以下代码,将文件内容发送到服务器:
js
Copy code
methods: {
handleFileUpload(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
const fileContent = e.target.result;
// 发送文件内容到服务器
fetch('/upload', {
method: 'POST',
body: fileContent
});
};
reader.readAsText(file);
}
}
上面的代码使用 Fetch API 将文件内容发送到服务器。如果需要使用 Ajax,可以使用类似的方式来实现。
需要注意的是,如果上传的文件比较大,可能会导致内存占用过高。在实际应用中,我们应该将文件内容分块读取并上传,或者使用流式上传的方式,以减少内存占用。
52.http get和post请求的区别 (说个人理解)
- 参数传递方式:HTTP GET 请求的参数可以直接在 URL 中看到,而 HTTP POST 请求的参数不会出现在 URL 中。
- 请求体大小限制:由于 HTTP GET 请求的参数是在 URL 中传递的,一般都在 2KB 到 8KB 之间。而 HTTP POST 请求的参数是在请求体中传递的,因此它的请求体大小理论上没有限制。
- 安全性:由于 HTTP GET 请求的参数出现在 URL 中,因此它的安全性相对较低。例如,通过在 URL 中添加敏感信息,可以使这些信息被截获和泄露。而 HTTP POST 请求的参数在请求体中传递,相对来说比较安全,但仍然需要注意防止敏感信息泄露。
- 缓存:由于 HTTP GET 请求的参数出现在 URL 中,因此它容易被缓存。例如,如果多次发送相同的 HTTP GET 请求,浏览器可能会从缓存中获取响应,而不是发送新的请求。而 HTTP POST 请求的参数在请求体中传递,因此它不容易被缓存。
- 幂等性:HTTP GET 请求是幂等的,即多次发送相同的 HTTP GET 请求,服务器返回的结果应该是相同的。而 HTTP POST 请求不一定是幂等的,因为它可能会对服务器状态进行修改。例如,向数据库中插入一条新记录的操作,每次发送 HTTP POST 请求都会产生不同的结果。
53.了解那些布局方式
- 盒模型布局 流式布局 定位布局 弹性布局 网格布局 多列布局 栅格布局
54.怎么做50000条数据加载虚拟表格虚拟滚动
在前端中,对于大量数据的展示,为了提高性能和用户体验,可以使用虚拟表格(Virtual Table)和虚拟滚动(Virtual Scroll)。
虚拟滚动是一种只渲染当前可视区域内的数据,而不是全部数据的滚动组件。当用户向下滚动页面时,它会自动加载更多的数据并展示出来,这样可以大大减少页面的加载时间和渲染时间,提高用户的使用体验。
- 数据的分页加载:将数据分成多页,每次只加载当前页的数据,当用户向下滚动页面时,自动加载下一页的数据。
- 可视区域的高度计算:计算可视区域的高度,根据可视区域的高度和行高,确定当前可见的行数,只渲染当前可见的行。
- 虚拟滚动的实现:在虚拟滚动的组件中,监听滚动事件,计算当前滚动位置所在的行数和需要渲染的行数,只渲染这些行的数据,其余行的数据则不渲染。
- 性能优化:在数据量非常大的情况下,应该考虑使用一些性能优化技术,例如增量渲染、缓存机制、前后端分离等,以提高页面的性能和用户的使用体验。
- vue-virtual-scroll 是一个 Vue.js 组件,用于实现虚拟滚动的功能。它可以非常高效地渲染大量的数据,提高页面的性能和用户的使用体验。
<template>
<div class="list">
<virtual-scroll :items="items" :item-height="itemHeight">
<div slot-scope="{ item }" class="item">
{{ item.text }}
</div>
</virtual-scroll>
</div>
</template>
<script>
import VirtualScroll from 'vue-virtual-scroll'
export default {
components: {
VirtualScroll,
},
data() {
return {
items: [
{ id: 1, text: 'Item 1' },
{ id: 2, text: 'Item 2' },
{ id: 3, text: 'Item 3' },
// ...
],
itemHeight: 50, // 每个 item 的高度
}
},
}
</script>
<style>
.list {
height: 400px; /* 可视区域的高度 */
overflow-y: auto; /* 开启滚动条 */
}
.item {
height: 50px; /* 每个 item 的高度 */
line-height: 50px;
text-align: center;
border: 1px solid #ccc;
}
</style>
55.Ts有什么了解,装饰器有几种 (ts重点)
TypeScript 是一种由微软开发的静态类型检查的 JavaScript 的超集,它在 JavaScript 的基础上添加了一些新的语法和特性,使得开发者可以更加安全和高效地开发大型的应用程序。
- 强类型系统:TypeScript 可以检查变量的类型,并在编译时检查错误。
- 类和接口:TypeScript 支持类和接口,使得代码更加结构化和易于维护。
- 泛型:TypeScript 支持泛型,可以增加代码的复用性和灵活性。
- 装饰器:TypeScript 支持装饰器,可以用来增强类、方法、属性等的功能。
在 TypeScript 中,装饰器是一种特殊类型的声明,它可以被附加到类声明、方法、属性或参数上,以修改类的行为。它们以 @expression 的形式应用于类、方法、访问器、属性或参数上,其中 expression 求值后必须是一个函数,被称为“装饰器工厂函数”。
常见装饰器
-
@ClassDecorator
:应用于类,用于修改类的行为。类装饰器类装饰器是我们最常使用到的,它的通常作用是,为该类扩展功能 -
@MethodDecorator
:应用于类方法,用于修改方法的行为。 对于静态方法,第一个参数为类的构造函数。对于实例方法,为类的原型对象。第二个参数为方法名。第三个参数为方法描述符。 -
方法装饰器可以有返回值,返回值会作为方法的属性描述符
-
@PropertyDecorator
:应用于类属性,用于修改属性的行为。属性装饰器接受两个参数 对于静态属性,第一个参数为类的构造函数。对于实例属性,参数为类的原型对象 第二个参数为属性名称5.
@ParameterDecorator
:应用于类构造函数参数,用于修改构造函数参数的行为。参数装饰器接受三个参数6.访问器装饰器 对于静态方法,第一个参数为类的构造函数。对于实例方法,为类的原型对象。第二个参数为参数所在的方法名称。第三个参数为参数在参数列表中的索引。
56.ts怎么收缩约束 (TS学习—>Next.js)
-
类型保护函数:可以使用自定义函数来判断变量的类型,并在函数内部使用
is
关键字指定类型保护条件。例如:typescriptCopy codefunction isString(value: unknown): value is string { return typeof value === 'string'; } let str: unknown = 'hello world'; if (isString(str)) { // 在这个块中,str 的类型被收缩为 string console.log(str.length); }
-
typeof
类型保护:可以使用typeof
关键字来判断变量的类型,并在判断条件中使用类型保护条件。例如:typescriptCopy codelet x: string | number; if (typeof x === 'string') { // 在这个块中,x 的类型被收缩为 string console.log(x.length); } else { // 在这个块中,x 的类型被收缩为 number console.log(x.toFixed(2)); }
-
in
类型保护:可以使用in
关键字来判断变量是否具有某个属性,并在判断条件中使用类型保护条件。例如:typescriptCopy codeinterface Cat { name: string; meow(): void; } interface Dog { name: string; bark(): void; } function isCat(animal: Cat | Dog): animal is Cat { return 'meow' in animal; } function doSomething(animal: Cat | Dog) { if (isCat(animal)) { // 在这个块中,animal 的类型被收缩为 Cat animal.meow(); } else { // 在这个块中,animal 的类型被收缩为 Dog animal.bark(); } }
57.vue3ref双向绑定数据为什么要用.value来获取
在 Vue 3 中,使用 ref
创建的响应式对象,实际上是一个对象,其内部包含一个名为 value
的属性,该属性是一个可变的值。
因此,在模板中使用 ref
创建的响应式对象时,需要使用 .value
来访问其值,否则将只能获取到该对象本身,而不是其中的值。
58.vue2中data数据定义了一个双向绑定数据但数据更新页面数据并未更新
在 Vue 2 中,当使用 data
定义双向绑定数据时,需要将该属性声明为响应式对象,否则当数据更新时,页面上对应的数据并不会自动更新。
通常情况下,可以使用 Vue 提供的 Vue.observable()
方法将一个普通对象转换为响应式对象。例如:
vueCopy code<template>
<div>{{ message }}</div>
</template>
<script>
import Vue from 'vue';
export default {
data() {
return {
message: 'Hello World!',
};
},
created() {
// 将 message 属性声明为响应式对象
Vue.observable(this.$data);
},
mounted() {
// 修改 message 的值,页面上的数据也会更新
setTimeout(() => {
this.message = 'Hello Vue!';
}, 1000);
},
};
</script>
在上述代码中,Vue.observable(this.$data)
将组件实例的 data
对象转换为响应式对象,从而使其中的属性能够进行双向绑定。通过调用 setTimeout
函数修改 message
的值,页面上的数据也会自动更新。
59.首屏加载优化 (减少http请求)
- 合并文件:将多个 CSS、JavaScript 文件合并为一个文件,减少 HTTP 请求次数。
- 图片精灵:将多个小图片合成一张大图,然后使用 CSS 的
background-image
属性来显示需要的图片,减少 HTTP 请求次数。 - 使用字体图标:使用字体图标代替图片,可以减少 HTTP 请求次数。
- 使用缓存:使用浏览器缓存,缓存静态文件,减少 HTTP 请求次数。
- 使用数据缓存:使用浏览器缓存和数据缓存技术,避免不必要的 HTTP 请求。
- 使用 CDN:使用 CDN 加速静态资源,加快访问速度,减少 HTTP 请求次数。
- 图片懒加载:将页面上的图片加载延迟到需要显示时再进行加载,减少首次 HTTP 请求次数。
- 延迟加载:将页面上的 JavaScript 文件延迟加载到页面内容加载完成之后再加载,减少首次 HTTP 请求次数。
60.组件封装思路
61.浏览器事件执行机制
- 捕获阶段(Capture phase):事件从根节点向下传递,直到达到事件触发的目标元素。
- 目标阶段(Target phase):事件达到目标元素,并执行目标元素上绑定的事件处理函数。
- 冒泡阶段(Bubble phase):事件从目标元素开始向上冒泡,直到到达根节点。
62.js事件执行机制
javaScript的事件执行机制基于事件循环(Event Loop) 参考课件。宏任务微任务的理解什么是宏任务什么是微任务
63.微应用了解么?基于qiankun多个微应用合并打包上线后不会发生冲突是为什么
基于 qiankun 的多个微应用合并打包上线后不会发生冲突,是因为 qiankun 实现了一套标准的微服务架构规范,各个微应用之间通过特定的接口协议进行通信和交互,保证了微应用之间的隔离和互不干扰。
在 qiankun 的架构中,每个微应用都是一个独立的 JavaScript 运行环境,拥有自己的代码、数据和状态等,不同微应用之间的状态和数据不会相互影响。每个微应用都有一个独立的沙箱环境,用于隔离全局变量、 DOM 等资源,从而避免不同微应用之间的全局变量污染、 DOM 节点冲突等问题。
此外,qiankun 还提供了一套完善的通信机制,包括应用间通信(如 props 传递、事件监听、emit 等)、路由管理、全局状态管理等,使得微应用之间的通信和交互变得更加便捷和高效,同时避免了各个微应用之间的命名冲突和数据重复等问题。
因此,基于 qiankun 的多个微应用合并打包上线后不会发生冲突,是因为 qiankun 的架构和通信机制保证了微应用之间的隔离和互不干扰,同时提供了便捷的通信和交互方式,使得多个微应用可以协同工作,共同构建一个完整的应用系统。