当前位置: 首页 > news >正文

用网站做平台佛山网站代运营

用网站做平台,佛山网站代运营,微信机器人,网站模板织梦学习资源来自#xff1a; 类与接口 TypeScript 入门教程 (xcatliu.com) 一.TypeScript的安装和运行 1.安装TypeScript 通过npm#xff08;Node.js包管理器#xff09;安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了Ty…学习资源来自 类与接口 · TypeScript 入门教程 (xcatliu.com)  一.TypeScript的安装和运行 1.安装TypeScript 通过npmNode.js包管理器安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了TypeScript。 如果你的Visual Studio还没有安装TypeScript) 2.npm安装TypeScript 安装教程 TypeScript环境搭建并且部署到VSCode亲测有效_咖啡壶子的博客-CSDN博客安装过程中问题 TypeScript- 解决tsc 不是内部或外部命令也不是可运行的程序或批处理文件问题 - sanyekui - 博客园 (cnblogs.com) 3.将环境安装好之后就可以尝试构建第一个typeScript程序 新建Demo.ts文件 function greeter(person: string) {return Hello, person }let user Jane Userdocument.body.innerHTML greeter(user) 在终端输入  tsc greeter.ts 就会输出一个 包含和输入内容一样的JavaScript代码 新建文件demo.html  !DOCTYPE html htmlheadtitleTypeScript Greeter/title/headbodyscript srcdemo.js/script/body /html 执行结果会展示在界面上 二.基础类型 1.布尔值 true 或者 false在JS或者TS中叫boolean语法 let boolean false注意使用Boolean 创造的对象不是布尔值比如let createdByNewBoolean: Boolean new Boolean(1);直接调用Boolean 也可以返回一个 boolean类型 let createdByBoolean: boolean Boolean(1);在TypeScript中boolean 是基本类型Boolean 是构造函数  2.数字类型 TypeScript里面所有数字都是浮点数这些浮点数的类型是Number除了支持十进制和十六进制字面量TypeScript还支持ECMAScript 2015 中引入的二进制和八进制二进制表示法let binaryLiteral: number 0b1010;八进制表示法let octalLiteral: number 0o744;二进制和八进制会被编译为十进制数字       3.字符串 使用string表示用单引号或者双引号包起来可以使用模板字符串 ${XXX} 4.数组 let list:number[] [1, 2, 3]let list:Arraynumber [1, 2, 3] 5.元组Tuple 表示一个已知元素数量和类型的数组各个元素的类型不一定相同let x:[string, number]x [hello, 10] 6.枚举 enum类型是对JavaScript标准数据类型的一个补充 enum Color {Red,Green,Blue, } let c: Color Color.Green 默认情况下从0开始为元素编号可以手动指定成员的数值 enum Color {Red 1,Green,Blue, } let c: Color Color.Green console.log(c) // 2 全部采用手动赋值 enum Color {Red 1,Green 2,Blue 4, } let c: Color Color.Blue console.log(c) // 4 找出映射的名字 enum Color {Red 1,Green,Blue, } let colorName: string Color[2] console.log(colorName) // Green 7.任意值 any 需要在编译阶段还不清楚的变量指定一个类型不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查就可以使用any类型来标记这些变量注意Object类型的变量只是允许你给他赋任意值却不能够在它上面调用任意的方法当你只知道一部分数据的类型时any类型也是有用的 比如 let list: any[] [1, true, free] 声明一个变量为任意值之后对它的任何操作返回的内容的类型都是任意值 在声明的之后未指定其类型就会被识别为任意值类型 8.空值 void 表示没有任何类型当一个函数没有返回值时就会见到void声明一个void变量没什么用因为你只能赋予它undefined 和 null 9.null和undefined 与void的区别是undefined和null是所有类型的子类型也就是说undefined类型的变量可以赋值给所有类型void的类型不可以 10.never never类型标识永不存在的值的类型never类型是那些总是会抛出异常或者根本不会有返回值的函数表达式或箭头函数表达式的返回值类型变量也可能是never类型当它们被永不为真的类型保护所约束的时候never类型是任何类型的子类型可以赋值给任何类型没有类型是never的子类型就是只能将never类型赋值给never类型any也不可以赋值给never // 返回never的函数必须存在无法达到的终点 function error(message: string): never {throw new Error(message); }// 推断的返回值类型为never function fail() {return error(Something failed); }// 返回never的函数必须存在无法达到的终点 function infiniteLoop(): never {while (true) {} } 12.联合类型 表示取值可以为多种类型中的一种 let myFavoriteNumber: string | number; myFavoriteNumber seven; myFavoriteNumber 7; 联合类型使用 | 分隔每个类型 let myFavoriteNumber: string | number;  的含义是允许 myFavoriteNumber 是string类型或者number类型但是不能是其他类型 当TypeScript不确定一个联合类型的变量到底是哪个类型的时候只能访问此联合类型中所有属性里共有的属性和方法 11.类型断言 类型断言就相当其他语言中的类型转换显示转换但是不进行特殊的数据检查和解构没有运行时的影响只是在编译阶段起作用 两种形式 尖括号语法 let someValue: any this is a string let strLength: number (stringsomeValue).length as 语法 let someValue: any this is a string let strLength: number (someValue as string).length 12.类型推论 下面代码虽然没有指定类型但是在编译的时候会报错TypeScript 会在没有明确的指定类型的时候推测出一个类型这就是类型推论 let myFavoriteNumber seven; myFavoriteNumber 7; 如果在定义的时候没有赋值不管之后有没有赋值都会被推断为any类型而不被类型检查 三.变量声明 ① var和let声明与JavaScript中一致 var 声明可以在包含它的函数模块命名空间或者全局作用域内部任何位置被访问let 支持块作用域在声明之前读或者写var可以多次声明只会取最后一个let如果多次声明就会报错使用let替换var ② const 声明 赋值后不能被改变和let的作用域规则相同但是不能对它们重新赋值但是可以修改对象内部的值 ③ let 和 const 的选择 使用最小特权原则所有变量除了你计划去修改的都应该使用const如果需要修改就使用let ④ 解构 解构数组 最简单的解构数组 let input [1, 2] let [first, second] input console.log(first) console.log(second) 利用解构交换两个变量的值 let input [1, 2] let [first, second] input ;[first, second] [second, first]console.log(first) console.log(second) 解构用在函数参数上 let input [1, 2] function f([first, second]: number[]) {console.log(first)console.log(second) } f(input) 使用剩余参数解构 let [first, ...rest] [1, 2, 3, 4] console.log(first) console.log(rest) 只解构其中一个数据 let [first] [1, 2, 3, 4] console.log(first) 将不关心的元素省略 let [, second, , fourth] [1, 2, 3, 4] console.log(second) 解构对象 let o {a: foo,b: 12,c: bar, } let { a, b } o console.log(a) console.log(b) 属性重命名 let o {a: foo,b: 12,c: bar, } let { a: name1, b: name2 } o console.log(name1) console.log(name2) 默认值 参数默认值如果函数没有传参数就使用初始化列表中的值 解构表达还是要尽量保持小而简单 ⑤ 展开运算符 允许将一个数组展开为另一个数组 let first [1, 2] let second [3, 4] let bothPlus [0, ...first, ...second, 5] console.log(bothPlus) // [0, 1, 2, 3, 4, 5] 将一个对象展开为另一个对象 let defaults { food: spicy, price: $$, ambiance: noisy } let bothPlus { ...defaults, food: rich } console.log(bothPlus) // 四.接口 在TypeScript中使用接口Interfaces来定义对象的类型在TypeScript中除了可用于对类的一部分行为进行抽象以外也常用于对【对象的形状】进行描述TypeScript核心原则对值所具有的结构进行类型检查接口的作用是为这些类型命名和为你的代码或第三方代码定义契约下面的例子定义了一个接口接着定义了一个变量tom类型是Person,  约束tom的形状必须和接口 Person 一致定义的变量比接口少了一些属性或者多了一些属性都不被允许必须和接口的形状保持一致 可选属性 ① 有时候希望不要完全匹配一个形状可以用可选属性 ② 可选属性的含义就是该属性可以不存在 ③ 但是仍然不允许添加未定义的属性 任意属性   ① 有时候我们希望一个接口允许有任意的属性上面是使用 [propName: string]  定义了任意属性取string 类型的值 ② 一旦定义了任意属性那么确定属性和可选属性的类型都必须是它的类型的子集 ③ 所以下面的案例中如果任意属性中的值允许是string, 但是可选属性age的值是number不是string的子属性所以报错了 ④ 一个接口中只能定义一个任意属性如果接口中有多个类型的属性则可以在任意属性中使用联合类型 只读属性 ① 有时候我们希望对象中的一些字段只能在创建的时候被赋值就使用 readonly 定义只读属性 ② 只读的约束存在于第一次给对象赋值的时候而不是第一次给只读属性赋值的时候 ③ 只读属性不能进行赋值无法修改 interface Point {readonly x: numberreadonly y: number }let p1: Point { x: 10, y: 10 } p1.x 10 // 会报错属性是只读属性 ③ 只读属性在第一次初始化对象的时候必须进行初始化 数组只读属性 let a: number[] [1, 2, 3, 4] // 限制数组是只读类型 let ro: ReadonlyArraynumber aro[0] 1 // 报错 readonly 和 const ① 作为变量使用的话就用const ② 作为属性就使用  readonly 额外的属性检查 解决方法 ①  解决方法 ② 添加一个字符串索引签名 解决方法③ 将这个对象赋值给另一个变量不会经过额外属性检查 五.数组类型 ①【类型 方括号】表示法 let fibonacci: number[] [1, 1, 2, 3, 5]; ② 数组的项中不允许出现其他类型 ③ 数组中的一些方法的参数也会根据数组在定义时约定的类型进行限制 ④ 可以使用数组泛型   ArrayelemType  来表示数组 let fibonacci: Arraynumber [1, 1, 2, 3, 5]; ⑤ 用接口表示数组 interface NumberArr {[index: number]: number } let fib: NumberArr [1, 2, 3, 4] 用接口表示数组比较少见但是经常用它表示类数组伪数组 使用普通数组不能定义为数组所以使用接口的形式 常用的类数组都有自己的接口定义比如 IArguments, NodeList, HTMLCollection function sum() {let args: IArguments arguments } IArgument 是TypeScript定义好的类型实际上就是 interface IArguments {[index: number]: any;length: number;callee: Function; } ⑥ any在数组中的应用any表示数组中允许出现任意类型 let list: any[] [xcatliu, 25, { website: http://xcatliu.com }]; 六.函数的类型 ① 函数声明 输入多余或者少于的参数是不被允许的 function sum(x: number, y: number): number {return x y; } ②  函数表达式 let mySum: (x: number, y: number) number function (x: number, y: number): number {return x y; }; TypeScript 中的 和 ES6中的箭头不一样TypeScript中用来表示函数的定义左边是输入类型需要用括号括起来右边是输出类型 ③ 用接口定义函数的形状 interface SearchFunc {(source: string, subString: string): boolean }let mySearch: SearchFunc mySearch function (source: string, subString: string) {return source.search(subString) ! -1 } 用函数表达式或者接口定义函数时对等号左侧进行类型限制可以保证对函数名赋值时保证参数的个数参数类型和返回值类型不变 ④ 可选参数 在参数名后面加问号可选参数后面不允许再出现必选参数 ⑤ 参数默认值 允许给函数添加默认值TypeScript会将添加了默认值的参数识别为可选参数不受【可选参数必须在必选参数后面】限制了 ⑥ 剩余参数 ...rest的方式获取函数中的剩余参数rest只能是最后一个参数 function push(array: any[], ...items: any[]) {items.forEach(function (item) {array.push(item)}) }let a: any[] [] push(a, 1, 2, 3) ⑦ 重载 重载允许一个函数接受不同数量或类型的参数时作出不同的处理注意多个函数定义如果有包含关系需要优先把精确的定义写在前面因为TypeScript会优先从最前面的函数定义开始匹配 function reverse(x: number): number function reverse(x: string): string function reverse(x: number | string): number | string | void {if (typeof x number) {return Number(x.toString().split().reverse().join())} else if (typeof x string) {return x.split().reverse().join()} } 七.类型断言 ① 概念 类型断言含义可以手动指定一个值类型 语法值 as 类型     类型值 在 tsxReact 的 jsx 语法的 ts 版  语法中必须使用前者 类型这种语法在ts中除了表示类型断言之外也有可能是表示一个泛型 所以在使用断言的时候统一使用 值 as 这样的语法 ② 类型断言的用途 1 将一个联合类型断言为其中一个类型 此时可以使用类型断言将 animal 断言成 Fish 使用断言的时候一定要格外小心尽量避免断言后调用方法或者引用深层属性减少不必要的运行时的错误 2将一个父类断言为更加具体的子类 3将任何一个类型断言为any 在any类型的变量上访问任何属性都是允许的但是它可能掩盖了真正的类型错误所以如果不是非常确定就不要使用as any不能滥用 as any 也不要完全否定它的作用需要在类型的严格性和开发的便利性之间掌握平衡 4将as断言为一个具体的类型 明确tom的类型之后提高代码的可维护性 总结 联合类型可以被断言为其中一个类型父类可以被断言为子类任何类型都可以被断言为anyany可以被断言为任何类型 ③ 类型断言的限制 并不是任何一个类型都可以被断言为任何另一个类型如果A兼容B那么A能够被断言成B, B也能被断言成A interface Animal {name: string } interface Cat {name: stringrun(): void }function testAnimal(animal: Animal) {return animal as Cat } function testCat(cat: Cat) {return cat as Animal } 允许animal as Cat 是因为 [父类可以被断言为子类]允许cat as Animal 是因为既然子类拥有父类的属性和方法那么被断言为父类获取父类的方法就不会有任何问题所以子类可以被断言为父类要使A能够被断言成B, 只需要A兼容B或者B兼容A即可 综上所述 联合类型可以被断言为其中一个类型父类可以被断言为子类任何类型都可以被被断言为anyany可以被断言为任何类型要使得 A 能够被断言为 B只需要 A 兼容 B 或 B 兼容 A 即可 ④ 双重断言 interface Cat {run(): void } interface Fish {swim(): void }function testCat(cat: Cat) {return cat as any as Fish } 会导致运行时错误除非迫不得已千万别使用双重断言 ⑤ 类型断言和类型转换 类型断言只会影响到TypeScript编译时的类型类型断言语句在编译结果中会被删除 类型断言不是类型转换它不会真的影响到变量的类型如果要进行类型转换需要直接调用类型转换的方法 ⑥ 类型断言和类型声明 类型断言 animal断言为Cat只需要满足Animal 兼容 Cat 或 Cat 兼容 Animal 即可animal赋值为Cat, 需要满足Cat兼容Animal才行但是Cat并不兼容Animal类型声明比类型断言更加严格最好优先使用类型声明 ⑦ 类型断言和泛型 更加规范的实现对 getCacheData 返回值的约束同时去掉了代码中的any是最优的一个解决方案 function getCacheDataT(key: string): T {return (window as any).cache[key] }interface Cat {name: stringrun(): void }const tom getCacheDataCat(tom) tom.run() 八. 声明文件 ① 当使用第三方库时我们需要引用它的声明文件才能获得对应的代码补全接口提示等功能 ② 声明语句 ③ 声明文件把声明语句放到一个单独的文件中 文件以 .d.ts 为结尾 其他所有*.ts文件就可以获得 jQuery 的类型定义了 declare var jQuery: (selector: string) any; ④ 第三方声明文件 使用 type 统一管理第三方库的声明文件直接使用npm 安装对应的声明模块  npm install types/jquery --save-dev ⑤ 书写声明文件 库的使用场景 全局变量通过script标签引入第三方库注入全局变量npm: 通过 import foo from foo 导入符合ES6模块规范UMD 库既可以通过 script 标签引入又可以通过 import 导入直接扩展全局变量通过 script 标签引入后改变一个全局变量的结构在 npm 包或 UMD 库中扩展全局变量引用 npm 包或 UMD 库后改变一个全局变量的结构模块插件通过 script 或 import 导入后改变另一个模块的结构 1全局变量 declare var/let/const 定义全局变量使用 declare var 和 declare let 没有区别使用 declare const 时表示此时的全局变量是一个常量不允许再修改它的值了一般来说全局变量都是禁止修改的常量所以大部分情况都应该使用const而不是var 或者 let声明语句中只能定义类型不要定义具体的实现 declare function 定义全局函数  declare function jQuery(selector: string): any; 函数类型的声明语句中函数重载也是支持的 declare function jQuery(selector: string): any; declare function jQuery(domReadyCallback: () any): any; declare class 定义的全局变量是一个类 declare class Animal {name: string;constructor(name: string);sayHi(): string; }  只能用来定义类型不能用来定义具体的实现 declare enum 定义枚举类型也被称为外部枚举 declare enum Directions {Up,Down,Left,Right } declare enum 仅用来定义类型而不是具体的值 declare namespace 用来表示全局变量是一个对象包含很多子属性 declare namespace jQuery {function ajax(url: string, settings?: any): void;const version: number;class Event {blur(eventType: EventType): void}enum EventType {CustomClick} } jQuery.ajax(/api/get_something); 嵌套的命名空间 如果对象拥有深层的层级需要使用嵌套的 namespace 来声明深层的属性的类型 declare namespace jQuery {function ajax(url: string, settings?: any): void;namespace fn {function extend(object: any): void;} }jQuery.ajax(/api/get_something); jQuery.fn.extend({check: function() {return this.each(function() {this.checked true;});} }); 如果 jQuery 下仅有fn这一个属性可以不需要嵌套  namespace declare namespace jQuery.fn {function extend(object: any): void; }jQuery.fn.extend({check: function() {return this.each(function() {this.checked true;});} }); interface 和 type 声明一个全局的接口或者类型 interface AjaxSettings {method?: GET | POSTdata?: any; } declare namespace jQuery {function ajax(url: string, settings?: AjaxSettings): void; }// src/index.tslet settings: AjaxSettings {method: POST,data: {name: foo} }; jQuery.ajax(/api/post_something, settings); type 与 interface类似 防止命名冲突 暴露在外层 interface 或 type 会作为全局类型作用于整个项目中应该尽可能减少全局变量或全局类型的数量所以将他们最好放到 namespace 下 declare namespace jQuery {interface AjaxSettings {method?: GET | POSTdata?: any;}function ajax(url: string, settings?: AjaxSettings): void; } 在使用interface的时候也应该加上 jQuery 前缀 let settings: jQuery.AjaxSettings {method: POST,data: {name: foo} }; jQuery.ajax(/api/post_something, settings); 声明合并 假如 jQuery 既是一个函数可以直接被调用 jQuery(#foo)又是一个对象拥有子属性 jQuery.ajax()事实确实如此那么可以组合多个声明语句他们会不冲突的合并起来 declare function jQuery(selector: string): any; declare namespace jQuery {function ajax(url: string, settings?: any): void; }jQuery(#foo); jQuery.ajax(/api/get_something); npm 包 九.内置对象 ① ECMAScript  标准提供的内置对象Boolean、Error、Date、RegExp可以在TypeScript中定义以下类型 let b: Boolean new Boolean(1); let e: Error new Error(Error occurred); let d: Date new Date(); let r: RegExp /[a-z]/; ② DOM和BOM的内置对象 Document、HTMLElement、Event、NodeListTypeScript中会经常用到这些类型 ③ TypeScript核心库的定义文件 定义了所有浏览器环境需要用到的类型并且是预置在 TypeScript中当使用一些常用的方法的时候TypeScript实际上已经帮你做了很多类型判断的工作TypeScript 核心库的定义中不包含 Node.js 部分如果想用TypeScript写Node.js,需要引入第三方声明文件  npm install types/node --save-dev 十.类型别名 就是给类型起一个别的名字使用type创建类型别名类型别名常用于联合类型 type Name string; type NameResolver () string; type NameOrResolver Name | NameResolver; function getName(n: NameOrResolver): Name {if (typeof n string) {return n;} else {return n();} } 十一.字符串字面量类型 用来约束取值只能是某几个字符串中的一个使用type定了一个 字符串字面量类型 EventNames 只能取三种字符串中的一种类型别名和字符串字面量类型都是type进行定义的 type EventNames click | scroll | mousemove; function handleEvent(ele: Element, event: EventNames) {// do something }handleEvent(document.getElementById(hello), scroll); // 没问题 handleEvent(document.getElementById(world), dblclick); // 报错event 不能为 dblclick 十二.元组 数组合并了相同类型的对象元组合并了不同类型的对象 let tom: [string, number] [Tom, 25]; let tom: [string, number]; tom[0] Tom; tom[1] 25;tom[0].slice(1); tom[1].toFixed(2); 也可以赋值其中一项 let tom: [string, number]; tom[0] Tom; 直接对元组类型变量进行初始化或者赋值的时候需要提供所有元组类型中指定的项 越界的元素 ① 当添加越界的元素时它的类型会被限制为元组中每个类型的联合类型 十三.枚举 枚举类型用于取值被限定在一定范围内的场景使用enum关键字来定义 enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; 手动赋值 ① 未手动赋值的枚举项会接着上一个枚举递增 ② 如果未手动赋值的枚举项与手动赋值的重复了TypeScript是不会报错的 ③ 所以使用的时候要注意最好不要有这种情况  enum Days {Sun 7, Mon 1, Tue, Wed, Thu, Fri, Sat}; ④ 手动赋值的枚举项可以不是数字这个时候需要使用类型断言来让tsc无视类型检查 enum Days {Sun 7, Mon, Tue, Wed, Thu, Fri, Sat anyS}; ⑤ 手动赋值的枚举项也可以是小数或者负数未赋值的项逐步增长1 常数项和计算所得项 ① 枚举项有两种类型常数项和计算所得项 常数项上面的例子就是常数项 计算所得项Blue blue.length enum Color {Red, Green, Blue blue.length}; ② 但是如果紧接在计算所得项后面的是未手动赋值的项就会因为无法获得初始值而报错 ③ 当满足以下条件时枚举成员被当作是常数 不具有初始化函数并且之前的枚举成员是常数当前枚举成员的值等于上一个枚举成员的值 1第一个枚举元素的值是0枚举成员使用常数枚举表达式初始化 数字字面量引用之前定义的常数枚举成员 带括号的常数枚举表达式 , -, ~ 一元运算符应用于常数枚举表达式 , -, *, /, %, , , , , |, ^ 二元运算符常数枚举表达式做为其一个操作对象 所有其他情况的枚举成员被当作是需要计算得出的值 ④ 常数枚举 使用 const enum 定义的枚举类型 const enum Directions {Up,Down,Left,Right }let directions [Directions.Up, Directions.Down, Directions.Left, Directions.Right]; 与普通枚举的区别是会在编译阶段被删除并且不能包含计算成员 ⑤ 外部枚举 外部枚举是使用 declare enum 定义的枚举类型 declare enum Directions {Up,Down,Left,Right }let directions [Directions.Up, Directions.Down, Directions.Left, Directions.Right]; declare和const可以同时使用 declare const enum Directions {Up,Down,Left,Right }let directions [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
http://www.w-s-a.com/news/672886/

相关文章:

  • 适合seo的建站系统如何建立网页
  • 我想自己建立一个网站给大家分享个永久免费的云服务器
  • 怎样做网站和网站的友情链接官网优化 报价
  • 购买网站空间大小聊城网站空间公司
  • 做像美团淘宝平台网站多少钱开发网站企业
  • 网站建设前期费用二手购物网站策划书
  • dede学校网站百度联盟是什么
  • 献县网站建设网站开发专业定制
  • 龙华做网站yihe kj安徽六安彩礼一般给多少
  • flash网站建设公司我的小程序在哪里找
  • 建网站需要数据库吗如何制作简单的网页链接
  • 杭州设计企业网站高端公司上虞做网站公司
  • 做网站能赚钱么用wordpress搭建知名网站
  • 阿里云服务器网站开发青岛做网站找哪家
  • 凡科做的网站为什么打不开织梦cms仿某作文网站整站源码(带采集)安装数据库
  • 免费h5模板网站模板汽车报价网址
  • 蔡甸网站建设烟台网站建设yt
  • 最流行的网站开发新开的网页游戏平台
  • 暴富建站wordpress 标签分类
  • 搞笑网站源码百度快照替代
  • 重庆网站建设哪家公司哪家好关键词是怎么排名的
  • 青县网站建设今天国际大事新闻
  • 深圳正规网站制作哪里好怎样优化网络
  • 米拓网站建设教程dw成品网站成品视频教学
  • 用jsp做的网站源代码天门网站网站建设
  • 百度如何把网站做链接地址有没有资源可以在线观看
  • 淮安做网站找哪家好电子商务网站建设规划书的内容
  • 开发网站建设用什么框架php黄页系统
  • 聊城制作网站全球十大电商平台排名
  • 用什么来网站开发好mega menu wordpress