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知识库 -> 79-高阶 -> 正文阅读

[JavaScript知识库]79-高阶

mixin

Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个 mixin 对象可以包含任意组件选项。当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。

mixin会和原本组件的选项里的数据合并(例如data,methods之类),组件的选项优先级高于mixin,如果有相同的会被替换,如果是生命周期的钩子函数,会新执行mixin再执行组件里的钩子函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="js/vue.js"></script>
</head>

<body>
    <div id ="app1">

    </div>
    <p>--------</p>
    <div id ="app2">
    </div>
    <script>
    // 定义一个mixin对象
    const myMixin={
        data() {
            return{
                msg:'hello'
            }
        },
        methods: {
            hello(){
                alert('mehhh')
            }
        },
        mounted () {
          console.log('先加载mixin')  
        },
    }
     const app1 = Vue.createApp({
        data(){
            return{
            	msg:"组件里优先级更高“
                site:"kkk.com"
            }
        },
        methods:{
            change(){
                alert('哈哈')
            }
        },
        mixins: [myMixin],
        template:`
            <div>
                <h1>{{msg}}</h1>
                <h1>{{site}}</h1>
                <button @click="hello">点我</button>
                <button @click="change">改变</button>
            </div>
        `,
         mounted () {
          console.log('后加载组件的钩子函数')  
        },
     });
     app1.mount('#app1');
     const app2 = Vue.createApp({
        mixins: [myMixin],
        template:`
            <div>
                <h1>{{msg}}</h1>

                <button @click="hello">点我</button>

            </div>
        `
     });
     app2.mount('#app2');
    </script>
</body>

</html>

site是合并的,msg取优先级更高的,钩子函数先后执行

当mixin里为自定义属性时,不能直接引用,组件挂载最终是再options上通过options进行获取
但是如果有相同属性会被覆盖,可以通过配置改变,也可全局配置mixin

      //  通过配置绝对使用哪个里面的属性
      app1.config.optionMergeStrategies.age = (mixinVal, appValue) => {
      //改变return的顺序,可改变优先级
        return mixinVal || appValue;
      };
      app1.mount("#app1");
    // 全局配置mixin
    app1.mixin({

    });
  <body>
    <div id="app1"></div>
    <script>
      // 定义一个mixin对象
      const myMixin = {
        //   自定义属性
        age: 100,
      };
      const app1 = Vue.createApp({
        mounted () {
          console.log(this.$options);
        },

        data() {
          return {
            msg: "hhh",
          };
        },
 
        methods: {
          hello() {
            alert("哈哈");
          },
        },
        age:99,
        mixins: [myMixin],
        template: `
            <div>
                <h1>{{msg}}</h1>
                <h1>{{age}}</h1>
                直接引用mixin的自定义属性是不会出现的,需要运用到this.$options,
                <h1>{{this.$options.age}}</h1>
                <button @click="hello">点我</button>
            </div>
        `,
      });

      //  通过配置绝对使用哪个里面的属性
      app1.config.optionMergeStrategies.age = (mixinVal, appValue) => {
        return mixinVal || appValue;
      };
      app1.mount("#app1");
    // 全局配置mixin
    app1.mixin({

    });
    </script>
  </body>

自定义指令

自定义全局指令

// 自定义全局指令
  app.directive('focus', {
      mounted (el) {
         //   自定义获取焦点
           el.focus();
      }
   });
  <body>
    <div id="app"></div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            msg: "hello",
          };
        },
        template: `
            <div>
                <input placeholder="请输入姓名" v-focus>
                </div>
        `,
      });

      // 自定义全局指令
        app.directive('focus', {
            mounted (el) {
               //   自定义获取焦点
                 el.focus();
            }
         });

      app.mount("#app");
    </script>
  </body>

自定义局部指令

使用directives: lkDirective,引入

  <body>
    <div id="app"></div>
    <script>
    //定义一个局部自定义指令
      const lkDirective = {
        focus: {
          mounted(el) {
            el.focus();
          },
        },
      };
      const app = Vue.createApp({
        data() {
          return {
            msg: "hello",
          };
        },
        template: `
            <div>
                <input placeholder="请输入姓名" v-focus>
                </div>
        `,
        //   挂载局部指令
        directives: lkDirective,
      });


      app.mount("#app");
    </script>
  </body>

自定义指令的钩子函数

<body>
    <div id ="app">
    </div>
    <script>
        const lkDirective ={
            focus:{
                created () {
                  console.log('created')  
                },
                beforeMount () {
                    console.log('beforeMount')
                },
                mounted (el) {
                    el.focus();
                    console.log('mounted')
                    
                },
                beforeUpdate () {
                    console.log('beforeUpdate')
                },
                updated () {
                    console.log('updated')
                },
                beforeMount(){
                    console.log('beforeMount')
                },
                unmounted(){
                    console.log('unmounted')
                }
            }
        };
     const app = Vue.createApp({
        data() {
            return{
                isshow:true
            }
        },
        template:`
            <div v-show="isshow">
                <input type="text" v-focus>
            </div>
        `,
        directives: lkDirective,
        
     }).mount('#app');
    </script>
</body>

v-show改为v-if可以触发两个mounted函数
在这里插入图片描述

自定义指令传参

<body>
    <div id ="app">

    </div>
    <script>
     const app = Vue.createApp({
        data() {
            return{
                posData:{
                    top:200,
                    left:200
                }
            }
        },
        template:`
            <div class="box" v-fixed:pos="posData">哈哈哈</div>
        `,
        methods: {},

     });
     app.directive('fixed', (el,binding)=>{
         console.log(el,binding);
         el.style.position="fixed";
         el.style.top=binding.value.top+'px'
         el.style.left=binding.value.left+'px'
     });
     app.mount('#app');
    </script>
</body>

通过传递参数,调用value进行运算
在这里插入图片描述

Teleport 传送门

当有多层嵌套组件时,有时会出现嵌套子组件,执行后要展示在例如最外层的父组件上,这时就可以使用teleport

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <script src="js/vue.js"></script>
  </head>
  <style>
    .box {
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      width: 500px;
      height: 500px;
      background-color: red;
    }
    .mask {
      position: absolute;
      left: 0;
      top: 0;
      right: 0;
      bottom: 0;
      background-color: #000;
      opacity: 0.5;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    #root {
      position: absolute;
      width: 200px;
      height: 200px;
      background-color: #cccc;
    }
  </style>
  <body>
    <div id="app"></div>
    <div id="root"></div>

    <script>
      const app = Vue.createApp({
        data() {
          return {
            msg: "hello",
            isshow: false,
          };
        },
        methods: {
          btnClick() {
            this.isshow = !this.isshow;
          },
        },
        template: `
        <div class="box">
        <button @click="btnClick">蒙版</button>
        <!-- <div class="mask" v-show="isshow">{{msg}}</div> -->
        <!-- <teleport to="body">
            <div class="mask" v-show="isshow">{{msg}}</div>
        </teleport>-->

        <teleport to="#root">
            <div class="mask" v-show="isshow">{{msg}}</div>
        </teleport>
    </div>
        `,
      }).mount("#app");
    </script>
  </body>
</html>


点击蒙版后,按照to属性的值,渲染到#root
在这里插入图片描述

optionsAPI 组合式api

(1)setup

setup不能调用生命周期或者选项内的东西,但反过来,生命周期或者选项可以调用setup中的东西,
setup用来取代beforecreated和created两个钩子函数,可以定义data和一些methods的方法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <script src="js/vue.js"></script>
  </head>

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <script>
      const app = Vue.createApp({
        setup(props, context) {
          // 不能调用this
          //this.deal();//会报错
          return {
            msg: "hello",
            log: () => {
              alert("kkk");
            },
          };
        },
        methods: {
          deal(){
            console.log(this.$options.setup())
          },
        },
        template: `
            <div>
                <h1>{{msg}}</h1>
                <button @click="log">dianw</button>
                可以调用setup
                <button @click="deal">处理</button>
            </div>
        `,

      }).mount("#app");
    </script>
  </body>
</html>

在这里插入图片描述

(2)ref

ref:让基础类型的数据具备响应式
setup中不会调用生命周期里的选项内容,可以通过ref来实现响应
vue渲染的数据,可以通过控制台替换直接响应式修改显示在页面,使用setup后,修改了但没有响应
在这里插入图片描述
使用ref,实现动态响应,这里原理是改变proxy的值,所以settimeout的时候要修改的是value

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <script>
        // ref:让基础类型的数据具备响应式
      const app = Vue.createApp({
        setup(props, context) {
            // 1、引入ref
            const {ref} = Vue;
            // 通过proxy,'hello'-->proxy{value:‘hello’} 原理是通过代理实现
            let msg =ref("hello")
            setTimeout(() => {
                msg.value="kkk"
            }, 2000);
          return {
            msg
          };
        },
        template: `
        <div>
                <h1>{{msg}}</h1>
                <button @click="log">dianw</button>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>
  </body>

在这里插入图片描述

(3)reactive

跟ref一样的功能,也是让setup中的数据实时响应

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <script>
        // reactive:让引用类型的数据具备响应式
      const app = Vue.createApp({
        setup(props, context) {
            // 1、引入reactive
            const {reactive} = Vue;
            let pobj =reactive({name:'张三',sex:'男'});
            let parr =reactive(['vue','react']);
            setTimeout(()=>{
              pobj.name="lily"
            },2000)

          return {
            pobj,
            parr
          };

        },
        template: `
        <div>
                <h1>{{pobj.name}}{{pobj.sex}}</h1>
                <h2>{{parr}}</h2>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>
  </body>

在这里插入图片描述

(4)readonly的使用

常见的嵌套组件,数据流动都为单向,父组件的数据传递给子组件再到孙组件,为了避免数据改变, 可以使用readonly禁止修改

  <body>
    <div id="app">
      <h1>{{msg}}</h1>
    </div>
    <script>
      const app = Vue.createApp({
        setup(props, context) {
            // 1、引入readonly
            const {readonly} = Vue;
            let pobj =readonly({name:'张三',sex:'男'});
            setTimeout(()=>{
              pobj.name="lily"
            },2000)

          return {
            pobj,
          };

        },
        template: `
        <div>
                <h1>{{pobj.name}}{{pobj.sex}}</h1>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>
  </body>

两秒后数据不会发生变化,因为只读
在这里插入图片描述

(5)toRefs

对数据进行结构,可以显示,2秒后数据没有改变,不能动态响应,需要使用toRefs让解构的数据响应

<script>
      const app = Vue.createApp({
        setup(props, context) {
          const { reactive } = Vue;
          let pobj = reactive({ name: "张三", sex: "男" });
          setTimeout(() => {
            pobj.name = "lily";
          }, 2000);
          // 解构
          const { name, sex } = pobj;

          return {
            name,
            sex,
          };
        },
        template: `
        <div>
                <h1>{{name}}{{sex}}</h1>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>

使用toRefs
原理也是通过获取到proxy的value进行修改

    <script>
      const app = Vue.createApp({
        setup(props, context) {
          const { reactive,toRefs } = Vue;
          let pobj = reactive({ name: "张三", sex: "男" });
          setTimeout(() => {
            pobj.name = "lily";
          }, 2000);
          // 解构
          // const { name, sex } = pobj;
          const { name, sex } = toRefs(pobj);
          // 底层处理
          // proxy({ name: "张三", sex: "男" })
          // name:proxy({value:'张三'})
          //sex:proxy({value:'男'})
          return {
            name,
            sex,
          };
        },
        template: `
        <div>
                <h1>{{name}}{{sex}}</h1>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>

加上toRefs后,两秒后结构的数据会变化

(6)toRef

例如有name、age、sex从父组件传递给子组件,但是父组件漏传了一个,子组件依然是使用的三个并改变了值,这时候会出现报错,例子如下

    <script>
      const app = Vue.createApp({
        setup(props, context) {
          const { reactive, toRefs } = Vue;
          let pobj = reactive({ name: "张三", sex: "男" });//只传了两个
          let { name, sex,age } = toRefs(pobj);//解构了三个
          setTimeout(() => {
            name.value = "lily";
            sex.value = "女";
            age.value=100;
          }, 2000);
          return {
            name,
            sex,
            
          };
        },
        template: `
        <div>
                <h1>姓名:{{name}}性别:{{sex}}年龄:{{age}}</h1>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>

因为父组件没有传age过去,age属性未定义
在这里插入图片描述
让name、sex必传,age不必传,如果子组件使用了就使用toRef创建一个age,并设置值为100

    <script>
      const app = Vue.createApp({
        setup(props, context) {
          const { reactive, toRefs,toRef } = Vue;
          let pobj = reactive({ name: "张三", sex: "男" });//只传了两个
          let { name, sex } = toRefs(pobj);//让这两个必传
          let  age = toRef(pobj,'age');/// 可传可不传,如果pobj没有就创建age
          setTimeout(() => {
            name.value = "lily";
            sex.value = "女";
            age.value=100;
          }, 2000);
          return {
            name,
            sex,
            age
            
          };
        },
        template: `
        <div>
                <h1>姓名:{{name}}性别:{{sex}}年龄:{{age}}</h1>
            </div>
        `,
        methods: {},
      }).mount("#app");
    </script>

在这里插入图片描述

(7)context

传递给 setup 函数的第二个参数是 context。context 是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值:
context有三个常用的,attrs,slots,emit

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}

执行 setup 时,组件实例尚未被创建。无法访问data,computed,methods,refs (模板 ref),只能访问props、attrs、slots、emit
需要返回函数或者是数据都需要return才能被父组件访问

(8)计算属性新用法

<body>
    <div id ="app">
    </div>
    <script>
     const app = Vue.createApp({
        setup(props,context){
            const {ref,computed} = Vue;//数据具备响应式
            let num1 =ref(10);
            // 计算属性
            let num2=computed(()=>{
                console.log('++++');
                return num1.value*10
            })

            // 定义一个函数,点击改变num1
            const add =()=>{
                console.log('----come----');
                num1.value +=10;
            }
            return{
                num1,
                num2,
                add //这里函数也要return才会生效
            }
        },
        template:`
            <h2>{{num1}}</h2>
            <h2>{{num2}}</h2>
            <p>---------------</p>
            <button @click="add">点我</button>
        `
     }).mount('#app');
    </script>
</body>

在setup中运用computed属性,在setup执行后返回给页面渲染

computed中,可以传入对象,有get和set,可以分别获取和改变数据
这里使用setTimeout改变num2的值,通过计算属性的set,会自动计算num1对应的值

        setup(props,context){
            const {ref,computed} = Vue;//数据具备响应式
            let num1 =ref(10);

            // 计算属性
            let num2=computed({
                get:()=>{
                    return num1.value*10
                },
                set:(res)=>{
                    console.log(res)
                    return num1.value=res/10;
                }
            });
            setTimeout(()=>{
                num2.value=2000;
            },2000)
            const add =()=>{
                num1.value +=10;
            }
            return{
                num1,
                num2,
                add 
            }
        },

在这里插入图片描述

(9)watch侦听器

在setup中监听input的值

  <body>
    <div id="app"></div>
    <script>
      const app = Vue.createApp({
        setup(props, context) {
          const { ref, watch } = Vue;
          let brand = ref("");
          let site = ref("");

          //   侦听一个
          // watch(brand,(currentValue,preValue)=>{
          //     console.log('现在的',currentValue)
          //     console.log('之前的',preValue)
          // })
          // 侦听多个
          watch(
            [brand, site],
            ([currentbrand, currentsite], [prebrand, presite]) => {
              console.log("现在的", currentbrand, currentsite);
              console.log("之前的", prebrand, presite);
            }
          );
          return {
            brand,
            site,
          };
        },

        template: `
            <div>
                品牌:<input v-model="brand">
                <p>输入的品牌是{{brand}}</p>
            </div>
            <p>---------</p>
            <div>
                网站:<input v-model="site">
                <p>输入的网站是{{site}}</p>
            </div>
        `,
      }).mount("#app");
    </script>
  </body>

在这里插入图片描述

侦听响应式的引用类型数据

  <body>
    <div id="app"></div>
    <script>
      const app = Vue.createApp({
        setup(props, context) {
          const { ref, watch,reactive,toRefs } = Vue;
          let eduObj =reactive({brand:'xxx学院',site:'www.com'})
          //   侦听一个
          //只能监听getter或者是函数、对象、数组,使用使用箭头函数
          watch(()=>eduObj.brand,(currentValue,preValue)=>{
              console.log('现在的',currentValue)
              console.log('之前的',preValue)
          })
          const {brand,site} =toRefs(eduObj)
          return {
            brand,
            site,
          };
        },

        template: `
            <div>
                品牌:<input v-model="brand">
                <p>输入的品牌是{{brand}}</p>
            </div>
            <p>---------</p>
            <div>
                网站:<input v-model="site">
                <p>输入的网站是{{site}}</p>
            </div>
        `,
      }).mount("#app");
    </script>
  </body>

在这里插入图片描述

(10)watchEffect

跟watch的区别
在这里插入图片描述

  <body>
    <div id="app"></div>
    <script>
      const app = Vue.createApp({
        setup(props, context,watchEffect) {
          const { ref, watch } = Vue;
          let brand = ref("");
          let site = ref("");

          // watch
          /* (1)有惰性
             (2)更加具体
             (3)可以配置属性之间的值
             (4)可配置的非惰性,深度监听
          */
          watch(brand,(currentValue,preValue)=>{
              console.log('现在的',currentValue)
              console.log('之前的',preValue)
          },{
            //非惰性(true为非惰性)
            immediate:false,
            deep:true
          })
          // watchEffect  
          /* (1)非惰性
             (2)更加抽象(监听的实例,直接引用监听的值就可以)
             (3)不可以配置属性之间的值
             (4)可配置的非惰性,深度监听
          */
          watchEffect( () => {
            console.log('开始侦听了');
            console.log(brand.value);
            console.log(site.value);
          })

          return {
            brand,
            site,
          };
        },

        template: `
            <div>
                品牌:<input v-model="brand">
                <p>输入的品牌是{{brand}}</p>
            </div>
            <p>---------</p>
            <div>
                网站:<input v-model="site">
                <p>输入的网站是{{site}}</p>
            </div>
        `,
      }).mount("#app");
    </script>
  </body>

(11)provide和inject

实际开发中,由于数据单向,孙组件要获取子组件的数据时,需要一层层传递,使用provide(发射),inject(订阅)可有效改善这个问题
组件进行发射,孙组件订阅,接受到发生的变量,不需要在经过父组件再一次传递

  <body>
    <div id="app"></div>
    <script>
      // 孙组件
      const lkSon = {
        setup(){
          const {inject} =Vue;
          const bName = inject('brand','默认值')
          const bCollege = inject('college')


          return{
            bName,
            bCollege
          }
        },
        template: `
          <div style="width:200px;height:200px;background-color:green">
            {{bName}}---{{bCollege}}
          </div>
        `,
      };
      // 子组件
      const lkfather = {
        components: {
          "lk-son": lkSon,
        },
        template: `
          <div style="width:400px;height:400px;background-color:red">
            父组件
            <lk-son></lk-son>  
          </div>
        `,
      };

      const app = Vue.createApp({
        setup() {
          const { ref, reactive, provide } = Vue;
          let brand = ref("hh");
          let college = reactive({ city: "上海", site: "baidu.com" });

          // 发射 
          provide('brand',brand)//注释掉就显示默认值
          provide('college',college)

        },
        components: {
          'lk-father':lkfather
        },
        template:`
          <lk-father></lk-father>
        `
      }).mount("#app");
    </script>
  </body>

在这里插入图片描述
使用过程中要主要准许数据单向,数据在哪里就在哪里修改,可以通过传递的值进行readonly,或者是在最外层发射一个改变值的函数由孙组件接受

(12) 生命周期钩子新写法

setup中用法其实与平时的钩子函数用法差不多,只差别在名称
这里补充两个setup中使用的函数

页面刷新调用onRenderTracked
改变数据调用onRenderTriggered

<body>
  <div id ="app">
    

  </div>
  <script>
   const app = Vue.createApp({
    setup() {
      const {ref,onRenderTracked,onRenderTriggered} = Vue;
      let msg =ref('kkk')
      const handleClick=()=>{
        msg.value='hhh'
      }
      //每次渲染后重新收集响应式依赖
      onRenderTracked(()=>{
        console.log('onRenderTracked')
      })
      // 每次触发页面重新渲染,自动执行
      onRenderTriggered(()=>{
        console.log('onRenderTriggered')
      })
      return{
        msg,
        handleClick
      }
    },
    methods: {},
    template:`
       <h1 @click="handleClick()">{{msg}}</h1>
    `

   }).mount('#app');
  </script>
</body>

在这里插入图片描述

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

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:17:01-

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