> 自媒体 > (AI)人工智能 > AI为面试赋能:利用AI去回答网友的面试题
AI为面试赋能:利用AI去回答网友的面试题
来源:阿珊和她的猫
2023-06-19 21:49:30
301
管理
布局相关题介绍一下 flex 布局,flex:1是哪几个属性的缩写

Flex布局是CSS中的弹性盒子布局,旨在为布局提供更加灵活的方式,可以实现对盒子的自适应调整和对齐方式的灵活控制。以下是Flex布局中常用的几个属性:

display:设置应用Flex布局方式的容器元素。容器元素的display属性为flex或inline-flex时容器内的子元素即应用了Flex布局方式。flex-direction:设置Flex容器内的Flex子元素的排列方向。Flex容器内的子元素可以横向排列(row)或纵向排列(column)。justify-content:设置Flex容器内的Flex子元素在Flex容器中沿主轴方向上的对齐方式。支持值有:flex-start、flex-end、center、space-between、space-around、space-evenly。align-items:设置Flex容器内的Flex子元素在Flex容器中沿交叉轴方向上的对齐方式。支持值有:flex-start、flex-end、center、baseline、stretch。align-content:设置Flex容器内的各个Flex子元素在交叉轴方向上的排列方式。支持值有:flex-start、flex-end、center、space-between、space-around、stretch。

其中,flex:1是flex-grow、flex-shrink、flex-basis三个属性的缩写。具体来说,它的意思是:

flex-grow: 1;flex-shrink: 1;flex-basis: 0%;flex-grow属性表示子元素的放大比例,可以设置为一个非负数。若容器空余空间大于0,子项目的大小会按照这个比例进行调整。flex-shrink属性表示子元素的缩小比例,可以设置为一个非负数。当容器空间不足指定时,子项目会按照这个比例进行缩小。flex-basis属性表示项目在分配多余空间之前的初始值。可以指定为一个长度(比如50px)或百分比(比如20%)。

当只设置flex:1;时,表示子元素会根据父元素的大小自适应调整,并平分剩余空间。即将所有子元素的flex-basis设定为0,并将所有子元素的flex-grow设定为相等的值1。这通常用于使所有子元素自适应父元素的空间,并占据整个父元素的空间。

grid 布局是什么?,和flex 布局有什么区别,他们的应用场景你会怎么选?

Grid布局是CSS中的一种强大的二维布局系统,可以用于开发复杂的网格布局。相较于Flex布局,Grid布局更加灵活、强大,可以实现更加复杂的布局效果。

Grid布局与Flex布局主要的区别如下:

方向不同:Flex布局只有主轴和交叉轴两个方向,而Grid布局则基于行和列构建。维度不同:Flex布局是一维布局,使用于单行或单列的情况。而Grid布局是二维布局,可以同时控制行和列。对齐方式不同:Flex布局的主要目的是控制项目在主轴和交叉轴上的对齐方式。而Grid布局可以针对任意行或列,控制对齐方式。

他们的应用场景一般如下:

对于单行或单列等简单布局,使用Flex布局就足够了,因为它代码简单、易于理解。对于需要控制多个项目多个维度的情况,Grid布局比Flex布局更加灵活、强大。例如,依次过滤五万个商品中,只显示特定颜色和分类的商品,并保证商品字体大小一致时,就可以利用Grid布局解决。

因此,在选择应该使用Flex布局还是Grid布局时,需要结合布局的实际情况做出选择。如果需要控制多行、多列,更加复杂的嵌套结构和空间关系时,应当使用Grid布局。如果只是简单的单行或单列布局时,使用Flex布局则更为方便。

flex 布局还有什么常用的属性? justify-content 有哪些可选项? 如果让他们都靠左对齐如何实现

除了justify-content属性以外,flex布局还有许多其他常用的属性,以下是一些常用的属性:

flex-direction:定义主轴的方向,可选值有row(默认值,从左到右)、row-reverse(从右到左)、column(从上往下)和column-reverse(从下往上)。flex-wrap:定义如何换行,可选值有nowrap(不换行)、wrap(换行,第一行在上方)和wrap-reverse(换行,第一行在下方)。flex-flow:同时定义flex-direction和flex-wrap属性的缩写。align-items:定义交叉轴上的对齐方式,可选值有flex-start(默认值,交叉轴的起点对齐)、flex-end(交叉轴的终点对齐)、center(交叉轴的中点对齐)、baseline(基线对齐)和stretch(如果子项目没有设置高度,则拉伸子项目以与容器相同的高度)。align-content:定义多根轴线的对齐方式,可选值与align-items相同,但只对多行flex容器生效。

就justify-content属性而言,以下是可选的属性值:

flex-start:默认值,左对齐。flex-end:右对齐。center:居中对齐。space-between:两端对齐,项目之间的间隔相等。space-around:每个项目两侧的间隔相等。

如果要让flex容器左对齐,可以将justify-content属性设置为flex-start即可,示例如下:

.flex-container { display: flex; justify-content: flex-start;}

上述代码中,.flex-container为flex容器的类名,justify-content: flex-start;表示让flex容器左对齐。

盒子垂直水平居中,有几种方法

在前端开发中,将盒子垂直和水平居中是一个非常常见的需求,下面列出几种实现方法:

1. 使用flex布局

可以使用flex布局中的justify-content和align-items属性。将display属性设置为flex,然后将justify-content和align-items都设置为center,即可实现盒子的水平和垂直居中。

.container { display: flex; justify-content: center; align-items: center;}

2. 使用绝对定位

将盒子的position属性设置为absolute,并将left、right、top、bottom都设置为0,然后将margin属性设置为auto,即可实现盒子的水平和垂直居中。

.container { position: relative;}.box { position: absolute; top: 0; left: 0; bottom: 0; right: 0; margin: auto;}

3. 使用display和margin

将盒子的display属性设置为inline-block,并将盒子的宽度和高度都设置为确定的值,然后将margin属性的值设置为auto,即可实现盒子的水平和垂直居中。

.container { text-align: center;}.box { display: inline-block; width: 200px; height: 200px; margin: auto;}

根据需求不同,也可以结合上述方法,进行组合使用,来达到更加复杂的布局方式。

Vue相关题对 VUE3 的了解

Vue3是Vue.js项目的下一代版本,相比于Vue2,Vue3在性能、开发体验和功能方面都有了重要的改进和变化。Vue3于2020年9月正式发布,以下是对Vue3的简要介绍:

更快的渲染速度:Vue3中重新设计了虚拟DOM算法,优化了渲染性能。在实际测试中,Vue3的性能比Vue2有了明显的提升。更小的体积:Vue3中优化了打包结构,将Vue核心库和编译器分开打包,使得运行时库、编译器和模板编译器的体积都更小。更好的TypeScript支持:Vue3中对TypeScript的支持更加完善,可以更便捷地使用TypeScript开发Vue项目。改进的响应式系统:Vue3中重新设计了响应式系统,使用Proxy代替了Object.defineProperty实现,使得响应式数据更加稳定、性能更高。Composition API:Vue3中提供了Composition API,可以将一个组件拆分成逻辑相关的部分,并使每个部分独立可测试、可重用。这个特性可以优化代码结构,使得代码更加易于维护。Teleport:Vue3中提供了Teleport特性,可以将组件的DOM插入到任何指定的DOM节点,使得多个组件共用同一个Template变得更加便捷。其他功能:Vue3中还加入了Suspense(异步组件Loading)和Fragments等新的功能。

总之,Vue3是一个更加高效、易用、灵活的版本,它带来了更好的性能、更好的组织代码的方式、更好的TypeScript支持和更加丰富的功能。同时,Vue3也保留了Vue2的一些核心特性,原有的Vue项目可以平滑地升级到Vue3。

setup 是什么

在Vue3中,setup是一个新的组件选项,代替了Vue2中的beforeCreate和created钩子函数。它是一个特殊的函数,用于设置组件的响应式数据、计算属性、事件处理函数等。

setup函数会在组件实例创建之前执行,它接收两个参数:props和context。

props是一个对象,包含了组件的 props 数据;context 是一个对象,包含了与当前组件上下文相关的属性和方法,例如attrs、slots和emit等。

在setup中可以使用Vue3中新增的响应式API(例如ref和reactive)来创建响应式数据,并通过return语句将数据暴露给组件模板使用。

以下是一个简单的例子:

Count: {{ count }}

Increase

在上面的例子中,setup函数使用ref创建了一个响应式数据count,并定义了一个事件处理函数increaseCount。最后,通过return语句将count和increaseCount暴露给组件模板使用。

需要注意的是,由于setup是一个新的选项,会替代beforeCreate和created钩子函数,因此在使用setup时,应该避免在beforeCreate和created钩子函数中定义数据,并确保所有的数据定义都在setup函数中进行。此外,setup中不能使用this关键字,因为this在setup中并不指向组件实例。

想操纵一个 DOM 元素,我应该在哪个生命周期里面去操作如果您想在Vue组件中操作DOM元素,则应该在mounted生命周期中执行操作。这是因为在mounted生命周期期间,组件已经插入到页面中,所以可以安全地操作DOM元素。当数据发生变化时,Vue会触发组件的更新,此时会依次触发beforeUpdate和updated生命周期函数。在beforeUpdate生命周期中,您可以访问先前的DOM状态并执行必要的操作。而在updated生命周期中,您可以访问更新后的DOM状态,但是请注意,在此期间更新DOM可能导致无限循环更新,因此应该谨慎操作。请注意,任何情况下都不建议直接操作DOM元素,Vue的理念是数据驱动视图,在大多数情况下,只需要更新数据即可使DOM自动更新。如果您确实需要直接操作DOM元素,建议使用Vue提供的ref来获取DOM元素的引用,并在mounted生命周期中执行操作。Updated 可以更新 DOM 节点吗,或者说更新数据吗updated生命周期函数用于在组件的DOM更新后执行操作,它不是用于直接操作DOM元素的函数。在updated生命周期函数中,您可以访问更新后的数据和DOM节点,但是建议您不要直接操作DOM节点,而是通过Vue的数据驱动视图的特性更新数据,从而更新DOM。更具体地说,当Vue组件的数据发生变化时,Vue会重新渲染组件的DOM节点。如果您在updated生命周期函数中直接修改DOM节点,则会导致Vue检测到DOM节点发生了变化,因此会再次更新DOM节点,从而导致无限循环更新。因此,建议您在updated生命周期函数中只处理一些需要在DOM更新后重新计算的操作,而不直接操作DOM节点。如果您需要更新DOM节点,请在mounted生命周期函数中执行操作。VUE 中有父子组件嵌套,当我子组件加载完成以后,那父组件是什么状态

在Vue中,父子组件嵌套时子组件的加载完成并不影响父组件的状态。当子组件完成加载后,Vue会将子组件的内容插入到父组件中,并执行父组件的生命周期钩子函数。

具体来说,当子组件加载完成后,父组件的mounted钩子函数会被调用。在mounted钩子函数中,可以访问子组件的DOM节点和数据。

需要注意的是,如果子组件中的数据是异步加载的,那么在父组件的mounted钩子函数中访问子组件的数据可能还没有加载完成。此时可以使用Vue提供的异步组件和webpack的动态import()语法来实现异步加载子组件和数据。

另外,如果是同时加载多个子组件,那么父组件的mounted钩子函数会在所有子组件完成加载后执行一次。如果需要在所有子组件加载完成后执行某些操作,可以在异步加载模块的回调函数中处理。

父子组件加载顺序应该是什么样的

在Vue中,父子组件的加载顺序是有规定的,具体如下:

首先加载父组件,父组件的创建过程是在beforeCreate和created钩子函数之间进行的。然后加载子组件,子组件的创建过程也是在beforeCreate和created钩子函数之间进行的。当子组件被创建完成之后,Vue会将子组件挂载到父组件上,这个过程在父组件的mounted钩子函数中进行。

值得注意的是,如果父组件中使用了v-if,当v-if表达式的值为false时,子组件不会被创建。而如果使用了v-show,子组件会被创建,但是不会立即被渲染到页面上。

另外,如果父组件和子组件中都有钩子函数,那么他们的执行顺序是先父组件再子组件。

简而言之,在Vue中,父组件和子组件的创建顺序是按照从父组件到子组件的顺序来进行的,而挂载的顺序则是从子组件到父组件的顺序来进行的。

父子组件之间如何进行通信?

在Vue中,父子组件之间可以通过Props和事件(Event)来进行通信。

1. Props

Props是用来传递数据给子组件的机制,父组件可以在引入子组件时通过Props进行传递。在子组件内部,可以通过this.$props来访问并使用Props。

举个例子,假设有一个父组件和一个子组件,父组件中有一个数据变量message,我们希望将这个变量传递给子组件。

{{message}}

在上面的例子中,父组件通过属性绑定将message变量作为message props传递给了子组件,子组件通过props选项声明了message props的类型。在子组件中就可以使用props.message访问并使用父组件中的变量了。

2. 事件(Event)

如果需要从子组件向父组件传递数据,则可以使用事件(Event)机制,在子组件中触发一个事件,由父组件监听并处理该事件。

假设父组件和子组件之间需要进行一个简单的计数器操作。

Count: {{count}}

Increase Count

在上面的例子中,子组件中的按钮通过监听click事件来触发父组件中的increaseCount方法。在触发事件时,使用了$emit方法来发送一个自定义的click事件。

通过上面的两个例子,我们可以看到Props和事件机制的使用非常简单和灵活,可以满足父子组件之间的大部分通信需求。

Vue3 中如何对传过来的数据类型进行限制,应该用哪个API?

在Vue3中,可以使用Props来限制传递给组件的属性类型。Props是组件的属性,用于接收外部传递的数据。

使用Props定义组件的属性时,可以指定数据类型、默认值、是否必须等选项。如果传递的数据类型不符合规定的类型,则会在浏览器控制台中显示警告信息。

下面是一个示例,展示如何在Vue3中使用Props限制数据类型:

{{title}}

{{text}}

在上面的示例中,定义了两个Props属性,分别是title和text。title属性必须为字符串类型,并且必须传递,否则会有警告信息;而text属性可以为字符串类型或为空,如果未传递,则使用默认值。

值得注意的是,即使使用Props限制了数据类型,也需要在组件内部对传递的数据进行正确性验证和处理,以确保应用程序的稳定性和安全性。

Vue3 没有传值的时候需要设置默认值,默认值如何去设置?

在 Vue 3 中,我们可以在组件内部使用 default 选项来设置默认值。

在没有传值的情况下,组件就会使用 default 选项中设置的默认值。如果父组件传递了 prop,则会覆盖 default 中的默认值。

具体使用方法如下:

在上面的例子中,我们设置了 default 选项为 0,如果父组件没有传递 count 属性,则 count 的默认值为 0。

需要注意的是,如果 default 的值是对象或数组,那么每个组件实例都会共享这个对象或数组的引用,如果你想让每个组件实例都有自己的独立的对象/数组引用,则应该使用一个 data 函数,该函数返回一个新的对象/数组。

下面是一个使用 data 函数设置默认值的例子:

在上面的例子中,我们通过 () => ({}) 函数返回一个新的空对象作为默认的 myObj 属性值,确保每个组件实例都有自己的独立的对象引用。

兄弟组件如何进行通信?有很多方法,请列举出来

在Vue中,兄弟组件之间的通信是一种非常常见的需求。

Vue提供了多种方法实现兄弟组件之间的通信,以下是其中一些常用的方法:

1. 使用 Props 传递数据

在 Vue 中,父组件可以通过 Props 把数据传递给子组件,而子组件可以通过 $emit 发射自定义事件来将数据传递给父组件。在这个机制的基础上,兄弟组件可以通过共同的父组件来进行通信。

2. 通过事件中心实现组件通信

Vue可以通过 $on、$emit方法来实现全局事件的监听和触发。在这个机制的基础上,可以创建一个Bus对象,作为事件中心在兄弟组件之间传递数据。

3. 使用 provide / inject 实现数据共享

利用 provide/inject 可以实现祖先组件向所有后代组件注入一个依赖,在后代组件中可以直接调用依赖中的方法,达到组件通信的目的。

4. 使用 Vuex 进行状态管理

Vuex是Vue官方提供的一个专为Vue.js应用程序开发的状态管理模式,它可以帮助开发者简化组件之间的通信,并且提供强大而直观的数据管理能力。

5. 通过$refs实现组件间调用方法

在Vue中,可以通过ref属性来获取到组件实例,然后可以通过调用组件实例中的方法来实现直接的函数调用。例如,兄弟组件中可以通过$refs获取到子组件的实例,从而调用子组件中的方法。

总之,以上是一些常见的兄弟组件通信的方法,开发者可以根据自己的实际需求和开发情况来选择适合自己的通信方式。

Webpakc相关题Webpack 的输出目录应该如何配置?输入目录如何配置?中间可能会经过预处理

输出目录和输入目录是Webpack中必须要进行配置的选项。

1. 输出目录

在Webpack中,输出目录可以通过output.path选项进行配置,例如:

module.exports = { // ... output: { path: path.resolve(__dirname, 'dist') }};

上面的代码指定将打包好的文件输出到项目根目录下的dist目录中。在打包完成后,输出的bundle.js文件和其他静态文件都会打包到dist目录中。

在进行生产环境打包时,还可以使用output.filename选项来对打包后的文件命名,例如:

module.exports = { // ... output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.[hash].js' }};

上面的代码将打包后的JS文件命名为bundle.[hash].js的格式,其中[hash]会根据文件的内容生成一个唯一的哈希值用于浏览器缓存。

2. 输入目录

通常Webpack的输入目录就是项目源代码目录,具体位置可以通过entry选项来配置。例如:

module.exports = { // ... entry: './src/main.js'};

上面的代码将项目的入口文件设置为src/main.js,Webpack会从这个文件开始递归地构建依赖图并打包输出到指定的目录中。

3. 经过预处理

在实际开发中,项目中可能会使用各种各样的打包工具、预处理器等,例如Babel、ESLint、Sass等,Webpack也支持对这些工具的预处理。这些预处理工具可以帮助开发者编写更高效、更易维护的代码。在Webpack中,可以在webpack.config.js中使用各种Loader和Plugins来进行预处理工作的配置。

例如,在使用Babel对ES6代码进行转换时,可以使用babel-loader,配置方式如下:

module.exports = { // ... module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }};

上面的代码将在Webpack中使用babel-loader进行ES6到ES5的转换,在options的presets选项中可以定义使用的babel插件,例如这里使用了@babel/preset-env插件,来对ES6代码进行转换。

总之,Webpack中的输入目录、输出目录以及预处理工作的配置,对于项目工程的构建和打包来说,都具有非常重要的作用。根据实际的项目需求和开发情况,开发者需要对Webpack的配置进行合理有效的设置和调整。

Webpack 里面可以开启 source maps,这是干什么的

开启source maps后,Webpack会在构建过程中生成Source Map文件,该文件会记录原始代码与打包后代码之间的映射关系。在调试开发时,开启source maps可以让开发者更方便地进行代码调试和错误定位。

在狭义上,开启source maps后,在浏览器中调试源代码时,开发者可以使用打包后的文件进行调试,因为包含了原始代码之间的映射关系,可以帮助开发者精确地定位错误。在代码压缩及混淆的情况下,通过source maps,开发者可以轻松找到原始代码中产生错误的位置。

在广义上,除了在浏览器开发工具中进行调试外,source maps还可以用于性能分析、代码分析、优化等方面的开发工作,例如通过性能分析工具,开发者可以准确地分析代码中的性能瓶颈,找到优化点,提升代码性能。

因此,在Webpack构建中开启source maps对于项目开发和优化非常有帮助,可以提高开发者的效率和代码性能。通常,在webpack配置文件中,可以通过设置devtool来配置source maps的类型,例如:

module.exports = { // ... devtool: 'cheap-module-eval-source-map'};

在打包时,Webpack会根据设置的devtool来生成对应的source maps文件。常见的source maps文件类型有eval/source-map/hidden-source-map/inline-source-map等。

Webpack 如何进行打包?

Webpack进行打包的过程可以分为三个步骤:

1. 读取与解析配置文件:

Webpack会读取代码中的webpack.config.js配置文件,并根据文件中的配置信息进行相关的打包。在配置文件中,开发者可以定义入口文件、打包后的产出目录、输出文件名、配置处理JS、CSS、图片、字体等静态资源文件的Loader和Plugins等。Webpack会解析并处理这些配置。

2. 构建依赖图:

通过入口文件,Webpack会自动递归解析所有被引用的模块,并构建出整个依赖图。这个依赖图为 Webpack 接下来的模块打包提供了对应的依赖关系。

3. 执行打包:

Webpack 会从入口文件开始,通过依赖图递归地进行打包。Webpack 按照预先设置的规则,将文件模块转成浏览器可识别的格式,并将这些模块打包到一个或多个文件中。在这个过程中,Webpack会依次处理每一个模块,并执行对应的Loader和Plugins对模块进行转换和处理。

打包的结果会输出到指定的目录下(通常是dist目录),生成到对应的文件中。

需要注意的是,在开发环境中,通常使用最基本的Webpack打包方式,只对代码进行简单转换和处理即可;而在生产环境中,常常会使用更为严格和全面的打包配置,以尽可能减少打包文件的体积、优化打包速度并提高代码性能。

Webpack 有哪些常用的loader和plugin

Webpack作为一款主流的前端构建工具,其Loaders和Plugins是其功能强大的核心部分,以下是一些常用的loader和plugin:

Loader:

(1)Babel-loader:用于将ES6 的代码转换成ES5标准的代码,使得浏览器可以兼容运行。

(2)CSS-loader:处理CSS中的URL、@import和浏览器兼容等问题。

(3)Style-loader:将CSS文件转换成内联的style标签。

(4)less-loader:将Less文件转换成CSS文件。

(5)Sass-loader:将Sass文件转换成CSS文件。

(6)file-loader:处理图片、字体等静态文件的加载问题。

(7)url-loader:可以将小于指定字节的图片、字体等资源文件转换成DataURL。

(8)vue-loader:用于解析Vue组件文件。

(9)html-loader:用于解析HTML文件中的图片、字体等资源文件。

Plugin:

(1)HtmlWebpackPlugin:生成html文件,并自动链接入口处需要使用的资源。

(2)CleanWebpackPlugin:用于清空构建输出文件夹的内容。

(3)HotModuleReplacementPlugin:用于热更新。

(4)MiniCssExtractPlugin:用于提取CSS到单独的文件中。

(5)ProvidePlugin:自动加载模块,而不必每次 import 或 require。

(6)DefinePlugin:定义全局变量。

(7)UglifyJsPlugin:代码压缩。

(8)CopyWebpackPlugin:用于将文件从源目录复制到构建目录。

(9)Webpack-bundle-analyzer:用于查看构建后的Bundle的构成和大小,来优化代码。

上述的 loader 和 plugin 只是简单列举了一部分,Webpack还有很多其他的 loader 和 plugin,开发人员可以根据自己的实际需求来选择使用。

用 webpack 启动 vue 项目

以下是使用Webpack启动Vue项目的一般步骤:

1. 安装依赖

首先需要安装Vue相关的依赖,例如Vue本身、Vue Router和Vuex等。

npm install vue vue-router vuex --save

2. 配置Webpack

接下来需要配置Webpack,包括处理JS、CSS等文件的Loaders以及如何输出产出文件等内容。Webpack配置的具体内容根据项目需求而定。

一个基础的Webpack配置文件可能长这样:

// webpack.config.jsconst path = require('path')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].bundle.js' }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } }, { test: /.vue$/, loader: 'vue-loader' }, { test: /.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html', filename: 'index.html' }) ]}

需要注意的是,以上只是一份非常基础的Webpack配置,具体的配置会根据具体项目而定。

配置Vue

接下来需要在Vue中配置相关内容。通常可以创建一个main.js文件来进行全局配置和页面的入口挂载:

// main.jsimport Vue from 'vue'import App from './App.vue'import router from './router'Vue.config.productionTip = falsenew Vue({ router, render: h => h(App)}).$mount('#app')

需要注意的是,这里的代码使用了路由器和App.vue组件,这需要在项目中做相应的安装和引入。

启动Webpack

完成了上述准备工作之后,就可以使用Webpack来启动开发服务器,即可在浏览器中访问项目页面了。

可以将启动命令定义在package.json文件中,例如:

{ "name": "my-vue-project", "scripts": { "dev": "webpack-dev-server --open" }, "dependencies": { "vue": "^2.6.10", "vue-router": "^3.0.3" }, "devDependencies": { "babel-loader": "^8.0.6", "css-loader": "^3.4.2", "html-webpack-plugin": "^3.2.0", "style-loader": "^1.1.3", "vue-loader": "^15.9.1", "webpack": "^4.41.5", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.10.3" }}

在项目目录下执行下面命令,即可启动应用。

npm run dev

大多数情况下就是启动Vue项目所需的全部步骤了。但具体的Webpack配置可能因项目需求而异。

webpack4 和 webpack5 的区别

Webpack 5相对于Webpack 4来说,有以下新特性与变化:

1. 更好的性能优化

Webpack 5在性能优化方面做了很多工作,例如引入了持久性缓存和更好的Tree Shaking算法,可以在构建时更快地实现更小的打包大小以及更高的构建速度。

2. 更好的chunk分离

Webpack 5引入了新的模块类型“module type”,可以更好地支持ES6模块语法,并对代码分离进行了优化。它可以使用splitChunksPlugin替代CommonsChunkPlugin来更好地处理打包后的代码分离,从而减少打包后的文件数量。

3. 支持Web Assembly

Webpack 5对Web Assembly(WASM)模块提供了原生的支持,这可以帮助开发人员更好地支持Web Assembly,并且可以优化构建过程。

4. 环境变量

Webpack 5引入了一种新的环境变量配置方法,可以通过直接指定环境变量的值来优化构建配置。

5. 模块热替换功能的改进

Webpack 5通过infrastructure logging来提供了更好的模块热替换(Hot Module Replacement)功能,以便更好地跟踪修改,从而更好地支持开发模式。

除了以上几点之外,Webpack 5还引入了一些其他的改进,如用于构建应用程序的 ‘output’ 和用于构建库的 ‘target’ 选项等。

总的来说,Webpack 5在构建速度和代码分离等方面都有很大的改进,并且提供了更好的Web Assembly支持和环境变量配置等特性。如果你想在Web项目中使用最新的Webpack,那么Webpack 5通常是更好的选择。

webpack 如何处理图片这种不是js 文件的css文件?

在Webpack中,可以使用file-loader和url-loader两个loader来处理图片等静态资源文件。

file-loader会将指定的文件移动到输出目录,并返回文件的URL。url-loader则可以在文件大小小于指定的limit值时,将文件转为DataURL作为模块导出,否则会被使用file-loader处理。

这里是基于Webpack 5 的配置示例:

module.exports = { module: { rules: [ { test: /.(png|jpe?g|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, // 限制打包文件的大小 name: 'images/[name].[ext]', esModule: false, }, }, ], }, { test: /.svg$/, use: [ { loader: 'file-loader', }, ], }, ], },};

在上述配置中,针对不同类型的图片文件使用了不同的loader。对于文件大小小于 8192 bytes (8KB) 的png、jpeg、gif文件,使用url-loader将其转为DataURL格式,而对于svg文件则使用file-loader处理,并将其移动到指定目录下。如果文件大小超过了8KB,则也会由file-loader进行处理。

通过定义这些loader,我们可以轻松地将项目中的图片资源在Webpack构建过程中自动进行处理,并最终打包输出到生成的文件中。

JS相关题把杂乱无序的数组变成从小到大排序,说几种方法。

对于杂乱无序的数组,有多种方法可以将其排序,以下是几种常用的方法:

1. 冒泡排序

冒泡排序是最简单的排序算法之一,其基本思想是比较相邻的两个元素,如果前面的比后面的大,则交换它们的位置。重复这个过程,依次比较每一对相邻的元素,直到最后一个元素被排序。

function bubbleSort(arr) { for(let i = 0; i < arr.length-1; i ) { for(let j = 0; j arr[j 1]) { let temp = arr[j 1]; arr[j 1] = arr[j]; arr[j] = temp; } } } return arr;}

2. 插入排序

插入排序的基本思想是从未排序的元素中依次取出一个元素,将其插入到已排序序列中的合适位置。重复这个过程,直到所有的元素都插入完成。

function insertionSort(arr) { for(let i = 1; i = 0 && arr[j] > key) { arr[j 1] = arr[j]; j--; } arr[j 1] = key; } return arr;}

3. 快速排序

快速排序是一种常用的排序算法,其基本思想是选取一个基准元素,将小于基准元素的元素放置在左侧,大于基准元素的元素放置在右侧,然后对左右两侧分别进行递归排序,最终得到有序序列。

function quickSort(arr) { if(arr.length <= 1) return arr; let pivotIndex = Math.floor(arr.length / 2); let pivot = arr.splice(pivotIndex, 1)[0]; let left = [], right = []; for(let i = 0; i < arr.length; i ) { if(arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat([pivot], quickSort(right));}

以上是常见的几种排序算法,除此之外还有选择排序、归并排序、堆排序等等。需要根据实际情况选择合适的排序算法。

实现一个深拷贝,说几种方法

深拷贝指的是在拷贝数据的同时,不会改变源数据的值,而是创建一个新的数据,并将源数据的值完全复制到新的数据中。

下面是几种实现深拷贝的方法:

1. 手写递归深拷贝函数

递归遍历所有的属性,如果是一个基本类型则直接赋值,如果是一个引用类型则递归调用该函数进行拷贝。

function deepCopy(obj) { let copy = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (typeof obj[key] === 'object' && obj[key] !== null) { copy[key] = deepCopy(obj[key]); } else { copy[key] = obj[key]; } } return copy;}

2. JSON.parse() 和 JSON.stringify()

利用JSON数据格式进行深拷贝。将需要拷贝的对象转换成JSON字符串再通过JSON.parse()方法将其转换成JSON对象。

let copy = JSON.parse(JSON.stringify(obj))

需要注意的是该方法有一些限制,例如无法拷贝函数,且会忽略 undefined 等属性。

3. 使用第三方库

可以使用一些第三方的深拷贝库,在代码中直接调用该库的深拷贝方法即可。

例如lodash库的 _.cloneDeep 方法:

const _ = require('lodash');let copy = _.cloneDeep(obj)

需要注意的是,使用第三方库会增加项目体积,不利于优化加载速度,因此需要在实现深拷贝时进行权衡。

闭包是什么?你怎么实现一个闭包? 你会怎么使用它?

闭包是指有权访问另一个函数作用域内变量的函数。

创建闭包最常见的方式就是在一个函数内部创建另一个函数,这个内部函数可以访问到外部函数的变量和参数。

闭包使得变量可以长期的驻留在内存中,不会被垃圾回收机制回收。

下面是一个简单的闭包实例:

function outer() { var name = "ChatAi"; function inner() { console.log(name); } return inner;}var fn = outer();fn(); //输出 "ChatAi"

在这个实例中,inner 函数访问了 outer 函数内的变量 name。而外部的 fn 函数实际上是 inner 函数,当执行 fn() 时,会输出 ChatAi。

实现一个闭包的关键在于在一个函数内部创建另一个函数,并且将这个内部函数作为外部函数的返回值,从而使这个函数可以在外部函数作用域之外被访问到。

闭包可以用来实现一些高级的编程技巧,例如模块化编程、惰性加载等,也可以用来缓存变量,提高程序的性能。但是,需要注意的是过度使用闭包可能会导致内存泄漏问题,因为闭包会一直持有其内部函数以及外部函数的作用域中的变量,这会导致这些变量无法被垃圾回收机制回收。因此,在使用闭包时需要谨慎使用,及时释放不需要的变量引用。

什么是引用类型?基本类型有哪些?

引用类型是指JavaScript中的数据类型,其值是对象。对象是一种复合值,可将其看作是属性的集合,每个属性都由名字和值组成。引用类型包括对象、数组、函数等。

而基本类型又称为简单类型,包括字符串、数值、布尔值、undefined和null。这些类型的值直接存储在变量所在的位置中,因此被称为基本类型。

引用类型和基本类型有一些区别,例如,在对基本类型进行赋值操作时,实际上是在变量中存储的是值本身,而在对引用类型进行赋值操作时,存储的是对象的引用地址而非对象本身。

此外,基本类型的比较是通过值来进行的,而引用类型的比较则是通过引用地址来进行的。

为什么用懒加载,懒加载是什么东西

懒加载是一种优化技术,它指的是在页面滚动到某个区域时,才开始加载对应区域的内容,而不是一次性加载整个页面的所有内容。这样可以有效降低页面的初始化时间,提高用户的体验。

懒加载可以应用在图片、视频、音频等资源的加载中,当用户滚动页面时,才会逐步加载对应的资源。它的作用在于减少页面的初始加载时间和数据流量,从而提高页面的响应速度和用户体验。

关于懒加载的等待时间和触发方式,具体取决于实际项目的需求和实现方式。一般来说,等待时间可以设置为页面滚动到特定位置或者用户停留在某个区域一定时间后触发。而触发懒加载的条件可以基于宏任务或微任务实现。

宏任务和微任务是JavaScript事件循环机制中的两种触发方式。宏任务包括定时器、事件回调和异步IO操作等,它们会放入主线程中执行;而微任务则包括Promise、异步函数等,它们会放在当前宏任务执行完后立即执行。在懒加载中,可以通过使用IntersectionObserver或滚动事件等方式监听页面的滚动位置,并将懒加载的任务添加到宏任务队列中,等待主线程执行。

懒加载触发的条件通常是指当页面滚动到特定位置或者用户停留在某个区域一定时间后,触发对应区域的懒加载。具体实现方式可以使用IntersectionObserver API进行监听,当目标元素和视口发生交叉时,就会触发回调函数并加载对应的内容。

需要注意的是,懒加载可以减少页面初始加载时间,但也有可能对用户体验造成一定影响。因为在页面滚动时,用户可能时不时地会看到页面闪烁、空白或内容突然出现的情况。因此,应该根据实际情况选择合适的懒加载方式,从而提高用户的体验。

Git相关题Git 基本命令

Git是一种分布式版本控制系统,通过Git可以更加方便地管理代码,协同开发等。下面是一些Git基本命令:

git init: 初始化新的本地仓库git clone [url]: 克隆远程仓库到本地git add [file]: 将文件添加到暂存区git commit -m "message": 将暂存区里的文件提交到本地仓库并添加提交信息git push: 将本地仓库中的文件推送到远程仓库中git pull: 将远程仓库中的文件更新到本地git branch: 查看本地分支git branch [name]: 创建分支git checkout [name]: 切换分支git merge [name]: 合并分支git log: 查看历史提交记录git diff: 查看所做修改的内容git stash: 暂存当前项目的改动,以便后续恢复。把当前的修改加入缓存区,应该用哪个API?

将当前修改加入缓存区可以使用 git add 命令来实现。在Git中,add 命令将当前目录下的修改添加到 Git 的暂存区中,以便于后续可以被提交到版本库中。

使用 git add 命令时,可以指定要添加到暂存区的具体文件,例如,如果要将 hello.txt 添加到暂存区,可以使用以下命令:

$ git add hello.txt

如果要将当前目录下的所有修改都加入到暂存区,可以使用以下命令:

$ git add .

上面的命令中的 . 表示当前目录。执行完上面的命令后,当前目录下的所有修改都会被添加到暂存区。

将当前缓存区的文件提交到本地仓库,应该怎么提交

将当前缓存区的文件提交到本地仓库可以使用 git commit 命令来实现。commit 命令将暂存区中的内容提交到本地仓库,并创建一个新的提交记录。

使用 git commit 命令时,可以在命令后面加上 -m 选项,以便在提交记录中添加提交信息。例如,执行以下命令可以将暂存区中的文件提交到本地仓库:

$ git commit -m "Add hello.txt"

上面的命令中的 "Add hello.txt" 即为提交信息,用于描述当前提交所做的修改。

执行完上面的命令后,Git会将暂存区中的文件提交到本地仓库并创建一个新的提交记录。提交记录包括提交信息、提交者信息、提交时间等信息。使用 git log 命令可以查看历史提交记录。

如何创建一个分支

创建一个分支可以使用 git branch 命令来实现。branch 命令用于查看、创建、删除分支等操作。

要创建一个新的分支,可以使用以下命令:

$ git branch [branch-name]

上面的命令中的 [branch-name] 表示要创建的新分支的名称。例如,要创建一个名为 dev 的新分支,可以执行以下命令:

$ git branch dev

执行完上面的命令后,Git会在当前所在的分支上创建一个名为 dev 的新分支。此时,切换到 dev 分支可以使用 git checkout 命令,例如:

$ git checkout dev

执行完上面的命令后,Git会将当前分支切换到 dev 分支,并将工作目录中的文件替换为 dev 分支上的内容。如果在 dev 分支上进行修改并提交,在 dev 分支上就会产生新的提交记录。

需要注意的是,新创建的分支不会自动与远程分支关联。如果需要将新创建的分支推送到远程仓库中,还需要使用 git push 命令来执行相应的操作。

解释下 git checkout -b new_branch

git checkout -b new_branch 是 Git 中创建并切换到一个新分支的快捷命令。该命令包含两个操作:

创建一个新分支,名称为 new_branch,并将分支指向当前所在分支的最新提交。切换到新的分支 new_branch 上。

具体来说,执行 git checkout -b new_branch 命令,相当于执行以下两个命令:

$ git branch new_branch$ git checkout new_branch

执行完这两个命令后,Git 会将当前分支切换到新分支 new_branch 上,此时的工作区和暂存区中的文件内容与当前所在分支的最新提交内容相同,可以在新分支上进行修改并提交。

需要注意的是,在使用 git checkout -b 命令之前,必须确认当前分支的所有修改已经被提交或暂存到暂存区,否则会在切换分支时出现问题。And,使用该命令只是本地创建并切换到一个新分支,如果需要将新分支推送到远程仓库中,还需要使用 git push 命令来执行相应的操作。

数据结构相关题有目录功能的项目怎么设计的? 从数据结构来讲应该是怎么样的结构?

有目录功能的项目可以通过树形数据结构来实现。

具体来说,可以使用节点来表示目录和文件,每个节点包含以下信息:

节点名称:表示目录或者文件的名字节点类型:表示该节点是目录还是文件子节点列表:表示该节点下的所有子节点,可以是目录或者文件

节点可以使用类来实现,例如:

class Node: def __init__(self, name, node_type): self.name = name self.node_type = node_type self.children = []

在实现目录功能时,可以首先创建根节点,根节点表示项目的根目录。然后依次添加子节点,如果子节点是目录,则添加到父目录的子节点列表中。

例如,下面的代码创建了一个包含两个目录和一个文件的树形结构:

root = Node("project", "directory")docs = Node("docs", "directory")src = Node("src", "directory")main = Node("main.py", "file")root.children = [docs, src, main]

通过树形结构,可以方便地遍历目录结构和查找文件。例如,可以使用递归来遍历整个目录树:

def traverse(node): print(node.name) for child in node.children: traverse(child)traverse(root)

上面的代码会遍历整个目录结构,并输出每个节点的名称。

react相关题简单说下 react

React是一个由Facebook开发的JavaScript库,主要用于构建用户界面。React的一大特点是采用组件化的开发模式,将UI拆分成独立的、可复用的组件。React使用声明式编程的方式,使得编写复杂的UI变得更加简单。

React的核心思想是“虚拟DOM”。在React中,所有的UI操作都转化为虚拟DOM的操作,React会将虚拟DOM与真实的DOM进行比较,只更新需要改变的部分,从而提高性能。

React也提供了一个强大的状态管理工具——Redux。在React中,Controller-View组件可以通过Redux来管理组件的状态,方便地实现组件间的数据共享和通信。

React可以与其他前端库和框架(如React Native、Vue等)进行配合使用,构建各种类型的应用程序。React的流行已经超过了Web开发的范畴,已经成为构建跨平台应用的首选技术之一。

react生命周期的简介/作用/应用场景

React组件生命周期可以分为三个阶段:Mounting(挂载)、Updating(更新)和Unmounting(卸载)。组件在挂载时会被创建并插入到DOM中,更新时会收到新的数据并重新渲染,卸载时则会被移除出DOM。

React生命周期的主要作用是控制组件的渲染流程,以及在不同的阶段执行不同的操作。根据组件的阶段,React生命周期提供了不同的方法,开发者可以在这些方法中编写自定义逻辑。

React生命周期的应用场景包括:

初始化组件数据:在组件挂载之前,可以在constructor()中初始化组件数据。发送网络请求:在componentDidMount()中可以发送网络请求,获取数据并更新组件状态。监听组件属性变化:在componentDidUpdate()中可以监听到组件属性的变化,并根据变化进行相应的操作。销毁组件:在componentWillUnmount()中可以进行组件销毁的操作,例如清除定时器、取消网络请求等。性能优化:在shouldComponentUpdate()中可以判断组件是否需要被重新渲染,从而优化组件性能。处理错误:在componentDidCatch()中可以捕获组件内部的错误,从而更好地处理异常情况。

总的来说,React生命周期的应用场景非常广泛,可以用于初始化组件数据、发送网络请求、监听组件属性变化、性能优化、处理错误等。掌握React生命周期可以提高React应用的开发效率和性能。

网络相关题http 和 https 有什么区别

HTTP(HyperText Transfer Protocol)和HTTPS(HyperText Transfer Protocol Secure)都是应用层协议,都是用于客户端和服务器端之间传输数据的协议,但是它们之间有以下几点区别:

安全性:HTTP协议基于TCP/IP协议来传递数据,不具备加密功能,而HTTPS则在HTTP和TCP/IP之间增加了SSL/TLS协议,通过使用公开密钥和私有密钥来进行加密,保证了数据传输的安全性。使用端口不同:HTTP默认使用80端口进行通信,而HTTPS默认使用443端口进行通信。性能:HTTPS协议因为加入了加密解密的过程,所以相对于HTTP协议来说,通信速度更慢、占用CPU资源更多,但是在现代计算机和网络环境下这种差异已经不大。证书方面:HTTPS需要使用HTTPS数字证书,这一数字证书可以验证网站及其所有者的身份,验证证书的过程需要消耗资源,但是可以保证服务器端是可信的,并保证数据传输的完整性和可靠性。

综上所述,HTTPS相对于HTTP来说,具有更高的安全性和可靠性,但是相应地有更多的性能消耗。在需要保护用户隐私和敏感信息的情况下,使用HTTPS是更好的选择,而在传输一般的信息和数据时,则可以使用HTTP协议。

从地址栏输入一个地址到页面出来,有哪些过程

从地址栏输入一个地址到页面出来的过程大致有以下几个步骤:

DNS解析:浏览器根据网址中的域名发送DNS请求,将域名解析为对应的IP地址,以便之后能够访问该网站。建立TCP连接:浏览器将请求发送给服务器,建立TCP连接,而HTTP/HTTPS请求通常使用TCP作为传输协议。发送HTTP请求:浏览器向服务器发送HTTP请求,并等待服务器的响应。HTTP请求由请求行、请求头和请求体组成,其中请求头包含了一些请求的参数信息。服务器响应请求:服务器接收到客户端的请求后,根据请求内容生成相应的响应,响应也由响应行、响应头和响应体组成,其中响应头包含了一些应的参数信息。下载HTML文件:浏览器接收到HTML响应后,解析HTML文件,并根据HTML文件中的标记生成DOM树和CSSOM树,其中DOM树表示HTML的结构,CSSOM树表示样式的结构。解析渲染页面:浏览器根据DOM树和CSSOM树生成渲染树,然后将渲染树渲染到屏幕上显示给用户,至此,页面加载完毕。

需要注意的是,不同的网站可能会存在不同的数据请求和资源加载过程,例如JavaScript文件、图片、视频等。每个请求和资源的加载过程都可能会导致额外的网络请求和服务器响应,从而影响页面的加载速度和性能,需要进行合理的优化和处理。

其他为什么可以实现无状态登录

无状态登录是指在用户登录认证后,服务器不记录任何用户信息而仅仅返回一个安全的凭证给客户端,客户端在以后的请求中携带凭证实现请求的认证和授权。这种认证方式,相对于传统的有状态登录方式,减轻了服务器的负担,提高了系统的扩展性和可伸缩性。

可以实现无状态登录的原因,主要是基于以下几点考虑:

安全性:无状态登录通过采用令牌或者加密技术保证了用户信息的安全,即使请求被劫持也无法伪造。性能:无状态登录避免了每个请求都需要验证中央数据库,减少了内存和CPU的消耗,同时减少了网络传输的数据量,从而提高了系统的性能和响应速度。扩展性:无状态登录允许多个服务器实例无缝协作,需要共享认证数据时只需要进行数据同步即可,不需要同步所有的会话数据,有效提高了系统的可伸缩性和可扩展性。

需要注意的是,无状态登录虽然有很多优点,但也存在一些缺点。例如在大型应用程序中,需要使用分布式缓存和令牌续期等技术来改善通信和安全性,这会带来一些额外的复杂性。另外,由于服务器无状态化,需要对所有请求进行验证和认证,对程序的编写和调试都产生了一定的挑战。

SSR 是什么?是怎么实现的

SSR全称为Server Side Rendering,指的是将网页应用的前端渲染工作转移到服务端完成,最终向客户端返回已经完整渲染好的HTML页面,使得客户端能够更快地看到首屏内容,提高了页面响应速度和用户体验。而传统的SPA单页应用,是通过浏览器执行JavaScript代码进行前端渲染,并将动态更新的内容加载到页面中。

实现SSR主要有以下几个步骤:

确定需要服务端渲染的页面,例如网站的首屏、SEO页面等。编写服务端代码,读取所需数据,并把数据注入到模版中。在服务端使用渲染引擎,例如Vue的Vue-Server-Renderer或 React的Next.js等,将包含注入数据的模版编译成完整的HTML。客户端通过访问服务端获取完整的HTML页面,将其渲染到浏览器中展示。

SSR的实现主要涉及到两大块内容,前端构建和后端渲染。前端构建是指开发人员使用Vue、React等前端框架和构建工具,根据路由等所需的数据和组件等信息,生成前端所需要的JavaScript文件、静态资源和模版等,以及对SEO的优化。后端渲染则是通过服务端引擎来执行服务端渲染,并根据返回的结果生成完整的HTML页面,将其返回给浏览器端渲染展示。

SSR的优点包括提高页面的响应速度、增强SEO效果、利于搜索引擎爬虫的索引和提高页面流量等。与此同时,SSR也存在一些缺点,需要服务器强大的性能和负载能力、开发难度较高、开发维护成本较高等。因此,在实现SSR时,需要根据具体的项目需求和技术实现选型等因素进行综合考虑。

你为什么要学前端

当有人问为什么要学前端,您可以从以下几个方面来回答:

前端技术的广泛应用:随着互联网行业的快速发展,前端技术已经被广泛应用于网站、手机app、H5游戏、小程序等多个领域,前端工程师已经成为整个互联网行业中不可或缺的一部分。前端技术的全面性:前端技术涵盖了HTML、CSS、JavaScript、Node.js等多个方面,要求开发人员具备广泛的技术深度和宽度,这样可以提高工程师的就业竞争力,并且有助于他们全面发展自己的技术。前端开发的高薪和优越的就业前景:前端工程师是互联网行业中薪酬较高的职业之一,同时他们也拥有广阔的就业空间和内部发展机会,在许多企业完整的IT体系中,前端开发工程师是不可或缺的一份子。个人兴趣爱好:前端开发工程师可以创造、设计、编写并交付能够在网络中随时随地使用的Web应用程序,有一定创造性和挑战性,对一些追求自我实现的人来说有很大的吸引力。

通过上述的回答,可以让问者了解前端技术在互联网行业中的重要性,以及前端开发工程师所扮演的角色和前景。同时也可以让他们了解前端技术的全面性和个人兴趣方面,为他们选择前端开发工程师岗位提供参考和帮助。

0
点赞
赏礼
赏钱
0
收藏
免责声明:本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本网证实,对本文以及其中全部或者 部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。 凡本网注明 “来源:XXX(非本站)”的作品,均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对 其真实性负责。 如因作品内容、版权和其它问题需要同本网联系的,请在一周内进行,以便我们及时处理。 QQ:617470285 邮箱:617470285@qq.com
关于作者
乖乖(普通会员)
文章
366
关注
0
粉丝
0
点击领取今天的签到奖励!
签到排行

成员 网址收录40329 企业收录2981 印章生成186770 电子证书796 电子名片49 自媒体20815

@2022 All Rights Reserved 浙ICP备19035174号-7
0
0
分享
请选择要切换的马甲:

个人中心

每日签到

我的消息

内容搜索