IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue前端面试题 -> 正文阅读

[JavaScript知识库]vue前端面试题

1:Vue解决了什么问题?

①虚拟dom:dom操作时非常耗性能的,不再使用原生的dom操作节点,极大的解放dom操作,但具体操作的还是dom,不过是换了一种方式。
②视图、数据、结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作。
③组件化:把一个单页应用中的各种模块拆分到一个一个单独的组件中,便于开发,以及后期的维护

2:MVVM的理解?

MVVM就是Model-View-ViewModel的缩写,MVVM将视图和业务逻辑分开。
View:视图层,Model数据模型,而ViewModel是把两者建立通信的桥梁。
在MVVM框架下,View和Model之间没有直接的联系,而是通过ViewModel进行交互。View和ViewModel之间以及Model和ViewModel之间的交互都是双向的,因此view数据的变化会同步到Model中,而Model数据的变化也会立即反映到View上。可以说它们两者是实时更新的,互相影响。 ViewModel通过双向数据绑定把View层和Model层连接了起来,而View和Model之间的同步工作完全是自动的,因此开发者只需要关注业务逻辑,不需要手动操作DOM,也不需要关注数据状态的同步问题,这些都由MVVM统一管理。

在这里插入图片描述

3:如何实现一个自定义组件?

创建子组件的文件,建立组件的模板,把架子搭起来,也就是在子组件中写好template视图层,script逻辑层style css样式层。然后定义好props里面的数据,实现子组件需要的逻辑代码后,也就封装好了,然后直接调用即可。调用import引入,同时在父组件script(逻辑层)中的components这个对象中写入组件名称,最后挂载到父组件的template中即可。

4:不同组件之间是如何通信的?

①props / e m i t 父 组 件 通 过 p r o p s 的 方 式 向 子 组 件 传 递 数 据 , 而 通 过 emit 父组件通过props的方式向子组件传递数据,而通过 emitpropsemit子组件可以向父组件通信。 ②$children
/ p a r e n t t h i s . parent this. parentthis.children[0].msg = “hello world” //父组件修改子组件data中的数据
this.$parent.mag //子组件拿到父组件data中的数据

c h i l d r e n 的 值 是 数 组 , children的值是数组, childrenparent的值是个对象
注意: p a r e n t , parent, parentchildren它们的目的是作为访问数组的应急方法,更推荐用props和events实现父子组件通信。

③provide / inject

这是vue2.2.0新增的api,简单来说就是父组件中通过provide来提供变量,然后再子组件中通过inject来注入变量。

//父组件
export default{
    name:"A",
    provide:{
        for:"demo"
    },
    components:{
        comB
    }
}

//子组件
export default{
    name:"B",
    inject:["for"],
    data(){
        demo:this.for
    }
}

④ref / refs

ref:如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例,可通过实例直接调用组件的方法或访问数据。

<template>
    <component-a ref="comA"></component-a>
</template>
<script>
    export default{
        mounted(){
            const comA = this.$refs.comA;
            console.log(comA.name)//Vue.js
            comA.sayHello() //hello
        }
    }
</script>
 //子组件
export default{
    data(){
        return {
            name:"Vue.js"
        }
    },
    methods:{
        sayHello(){
            console.log("hello")
        }
    }
} 

⑤eventBus(Bus总线):

//首先在src中创建一个Bus文件夹 => index.js
import Vue from "vue";
export default new Vue({
    
})

//子组件1(发送数据的组件)
<button @click="add()">点击</button>
import Bus from "@/Bus"
add(){
    Bus.$emit("add",this.content);
}

//子组件2(接受数据的组件)
<p>{{tit}}</p>
import Bus from "@/Bus";
created(){
    Bus.$on("add",(data) => {
        this.tit = data;
    })
} 

⑥Vuex;
⑦LocalStorage;
⑧$attrs / l i s t e n e r s 将 数 据 挂 在 到 子 组 件 的 标 签 上 去 后 , 在 子 组 件 中 使 用 t h i s . listeners 将数据挂在到子组件的标签上去后,在子组件中使用this. listeners使this.attrs直接获取到所有挂载的数据,返回的是一个对象。

5:nextTick 的理解?

使用nextTick的原因:Vue是异步修改DOM的,并且不鼓励开发者直接接触DOM,但是有时候需要必须对数据更改后的DOM元素做相应的处理,但是获取到的DOM数据并不是更改后的数据,这时候就需要this.$nextTick();
原理:Vue通过异步队列控制DOM更新和nextTick回调函数先后执行的方式。

使用:

<button @click="change()">按钮</button><h1 ref="gss">{{msg}}</h1>
//JS
export default{
    name:"app",
    data(){
        return {
            msg:"123"
        }
    },
    methods:{
        change(){
            this.msg = "456";
            console.log(this.refs["gss"].innerHTML)//123
            this.$nextTick(function(){
                console.log(this.refs["gss"].innerHTML)//456
            })
        }
    }
    
}

6:Vue的生命周期(11个钩子函数)?

⑴beforeCreate(创建前):在此生命周期函数执行的时候,data和methods中的数据都还没有初始化。
⑵created(创建后):在此生命周期函数中,data和methods都已经被初始化好了,如果要调用 methods中的方法,或者操作data中的数据,最早只能在created中操作。
⑶beforeMount(载入前):在此生命周期函数执行的时候,模板已经在内存中编译好了,但是尚未挂载到页面中去,此时页面还是旧的。
⑷mounted(载入后):此时页面和内存中都是最新的数据,这个钩子函数是最早可以操作dom节点的方法。
⑸beforeUpdate(更新前):此时页面中显示的数据还是旧的,但是data中的数据是最新的,且页面并未和最新的数据同步。
⑹Updated(更新后):此时页面显示数据和最新的data数据同步。
⑺beforeDestroy(销毁前):当执行该生命周期函数的时候,实例身上所有的data,所有的methods以及过滤器…等都处于可用状态,并没有真正执行销毁。
⑻destroyed(销毁后):此时组件以及被完全销毁,实例中的所有的数据、方法、属性、过滤器…等都已经不可用了。
//下面两个钩子函数一般配合使用
⑼activated(组件激活时):和上面的beforeDestroy和destroyed用法差不多,但是如果我们需要一个实例,在销毁后再次出现的话,用beforeDestroy和destroyed的话,就太浪费性能了。实例被激活时使用,用于重复激活一个实例的时候
⑽deactivated(组件未激活时):实例没有被激活时。
⑾errorCaptured(错误调用):当捕获一个来自后代组件的错误时被调用

7: 虚拟DOM原理

虚拟DOM,其实就是用对象的方式取代真实的DOM操作,把真实的DOM操作放在内存当中,在内存中的对象里做模拟操作。当页面打开时浏览器会解析HTML元素,构建一颗DOM树,将状态全部保存起来,在内存当中模拟我们真实的DOM操作,操作完后又会生成一颗dom树,两颗DOM树进行比较,根据diff算法比较两颗DOM树不同的地方,只渲染一次不同的地方。

补充:

diff算法核心: ①如何用vnode生成一个dom的节点 patch方法patch(container,
vnode)patch(vnode, newVnode) ②vnode和newVnode的对比 ③修改改变的dom节点
replacechildrencreateElement

8:双向绑定的原理?数据劫持?

mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

在这里插入图片描述
几个要点:

1、实现一个数据监听器 Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数 3、实现一个 Watcher,作为连接
Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者

9:Proxy相比于defineProperty的优势?

Vue3.0摒弃了Object.defineProperty,改为基于Proxy的观察者机制探索。
首先说一下Object.defineProperty的缺点:
? ①Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实施响应。
? ②Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue2.X里,是通过递归 + 遍历data对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象才是更好的选择。
而要取代它的Proxy有以下两个优点:
? 可以劫持整个对象,并返回一个新对象。
? 有多种劫持操作(13种)

补充:

? Proxy是ES6新增的一个属性,翻译过来的意思就是代理,用在这里表示由它来“代理”某些操作。Proxy让我们能够以简洁易懂的方式控制外部对象的访问,其功能非常类似于设计模式中的代理模式。
? Proxy可以理解为,在目标对象之前设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
? 使用Proxy的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。从而可以让对象只需要关注核心逻辑,达到关注点分离,降低对象复杂度等目的。

10:watch、computed和methods的区别

? methods即是方法,封装的功能代码块,调用后执行。在重新渲染的时候每次都会被重新的调用; ? computed
是自动监听依赖值的变化,从而动态返回内容,主要目的是简化模板内的复杂运算。所以区别来源于用法,只是需要动态值,那就用 computed ;需要知道值的改变后执行业务逻辑,才用 watch。 ?
watch也可以影响数据的变化,当绑定的数据方法变化时触发响应的函数,需要在数据变化时执行异步或开销较大的操作时使用watch。

11:virtual-dom原理实现(虚拟dom)?

virtual-dom(简称vdom)的概念大规模的推广还是得益于react的出现,virtual-dom也是react这个框架的非常重要的特性之一。相比于频繁的手动去操作dom而带来性能问题,vdom很好的将dom做了一层映射关系,进而将在我们本需要直接进行dom的一系列操作,映射到了操作vdom,而vdom上定义了关于真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作,并将这些操作放到vdom中进行,这样就通过操作vdom来提高直接操作的dom的效率和性能。
在vue的整个应用生命周期当中,每次需要更新视图的时候便会使用vdom,vdom算法是基于snabbdom算法所做的修改。

实现:

①用js对象构造一个虚拟的dom树,插入到文档中;
②状态变更时,记录新树和旧树的差异;
③把上面的差异构建到真正的dom中。

12:vue-router路由模式?

①hash(哈希默认)模式:使用 URL hash 值来作路由。默认模式。
②history(mode:history)模式: 依赖 HTML5 History API 和服务器配置。查看 HTML5 History 模式。
③abstract模式(严格模式):支持所有JavaScript 运行环境,如 Node.js 服务器端。 根据mode参数来决定采用哪一种方式。
vue-router的实现原理(核心):更新视图但不重新请求页面。

13: vue-router登陆权限的判断?

vue-router的登陆权限判断主要是在全局钩子函数中进行的,我们在router.js文件中的定义路由里,将需要登陆权限的页面加上meta属性,值是对象的形式,然后在该对象中自定义一个属性,属性值就是一个Boolean值,这时候在main.js文件的全局钩子函数中进行判断,如果需要跳转的页面的自定义属性值为true,那么将进行判断其是否登录,如果没有登录,则告诉用户登录,如果有登录,那么进行页面跳转。

routes:[
    {
        path:"/home",
        name:"Home",
        components:Home
        meta:{requireAuth:true}
    }
] 
router.beforeEach((to,from,next) => {
    if(to.meta.requireAuth){//判断该路由是否需要登录权限
        if(store.state.token){//通过vuex的state获取当前的token是否存在
            next()
        }else{
            next({
                path:"/one",
                query:{redirect:to.fullPath}//将跳转的路由path作为参数,登陆成功后跳转到该路由
            })
        }
    }else{
        next();
    }    
})

14:vue-router路由嵌套?

routes:[ 
	{ 
	  path:"/home", 
		name:"Home",
       components:Home, 	
	    children:[ 
		{ 
			path:"child", name:"Child",
		  	components:"Child" 
		} 
	] 
} ]

15: Vuex的理解?Vuex的五大核心?

定义:Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式储存管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
使用场景:需要构建一个中大型单页应用,您很可能会考虑如何更好的在组件外部管理状态,Vuex将会成为自然而然的选择。
优点:当你在state中定义了一个数据之后,可以在所在项目中的任何一个组件里进行获取、进行修改、并且你的修改可以得到全局的响应变更。
①state:定义初始数据。 ②mutations:更改Vuex的store中的状态的唯一方法是提交mutation
③getters:可以对 state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性,但是 getters
可以在多给件之间复用如果一个状态只在一个组件内使用,是可以不用 getters。
④actions:异步操作初始数据,其实就是调用mutations里面的方法。
⑤module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。

16 : Vue.js的特点

? 简洁:页面由HTML模板+Json数据+Vue实例组成 ? 数据驱动:自动计算属性和追踪依赖的模板表达式
? 组件化:用可复用、解耦的组件来构造页面 ? 轻量:代码量小,不依赖其他库 ? 快速:精确有效批量DOM更新
? 模板友好:可通过npm,bower等多种方式安装,很容易融入

17:Vuex的运行机制?

Vuex提供数据(state)来驱动视图(components),通过dispath派发actions,在其中可以做一些异步的操作,然后通过commit来提交mutations,最后mutations来更改state。

在这里插入图片描述

18:Vuex的映射?

state(数据)、getters(计算属性)需要映射在computed实例中,而mutations(同步操作放),actions(异步操作方法)等需要放在methods实例中

computed:{
    ...mapState([
        "list",
    ])
}
methods:{
    ...mapMutations([
        "changes",
    ])
}

19:描述下vue从初始化页面–>修改数据–>刷新页面UI过程?

当Vue进入初始化阶段时,一方面Vue会遍历data中的属性,并用Object.defineProperty将它转化成getter/setterd的形式,实现数据劫持;另一方面,Vue的指令编译器Compiler对元素节点的各个指令进行解析,初始化视图,并订阅Watcher来更新视图,此时Watcher会将自己添加到消息订阅器Dep中,此时初始化完毕。
当数据发生变化时,触发Observer中setter方法,立即调用Dep.notify(),Dep这个数组开始遍历所有的订阅者,并调用其update方法,Vue内部再通过diff算法,patch相应的更新完成对订阅者视图的改变。

20:Vue的响应式原理?

当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

21:插槽的理解?

插槽就是父组件往子组件中插入一些内容。 有三种方式,默认插槽,具名插槽,作用域插槽

  1. 默认插槽就是把父组件中的数据,显示在子组件中,子组件通过一个slot插槽标签显示父组件中的数据。
  2. 具名插槽是在父组件中通过slot属性,给插槽命名,在子组件中通过slot标签,根据定义好的名字填充到对应的位置。
  3. 作用域插槽是带数据的插槽,子组件提供给父组件的参数,父组件根据子组件传过来的插槽数据来进行不同的展现和填充内容。在标签中通过slot-scope来接受数据。

22:vue-router有哪几种导航钩子?

① 全局导航钩子:一般用来判断权限,以及页面丢失时需要执行的操作;

 beforeEach()每次路由进入之前执行的函数。
 afterEach()每次路由进入之后执行的函数。
 beforeResolve()2.5新增

② 单个路由(实例钩子):某个指定路由跳转时需要执行的逻辑。

beforeEnter()
beforeLeave()

③ 组件路由钩子:

beforeRouteEnter()
beforeRouteLeave()
beforeRouteUpdate()

23:vue组件中的data为什么是一个函数?

如果data是一个函数的话,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。Object是引用数据类型,里面保存的是内存地址,单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。 所以说vue组件的data必须是函数。

24:路由懒加载?

路由懒加载的应用场景:当项目很大的时候,为了提升用户体现,则必须使用懒加载。否则,首页会一次导入所有页面与组件。需要加载的内容过多,延时过长,不利于用户体验。但项目很小,则不推荐使用,项目小,分开后的懒加载会发多次请求,带来更多的性能缺陷;
路由懒加载的原理:vue 异步组件技术:异步加载,vue-router 配置路由 , 使用 vue 的异步组件技术 , 实现按需加载。

常用的懒加载方式有两种:即使用vue异步组件 和 ES中的import 1、vue异步组件实现路由懒加载

component:resolve=>([‘需要加载的路由的地址’,resolve])

2、es提出的import(推荐使用这种方式)

const HelloWorld = ()=>import(‘需要加载的模块地址’)

25:Vue.js介绍?

Vue.js是一个轻巧、高性能、可组件化的MVVM库,同时拥有非常容易上手的API;Vue.js是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue采用自底向上增量开发的设计。Vue的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合。数据驱动+组件化的前端开发。通过尽可能简单的API实现响应的数据绑定和组合的视图组件。核心是一个响应的数据绑定系统。

26:多环境变量

我一般使用多环境变量配置axios请求的baseURL,首先我在vue根目录下创建.env文件,用来写一些默认的配置信息;然后我会根据需要添加本地开发环境(.env.development)和生产环境的(.env.production)的配置信息,vue会根据配置信息自动获取变量值,然后在axios中使用process.env获取到相应的baseURL

27:对axios封装(url统一管理、axios请求拦截、响应拦截、函数封装)

首先要安装axios,一般我会在项目的src目录中,新建一个network文件夹,作为我们的网络请求模块,然后在里面新建一个http.js和一个api.js文件和一个reques.js。http.js文件用来封装我们的axios,api.js用来统一管理我们的接口url,
在request.js中添加请求拦截和响应拦截。在请求拦截中,会给请求头添加token字段,还有loading动画的开启。在响应拦截中,可以做一些loading动画的关闭,还有可以根据后端返回的状态码,做一些检验token是否有效或者过期的操作。接着就是做一些axios进行的api接口的封装,这里我用到了async,await封装请求接口函数,这样可以将异步操作同步化操作,代码更加友好,避免回调地域的出现。

28:Keep-alive

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。keep-alive
是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。

在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated(组件激活时使用) 与
deactivated(组价离开时调用)

如果需要缓存整个项目,直接在app.vue中用keep-alive包裹router-view即可。要缓存部分页面,需要在路由地址配置中,在meta属性中添加一个状态,在app.vue中判断一下包裹的router-view即可

29:常见的指令,修饰符

常用指令

在vue中提供了一些对于页面 + 数据的更为方便的输出,这些操作就叫做指令,指令中封装了一些DOM行为, 结合属性作为一个暗号,
暗号有对应的值,根据不同的值,框架会进行相关DOM操作的绑定 vue中的指令有很多,我们平时做项目常用的有:
v-if:是动态的向DOM树中添加或者删除元素;
v-else是搭配v-if使用的,它必须紧跟在v-if或者v-else-if后面,否则不起作用
v-show:是通过标签的CSS样式display的值是不是none,控制显示隐藏
区别:
1、当条件为真的时候 没有区别
当条件为假的时候 v-if通过创建或删除DOM节点来实现元素的显示隐藏,v-show通过css中的display属性来控制
2、v-if更适合数据的筛选和初始渲染 v-show更适合元素的切换 v-for:v-for是根据遍历数据来进行渲染,要配合key使用,要注意的是当v-for和v-if同处于一个节点时,v-for的优先级比v-if更高。这意味着v-if将运行在每个v-for循环中
v-on:用来绑定一个事件或者方法,简写方式是@click="" v-bind:
v-bind用来动态的绑定一个或者多个属性。没有参数时,可以绑定到一个包含键值的对象。常用于动态绑定class和style。以及href等。简写的方式是“:属性名=""”一个冒号
v-model 只能适用于在表单元素上,可以实现数据双向绑定

修饰符:

在Vue中,事件修饰符处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。在Vue中事件修饰符常用的主要有:
?.stop :阻止事件冒泡:由内而外,通俗的将就是阻止事件将向上级DOM元素传递
?.capture:事件捕获:由外而内,在捕获阶段,事件从window开始,之后是document对象,一直到触发事件的元素。
?.self:当事件作用在元素本身时才会触发 ? .once :只触发一次 ? .prevent: 阻止默认事件
?passive:告诉浏览器你不想阻止事件的默认行为 ? ?trim:自动过滤用户输入的首尾空格 语法:@事件名.修饰符=“方法名”

30:v-for中key的作用?

key相当于给每一个虚拟dom节点的唯一id,也是diff的一种优化策略,可以根据key更快,更精准的找到相应的虚拟dom节点

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:04:45  更:2021-07-15 16:04:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/28 11:44:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码