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知识库 -> js经验总结 -> 正文阅读

[JavaScript知识库]js经验总结

window.navigator 对象包含有关访问者浏览器的信息。

window.navigator 对象在编写时可不使用 window 这个前缀。


<script>
txt = "<p>浏览器代号: " + navigator.appCodeName + "</p>";
txt+= "<p>浏览器名称: " + navigator.appName + "</p>";
txt+= "<p>浏览器版本: " + navigator.appVersion + "</p>";
txt+= "<p>启用Cookies: " + navigator.cookieEnabled + "</p>";
txt+= "<p>硬件平台: " + navigator.platform + "</p>";
txt+= "<p>用户代理: " + navigator.userAgent + "</p>";
txt+= "<p>用户代理语言: " + navigator.language + "</p>";
document.getElementById("example").innerHTML=txt;
</script>

▲js代码执行顺序

//window.onload() 方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。
//window.onload 与 jQuery ready() 区别
1.执行时间
window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。
$(document).ready()DOM结构绘制完毕后就执行,不必等到加载完毕。 
2.编写个数不同 
 window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个
$(document).ready()可以同时编写多个,并且都可以得到执行
3.简化写法 
window.onload没有简化写法
$(document).ready(function(){})可以简写成$(function(){});

1.先对代码进行预处理(编译),然后再执行。预处理会跳过执行语句,只处理声明语句,同样也是按从上到下按顺序进行的。包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理。 即使声明是在调用的下方进行的,但浏览器仍然先声明再调用(执行),这个现象叫做“提升”。所以,即便一个函数的声明在下方,在前面仍然可以正常执行这个函数。
例如 var a = 1,在预处理阶段会把这句话拆成两句:
var a;
a = 1;
2.完成预处理之后,JavaScript代码会从上到下按顺序执行逻辑操作和函数的调用。

var a=1;
function func(){
    console.log(a); //undefined
    var a=2;
    console.log(a);//2
}
func();
js作用域链变量访问规则
(1)、当前作用域内存在要访问的变量时,则使用当前作用域中的变量。
(2)、当前作用域中不存在要访问的变量时,则会到上一层作用域中寻找,直到全局作用域。
js主要用来操控和重新调整DOM,通过修改DOM结构,从而来达到修改页面效果的目的

▲JSON数据是一种按照js对象语法的数据格式

//JSON数据是一种按照js对象语法的数据格式,通常用于网站上表示和传输数据;
//你可以把js对象写入JSON数据--字符串,数字,数组,布尔等其他字面量

//JSON是一种纯数据格式,它只包含属性,没有方法
//JSON要求在字符串和属性名称周围使用双引号。 单引号无效。
//JSON,前者用于解读json中的数据,后者用于通过网络传输json数据

//JSON.parse()从JSON字符串转换为js对象
//JSON.stringify()从js对象转换成JSON字符串

▲对象

对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称为对象里面的属性和方法)
点表示法person.interests[1]
括号表示法person['name']['first']
括号表示法一个有用的地方是它不仅可以动态的去设置对象成员的值,还可以动态的去设置成员的名字。

//构建函数
function Person(name) {
  this.name = name;
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
  };
}

//创建实例对象 关键字 new 跟着一个含参函数,用于告知浏览器我们想要创建一个对象,非常类似函数调用,并把结果保存到变量中。
var person1 = new Person('Bob');
var person2 = new Person('Sarah');

// 输出实例对象
{
  name : 'Bob',
  greeting : function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
}
{
  name : 'Sarah',
  greeting : function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
}
//create()方法
var person2 = Object.create(person1);//person2是基于person1创建的
//Object()构造函数
var person1 = new Object({
  name : 'Chris',
  age : 38,
  greeting : function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
});
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象用于一个原型对象,对象以其原型为模板,从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层以此类推,这种关系被称为原型链,准确的说,这些属性和方法定义在Object的构造器函数(construcor function)之上的prototype属性上,而非对象实例本身
js对象实例和他的构造器之间建立一个链接(它就是__proto__属性,他是从构造函数的prototype属性派生的)
Object.getPrototypeOf(obj)和obj.__proto__一样

每个函数都有一个特殊的属性叫做原型(prototype)

js中到处都是通过原型链继承的例子,比如,你可以尝试从Sting,Date,Number和Array全局对象的原型中寻找方法和属性,它们都在原型上定义了一些方法,因此你创建一个字符串时
var myString = 'This is my string.';
myString 立即具有了一些有用的方法,如 split()、indexOf()、replace() 等。

constructor属性
每个实例对象都从原型中继承一个constructor属性,该属性指向了用于构造此实例对象的构造函数
function  m                                                    (first, last, age) {
      this.first = first
      this.last = last
      this.age = age
    }
var person1 = new Person('Bob', 'Smith', 32)
var person2 = Object.create(person1)
console.log(person2.constructor == person1.constructor);//true


function Person(first, last, age, gender, interests) {
  this.name = {
    first,
    last
  };
  this.age = age;
  this.gender = gender;
  this.interests = interests;
};
Person.prototype.greeting = function() {
  alert('Hi! I\'m ' + this.name.first + '.');
};
function Teacher(first, last, age, gender, interests, subject) {
  Person.call(this, first, last, age, gender, interests);

  this.subject = subject;
}
.call()新指定您调用的函数里所有“this”指向的对象

对象方法
Object.keys()此方法可以获取对象所有可枚举的属性
var obj = {
    name: "李白",
    age: 24
}

▲XML

// ▇ get请求
window.onload=function(){
    var b=document.getElementsByTagName('input')[0]
    b.onclick=function(){
        var url='server.php' //设置请求的地址
        var xhr=createXHR() //实例化XMLHttpRequest对象
        xhr.open('post',url,true) //建立间接,要求异步响应
        xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')//设置表单方式提交
        xhr.onreadystatechange=function(){//绑定响应状态事件监听函数
            if(xhr.readyState==4){//监听readyState状态
                if(xhr.status==200||xhr.status==0){//监听http状态码
                    console.log(xhr.responseText//接受数据
                }
            }
        }
        xhr.send('callbakc=functionName')//发送请求
    }
}

// ▇ post请求
var xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.onreadystatechange = function (){
    if(xhr.readyState == 4 && xhr.status == 200){
        console.log(xhr.response);
    }
}
xhr.open("POST", "http://bufantec.com/api/test/user/doLogin");
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.send("username=libai&password=123456");

//XML被设计用来传输和存储数据,焦点是数据的内容
//HTML被设计用来显示数据,焦点是数据的外观

//XMLHttpRequest(XHR)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定url,获取数据
    
请求一般分成 4 个步骤。
// ▇ 1.构造函数XMLHttpRequest(),该构造函数用于初始化一个 XMLHttpRequest 实例对象。在调用下列任何其他方法之前,必须先调用该构造函数,或通过其他方式,得到一个实例对象。
var xhr=new XMLHttpRequest()

// ▇ 2. 与服务器建立连接,使用XMLHttpRequest对象的open()方法可以建立一个HTTP请求
xhr.open(method,url,async,user,password)

//发送get请求简单、方便,适用于简单字符串,不适用大容量或者加密数据
//发送post请求允许发送任意类型,长度的数据,多用于表单的提交

// ▇ 3.发送请求
xhr.send(null);

// ▇ 4.接收返回值  onreadystatechange 事件。当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。readyState:请求状态,返回的是整数(0-4)。
//XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest  代理当前所处的状态
0 	UNSENT 	         	代理被创建,但尚未调用 open() 方法。
1 	OPENED 	            open() 方法已经被调用。
2 	HEADERS_RECEIVED 	send() 方法已经被调用,并且头部和状态已经可获得。
3 	LOADING 			解析中; responseText 属性已经包含部分数据。
4 	DONE 				解析完成。    
//status:请求结果,返回 200 或者 404。200 => 成功。404 => 失败。 
var xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.status); //UNSENT(未发送) 0

xhr.open('GET', '/server', true);
console.log('OPENED', xhr.status);// OPENED(已打开) 0

//progress event  progress事件会在请求接收到数据的时候被周期性触发。
xhr.onprogress = function () {
  console.log('LOADING', xhr.status);//LOADING(载入中) 200
};

//XMLHttpRequest: load event当一个XMLHttpRequest请求完成的时候会触发load 事件。
xhr.onload = function () {
  console.log('DONE', xhr.status);//DONE(完成) 200
};
xhr.send(null); 
//获取XML数据,通过responseText,responseBody,responseStream或responseXML属性获取响应信息
//responseBody 将响应信息正文以Unsigned Byte数组形式返回
//responseSteam 以ADO Stream对象的形式返回响应信息
//responseText 将响应信息作为字符串返回
//responseXML 将响应信息格式华为XML文档格式返回    
    
//XMLHttpRequest.timeout代表着一个请求在被自动终止前所消耗的毫秒数,默认值为 0,意味着没有超时。
//XMLHttpRequest: error 事件 当请求遇到错误时,将触发error 事件。
//中止请求,abort()方法可以中止正在进行的请求 xhr.about()

//获取和设置头部信息,http请求和响应都包含一组头部信息 
//getAllResponseHeaders()获取响应的http头部信息
//getResponseHeader('Header-name')获取指定的http头部信息
xhr.getResponseHeader("Content-Type")

//Header-name表示头部信息的名称,value表示消息的具体值 
//xhr.setResponseHeader('Header-name','value')
xhr.setResponseHeader('Content-Type','application/x-www-form-urlencoded')

▲js高阶函数

高阶函数:对其他函数进行操作的函数,函数作为参数,函数作为返回值
this指向
定时器this 指向window
// ▇ bind()绑定 改变this指向,不会立即调用的
// ▇ call()方法使用一个指定的this值和单独给出的一个或者多个参数来调用函数
//语法: function.call(thisArg, arg1, arg2, ...)
function Product(name,price){
	this.name=name;
	thsi.price=price;
}
function Food(name,price){
    Product.call(this,name,price)
    this.category='food'
}

// ▇ apply()
call()方法接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组
闭包closure有权访问另一个函数作用域中的变量的函数,延伸了变量的作用范围

▲数据类型

// ▇ 基本数据类型 String Number Boolean Undefined Null
js中的变量都是保存到栈内存的,基本数据类型的值在栈内存中存储,值与值之间是独立存在的,修改一个变量不会影响其他的变量

Undefined是没有定义的(在使用var声明变量但未对其初始化,这个变量即是undefined)null是定义了但是是空,null表示一个空对象指针 typeof操作符检测null值返回Object
string类型 字符创是不可变得,一旦创建,值就不能改变
object类型
constructor保存着用于创建当前的函数
hasOwnProperty(propertyName)检查当前属性在当前对象实例中是否存在,propertyName必须是字符串形式指定
例如:o.hasOwnProperty(“name”)
Symbol 类型
Symbol 类型的对象永远不相等,因此,可以用解决属性名冲突的问题(适用于多少编码
// ▇ 引用数据类型 Object 包含Function Array Date
判断数据类型
typeof
toString
toLocaleString
检测数据类型方法:
instanceof操作符
对象的constructor属性
Array.isArray检验是否为数组

// ▇ 1.如果两个变量保存的是同一个对象地址,当一个变量修改属性时,另一个也会受影响,所以需要想要2个相互不影响,就得克隆!
var obj=new Object()
obj.name='swk'
var obj2=obj
obj.name='zbj' //obj=>{name:'zbj'}
obj2.name='zbj'//obj2=>{name:'zbj'}
// ▇ 2.如果两个变量保存的是同一个对象地址,当一个变量修改值时,另一个不会受影响
obj2=null
console.log(obj2==obj);//false
// ▇ 3.比较两个基本数据类型,就是比较他们的值
var a = 10
var b = 10
console.log(a == b); //true
// ▇ 4.比较两个引用数据类型,就是比较他们的内存地址,如果两个对象一模一样,但是地址不同,也会返回fasle
var obj3 = new Object()
var obj4 = new Object()
obj3.name = '1'
obj4.name = '1'
console.log(obj3 == obj4); //false

▲判断数据类型的方法

// ▇ 1.typeof用来检测一个变量的数据类型(简单数据类型)
console.log(typeof 1); //number
console.log(typeof 'abc');//string
console.log(typeof true);//boolean
console.log(typeof undefined);//undefined
console.log(typeof null);//object
console.log(typeof function fn() { });//function
console.log(typeof [1, true]);//object
console.log(typeof {w actions: 1 });//object

// ▇ 2.instanceof(判断是不是实例对象) 一般用来检测引用数据类型, A instanceof B,如果 A是B的实例对象,返回true,否则false
console.log(10 instanceof Number);//false
console.log('10' instanceof String);//false
console.log(false instanceof Boolean);//false
console.log(null instanceof Object);//false
console.log([1, 2, 3] instanceof Array);//true
console.log(function fn() { } instanceof Function);//true
console.log({ a: 1, c: 2 } instanceof Object);//true
console.log(new Number() instanceof Number);//true
console.log(new String() instanceof String);//true

 // ▇ 3.constructor(判断是哪个构造函数的)是prototype对象上的属性,指向构造函数
let num = 12
console.log(num.constructor == Number);//true
console.log('abc'.constructor == String);//true

function Fn() {}
let dog = new Fn()
console.log(dog.constructor == Fn);   //true

// ▇ 4.Object.prototype.toString.call()最好的方法
let abc = [1, 2]
console.log(Object.prototype.toString.call(abc));//[object Array]
let abc = 1
console.log(Object.prototype.toString.call(abc));//[object Number]
let abc = 'abc'
console.log(Object.prototype.toString.call(abc));//[object String]
let abc = function(){}
console.log(Object.prototype.toString.call(abc));//[object Function]
let abc = {a:1}
console.log(Object.prototype.toString.call(abc));//[object Object]

// ▇ 当我们使用arr.toString()时,不能进行复杂数据类型的判断,因为它调用的是Array.prototype.toString,虽然Array也继承自Object,但js在Array.prototype上重写了toString,而我们通过toString.call(arr)实际上是通过原型链调用了Object.prototype.toString。
var arr = [1, 2, 3];
console.log(toString.call(arr));//[object Array]
console.log(arr.toString());//'1,2,3'

▲克隆

// ▇ 传值:表示传递的是变量所赋的值(就是当一个变量的值 赋给 另一个新变量的时候,新变量修改了值,不会影响原来变量的值)
// ▇ 传址:表示传递的是变量所在的内存地址【内存地址:也就是所谓的指针】(就是当一个变量的值 赋给 另一个新变量的时候,新变量修改了值,那么原来变量的值也会被修改,因为它们是同一个内存地址,所以一改全改)
【简单来说:就是类似给变量起了一个新的名字,但实际上还是原来的】。
注:一般情况下:简单类型赋值是 传值 !!, 复杂类型赋值是 传址!!。

// ▇ 浅拷贝:
当对某个数据(数组或对象)进行拷贝后,修改新数据(拷贝后的数据)里面第1层的数据是不会影响老数据(被拷贝的数据)的,但是如果还要第2层 或 更深层次的数据(复杂数据类型),它仍然是有关联的,如果修改了新数据,那么老数据也会被修改。
浅拷贝一般意义不大,了解就行,这里就不贴代码了。根据上面浅拷贝的问题,此时:深拷贝就排上用场了。

// ▇ 深拷贝:
* 就是在拷贝数据(数组或对象)时,不管数据里面有多少层,是简单 还是 复杂数据类型,只要进行深拷贝后,和老数据(之前被拷贝的数据)就毫无关联,相互独立,互不影响!在修改新数据,对老数据毫无影响。
* 作用:打断两个对象或数组之间的引用关系!
* 原理:在对数组或对象进行拷贝,使用递归循环复制,而每次递归都是开辟一个新的内存地址(指针),所以一般只要不是同一个内存地址,就不会修改其值
简单来讲:当拷贝一个数据后,和原来的数据就没有任何联系了,因为它们不是同一个指针。
           
// ▇ 使用场景:
无论是浅拷贝还是深拷贝,一般都用于操作Object 或 Array之类的复合类型。
比如想对某个数组 或 对象的值进行修改,但是又要保留原来数组 或 对象的值不被修改,此时就可以用深拷贝来创建一个新的数组 或 对象,从而达到操作(修改)新的数组 或 对象时,保留原来数组 或 对象。
如数组方法:concat(),filter(),slice(),map()等。它们在修改数组时,不会修改原来的数组,而是返回一个新的数组。
//浅拷贝 对一层的复杂数据类型中都是简单数据类型 Object.assign()  {...obj} assign(分配的意思)
// ▇ 1.Object.assign()将所有可枚举属性的值从一个或者多个源对象分配到目标对象
//语法:Object.assign(target,...sources)
//如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖,后面的原对象将类似的覆盖前面源对象的属性
// ▇ 感觉是合并2个对象,如果有相同的键,源的键覆盖目标的键
var obj = { a: 1, b: 2 }
var obj2=Object.assign({},obj)
console.log(obj2);//{ a: 1, b: 2 }
console.log(obj2==obj);//false

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(returnedTarget)//{ a: 1, b: 2,c:5} //b被源对象覆盖,加上目标元素萨
console.log(target == returnedTarget);//true
console.log(source);//{ b: 4, c: 5 } 源没变

// ▇ 2.解构赋值
var oo = { a: 1, b: 2 }
var oo2 = { ...oo }
oo2.c = 3
console.log(oo2);//{a: 1, b: 2, c: 3}
console.log(oo);//{a: 1, b: 2}
console.log(oo==oo2);//false

//深拷贝,针对有多层的引用数据类型
// ▇ 1.JSON.parse(JSON.stringigy( ))
var cc = [{
      name: '臧三',
      childs: ['小明', '小芳']
}]
var cc2=JSON.parse(JSON.stringigy(cc))
console.log(cc==cc2);//false

// ▇2.利用递归来实现拷贝

▲异步

// ▇ 异步编程,就是为了让程序在一个时间内做更多的事情

// ▇ 阻塞,当浏览器里面的一个web应用进行密集运算还没有把控制权返回给浏览器的时候,整个浏览器就像冻僵了一样,这就是阻塞,这时候浏览器无法继续处理用户的输入并执行其他任务,直到web应用交回处理器的控制权

//js是单线程的, main thread
//每个任务顺序执行,只用前面的任务结束了,后面的才开始
// Main thread: Task A-- > Task C
// Worker thread: Expensive task B

// ▇ js通过web workers可以把一些任务交给一个名为worker的单独的线程,这样就可以同时运行多个js代码块,一般来说,用一个worker来运行一个耗时任务,主线程就可以处理用户的交互,避免了阻塞

//worker局限:主要的一个问题是他们不能访问DOM,不能让一个worker直接更新ui,他基本只能做算数的苦活

// ▇ promise
状态:pending(初始化)=>fulfilled(操作成功)/rejected(操作失败)
var promise=new Promise(传一个函数)

// ▇ async,await

function f3() {
      return new Promise((res, rej) => {
        res('abc')
      })
    }
    async function f5() {
       console.log(1);//还是会执行先,只是await下面的阻塞了
      var c = await f3();
      //await开始阻塞,上面的await执行玩后,执行该函数下面代码,执行f5函数
      console.log(c);
    }
    f5()
    
    function f4() {
      return Promise.reject('cuowu')
    }
    async function f6() {
      try {
        var d = await f4()
        console.log(d);
      } catch (e) {  //try{}catch{}抛出错误
        console.log(e);
      }
    }
    f6()
	// try {
    //    tryCode - 尝试执行代码块
    // }
    // catch (err) {
    //   catchCode - 捕获错误的代码块
    // }
    // finally {
    //   finallyCode - 无论 try / catch 结果如何都会执行的代码块
    // }

// ▇ Promise.all可以将多个promise实例包装成一个新的promise实例,同时成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值
let p1 = new Promise((res, rej) => {
      res('成功了')
    })
    let p2 = new Promise((res, rej) => {
      rej('失败了')
    })
    let p3 = new Promise((res, rej) => {
      rej('shibai')
    })
Promise.all([p1, p2, p3]).then((result) => {
      console.log(result);
    }).catch((err) => {
      console.log(err);//返回最先被reject失败状态的值
    })
// ▇ Promise.race就是才跑的意思,Promise.race([p1,p2,p3])里面那个结果获得得快,就返回那个结果,不管结果本身是成功还是失败
Promise.race([p1, p2, p3]).then((result) => {
      console.log(result);//'成功了'
    }).catch((err) => {
      console.log(err);
    })






































获取时间

//获取当前时间
var date=new Date()
//获取当前小时
date.getHours()

throw语句 try{}catch{}语句

//throw 语句抛出一个错误。 
//异常 (err) 通过 catch 语句捕获并自定义输出错误信息

//try{}catch{}语句  当错误发生时, JavaScript 会停止执行(默认只会抛出一个错误),并生成一个错误信息。使用 throw 语句 来创建自定义消息(抛出异常)。如果你将 throw 和 try 、 catch一起使用,就可以控制程序输出的错误信息
<p>请输入 510 之间的一个数:</p>
<input id="demo" type="text"><button type="button" onclick="myFunction()">检测输入</button>
<p id="message"></p>
function myFunction() {
    var message, x;
    message = document.getElementById("message");
    message.innerHTML = "";
    x = document.getElementById("demo").value;
	try { 
    	if(x == "")  throw "为空";
        if(isNaN(x)) throw "不是一个数字";
        if(x > 10)   throw "太大了";
        if(x < 5)    throw "太小了";
    }
    catch(err){
         message.innerHTML = "输入的值 " + err;
    }
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:10:38  更:2021-11-28 11:12:22 
 
开发: 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/21 5:43:57-

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