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

中国建设银行网站密码沧州市建设局网站

中国建设银行网站密码,沧州市建设局网站,海宁市建设局官方网站,服务器网站 都被做跳转启用对 JavaScript 文件的类型检查 在 TypeScript 编译选项 compilerOptions 全部配置项 中#xff0c;可以通过以下2个属性配置 JavaScript Support#xff1a; allowJs 是否允许编译 JavaScript 文件。默认值是 false。在默认情况下#xff0c;TypeScript 编译器只处理 .…启用对 JavaScript 文件的类型检查 在 TypeScript 编译选项 compilerOptions 全部配置项 中可以通过以下2个属性配置 JavaScript Support allowJs 是否允许编译 JavaScript 文件。默认值是 false。在默认情况下TypeScript 编译器只处理 .ts、.tsx和 .d.ts文件不会编译 .js文件。 checkJs 是否对 JavaScript 文件进行类型检查。默认值是 false。在默认情况下TypeScript 编译器不会对 JavaScript 文件进行类型检查。 在 tsconfig.json 中配置 {compilerOptions: {allowJs: true,checkJs: true,target: es5,module: commonjs,strict: true} }类型检查的范围和限制 类型推断TypeScript 会尝试对 JavaScript 文件中的变量和函数进行类型推断。例如如果一个变量被赋值为一个字符串TypeScript 会推断该变量的类型为字符串。注意由于 JavaScript 是动态类型语言类型推断可能不是完全准确的。函数参数和返回值对于有明确参数和返回值类型注释的 JavaScript 函数TypeScript 可以进行更严格的类型检查。如果函数的实际参数类型与注释不匹配或者返回值类型与预期不符TypeScript 会报告错误。模块导入和导出当 JavaScript 文件使用模块导入和导出时TypeScript 可以检查导入和导出的类型是否匹配。但是如果导入的模块没有类型声明文件.d.ts类型检查可能会受到限制。 添加注释忽略类型检查 使用 // ts-nocheck 忽略类型检查 // ts-nocheck 注释可以用来忽略对特定 JavaScript 文件的类型检查。 如果allowJs: true,checkJs: true,需要对某个JavaScript文件关闭类型检查可以在文件的顶部添加 // ts-nocheck 注释 // ts-nocheck function add(a, b) {return a b; }const result add(Hello, 5); console.log(result);这样TypeScript 在处理这个文件时将忽略类型检查不会报告错误。 使用 // ts-check 开启类型检查 如果allowJs: true,checkJs: false,但是要对某个JavaScript文件进行类型检查可以添加 // ts-check 注释 // ts-check function multiply(a, b) {return a * b; }const product multiply(3, four); console.log(product);当 TypeScript 处理这个文件时会报告类型错误。 使用 // ts-ignore 忽略特定行的错误 如果allowJs: true,checkJs: true,需要让 TypeScript 忽略JavaScript文件某一行的类型检查错误可以该语句上方添加// ts-ignore 注释 let a 10; // ts 类型检查 推断 a 是numbera hello world; // 报错不能将类型“string”分配给类型“number”。// ts-ignore a hello world; // 类型检查错误被忽略不会报错// ts-ignore 仅仅对紧随其后的那一行代码做约束,可以写在代码的任意位置 使用// ts-expect-error忽略特定行的错误 如果allowJs: true,checkJs: true,需要让 TypeScript 忽略JavaScript文件某一行的类型检查错误可以该语句上方添加// ts-expect-error注释 let a 10; // ts 类型检查 推断 a 是numbera hello world; // 报错不能将类型“string”分配给类型“number”。// // ts-expect-error a hello world; // 类型检查错误被忽略不会报错// ts-expect-error与 // ts-ignore 的区别 如果随后一行代码是没有类型错误,代码提示器就会认为ts-expect-error 没有被使用。 ts-ignore不会有提示。 JavaScript 用 JSDoc 来 明确类型信息 .js文件里类型可以和在.ts文件里一样被推断出来。如同TypeScript--noImplicitAny会在编译器无法推断类型的位置报错。 所有JSDoc支持的模式请看JSDoc中文文档。 使用JSDoc来明确类型信息 使用 param 标签来指定函数参数的类型使用 return 标签来指定函数的返回值类型。 示例 /*** param {number} num1 - The first number.* param {number} num2 - The second number.* return {number} - The sum of the two numbers.*/ function sum(num1, num2) {return num1 num2; } // 使用示例 console.log(sum( hello, 10 )); // 报错类型“string”的参数不能赋给类型“number”的参数。在这个例子中使用 param {number} num1 和 param {number} num2 来指定函数 sum 的两个参数都是数字类型。 sum( hello, 10 ) 会报错类型“string”的参数不能赋给类型“number”的参数。 TS支持的JSDoc 下面的列表列出了当前所支持的JSDoc注解你可以用它们在JavaScript文件里添加类型信息。 注意没有在下面列出的标记例如async都是还不支持的。 typeparam (or arg or argument)returns (or return)typedefcallbacktemplateclass (or constructor)thisextends (or augments)enum type 可以使用type标记并引用一个类型名称原始类型TypeScript里声明的类型或在JSDoc里typedef标记指定的 可以使用任何TypeScript类型和大多数JSDoc类型。 语法 type {type} - description示例 /** /*** type {Object} person* property {string} name - The persons name.* property {number} age - The persons age.*/let person {name: John,age: 36,address: xxxxx } 变量person 有两个明确的属性name 是字符串类型用于表示人的名字age 是数字类型用于表示人的年龄。但是又不止这两个属性没有明确定义的属性address 也不会报错。 指定对象字面量类型使用 {} 来表示对象类型并列出对象的属性和类型 /** type {{name: string, age: number}} */ let person { name: John, age: 30 }; person { name: John, age: 30, address: xxxxx }; // 报错有多种方式来指定数组其中 type 是数组元素的类型 type Arraytypetype Array.typetype {type[]} 示例 /** type {Arraynumber} */ let arr [1, 2, 3]; arr.push(abc); // 报错类型“string”的参数不能赋给类型“number”的参数。type {Arraynumber} 指定数组的每项元素的类型是number。 使用 | 来表示联合类型 /** type {Arraynumber | string} */ let arr [1, 2, 3]; arr.push(abc);现在数组的每项元素的类型是 number 或 string。 在类型后面加上 ? 表示该类型是可选的 /** type {{name: string, age?: number}} */ let person { name: John }; person.age 36;可以使用字符串和数字索引签名来指定map-like和array-like的对象使用标准的JSDoc语法或者TypeScript语法 /*** A map-like object that maps arbitrary string properties to numbers.** type {Object.string, number}*/ let stringToNumber;/** type {Object.number, object} */ let arrayLike;这两个类型与TypeScript里的{ [x: string]: number }和{ [x: number]: any }是等同的。编译器能识别出这两种语法。 分析示例 第一个类型注释 “A map-like object that maps arbitrary string properties to numbers.”这个描述清晰地说明了这个对象的预期用途即它是一个类似映射map的对象将任意的字符串属性映射到数字。type {Object.string, number}表示这个变量 stringToNumber 被期望是一个对象其键为字符串类型值为数字类型。 使用示例 /*** A map-like object that maps arbitrary string properties to numbers.** type {Object.string, number}*/ let stringToNumber {key1: 10,key2: 20 };第二个类型注释 type {Object.number, object}表明变量 arrayLike 被期望是一个对象其键为数字类型值为任意对象类型。 这种类型注释可以用于表示一个类似数组的对象其中数字键可以用来模拟数组的索引而值可以是各种不同类型的对象。 使用示例 /** type {Object.number, object} */ let arrayLike {0: { name: obj1 },1: { name: obj2 } };指定一个对象是 Window 该对象应该具有 Window 对象的属性和方法 /** type {Window} */ let win window;win.alert(Hello!);指定一个变量 是一个类似于 Promise 的对象并且这个 Promise 最终会 resolve 为一个字符串值 /** type {PromiseLikestring} */ let promisedString;在这个示例中 Promise 类似对象 在 JavaScript 中Promise 是一种用于处理异步操作的机制。它代表了一个尚未完成但预期在未来完成的操作并提供了一种方式来处理操作成功resolved或失败rejected的情况。PromiseLike 表示具有与 Promise 类似的行为的对象。它不一定完全符合 Promise 的规范但可能具有 .then() 和 .catch() 等方法用于处理异步操作的结果。 注意PromiseLikestring 期望的 .then() 方法应该接受两个可选的回调函数一个用于处理成功的情况一个用于处理失败的情况。 字符串结果 type {PromiseLikestring}指定了这个 Promise 类似对象最终会产生一个字符串类型的结果。当这个异步操作完成时可以预期从这个对象中获取一个字符串值。 指定变量是一个HTMLElement 类型的对象 /** type {HTMLElement} */ let myElement document.querySelector(selector); element.dataset.myData ;在这个示例中 type {HTMLElement}表明变量 myElement 被期望是一个 HTMLElement 类型的对象。在 JavaScript 中HTMLElement 代表 HTML 文档中的一个元素。 使用TypeScript或Closure语法指定函数类型 /** type {function(string, boolean): number} Closure syntax */ let sbn; /** type {(s: string, b: boolean) number} Typescript syntax */ let sbn2;在这个示例中 JSDoc 类型注释Closure 语法 type {function(string, boolean): number} 这个 JSDoc 类型注释表明变量 sbn 被期望是一个函数类型。这个函数接受两个参数第一个参数是字符串类型string第二个参数是布尔类型boolean并且这个函数返回一个数字类型number的值。 TypeScript 类型注释语法 type {(s: string, b: boolean) number} 这是使用 TypeScript 类型注释语法来指定变量 sbn2 的类型。同样它表示 sbn2 是一个函数接受一个字符串参数 s 和一个布尔参数 b并返回一个数字。 用法示例 /** type {function(string, boolean): number} Closure syntax */ let sbn function (str, bool) {// 根据字符串和布尔值进行一些操作并返回一个数字if (bool) {return str.length;} else {return 0;} };/** type {(s: string, b: boolean) number} Typescript syntax */ let sbn2 function (s, b) {return b ? s.length : -1; };console.log(sbn(Hello, true)); // 5 console.log(sbn2(World, false)); // -1直接使用未指定的Function类型: /** type {Function} */ let fnOne; /** type {function} */ let fnTwo;在 JavaScript 中Function or function是所有函数的类型。使用这个注释意味着 fnOne 、fnTwo可以被赋值为任何函数。 Closure的其它类型也可以使用 /*** type {*} - can be any type*/ let star; /*** type {?} - unknown type (same as any)*/ let question;类型注释说明 type {*} : 这个 JSDoc 类型注释表明变量 star 可以是任何类型。在一些情况下使用 * 表示“any”类型是为了在文档中明确指出该变量的类型是不确定的或者可以是任意类型。type {?} 这个 JSDoc 类型注释表明变量 question 的类型是未知的并且说它与“any”类型相同。 转换 在括号表达式前面使用type标记可以将一种类型转换成另一种类型 /*** type {number | string}*/// 根据随机数的结果将变量 numberOrString 赋值为字符串 hello 或者数字 100。 let numberOrString Math.random() 0.5 ? hello : 100;// 类型断言将 numberOrString 断言为数字类型并赋值给 typeAssertedNumber。 let typeAssertedNumber /** type {number} */ (numberOrString)导入类型 可以使用导入类型从其它文件中导入声明。 这个语法是TypeScript特有的与JSDoc标准不同 /*** param p { import(./a).Pet }*/ function walk(p) {console.log(Walking ${p.name}...); }param p { import(./a).Pet } 这个 JSDoc 类型注释表明函数 walk 的参数 p 是从模块 ./a 中导入的类型为 Pet 的对象。这指定了参数 p 的预期类型。 如果模块 ./a 定义了 Pet 类型如下 // 模块./a export class Pet {constructor(name) {this.name name;} }可以这样使用 walk 函数 import { Pet } from ./a; const myPet new Pet(Fluffy); walk(myPet);导入类型也可以使用在类型别名声明中 /*** typedef Pet { import(./a).Pet }*//*** type {Pet}*/ let myPet; // myPet 的类型 是 Pet 的类型别名。 myPet.name;typedef Pet { import(./a).Pet }: 这里使用 typedef 定义了一个名为 Pet 的类型别名。它表示这个新定义的 Pet 实际上是从模块 ./a 中导入的类型。type {Pet} 这个类型注释表明变量 myPet 的类型是前面定义的 Pet 类型别名也就是从模块 ./a 中导入的那个类型。 导入类型可以用在从模块中得到一个值的类型 /*** type {typeof import(./a).x }*/ let x require(./a).x;type {typeof import(./a).x } 这个 JSDoc 类型注释表明变量 x 的类型是模块 ./a 中导出的变量 x 的类型。具体来说typeof import(./a).x 获取了模块 ./a 中 x 的类型信息这里使用这个类型信息来注释变量 x表示变量 x 应该与模块 ./a 中的 x 具有相同的类型。let x require(./a).x: 这行代码使用 CommonJS 模块规范的 require 函数导入模块 ./a并将模块中导出的 x 赋值给变量 x。 typedef 在 JSDoc 中typedef 用于定义一个类型别名。 语法 typedef {type} name - description其中type 是现有的类型name 是新定义的类型别名description 是对这个类型别名的描述。 示例 /*** typedef {Object} Person* property {string} name - The persons name.* property {number} age - The persons age.*//*** param {Person} person - A person object.*/ function greet(person) {console.log(Hello, ${person.name}! You are ${person.age} years old.); }const person1 { name: John, age: 30 }; greet(person1);在这个例子中typedef 定义了一个名为 Person 的类型别名它是一个对象类型包含 name字符串类型和 age数字类型两个属性。然后函数 greet 接受一个参数 person其类型被注释为 Person表示这个参数应该是一个符合 Person 类型定义的对象。 type 和 typedef 的区别 type 用于指定一个变量、参数或返回值的具体类型。它通常用于为已有的类型提供类型注释而不是创建新的类型别名。 typedef 用于定义一个新的类型别名。它允许你为一个复杂的类型结构创建一个更具描述性的名称以便在代码中重复使用。 param和returns 在 JSDoc 中param用于描述函数的参数。 param语法 param {type} name - description其中 type 是参数的类型name 是参数的名称description 是对参数的描述。 注意param语法和type相同但增加了一个参数名。 使用[]可以把参数声明为可选的。 在 JSDoc 中returns用于描述函数的返回值。 returns语法 returns {type} - description其中 type 是函数的返回值类型description 是对返回值的描述。 示例 /*** param {number} a - The first number.* param {number} b - The second number.* param {number} c - The third number.* param {number} [d10] - The fourth number.* returns {number} */ function sum(a, b, c, d 10) {c c ?? 0;return a b c d; }console.log(sum(1, 2, 3)); // 6 console.log(sum(1, 2, undefined, undefined)); // 3 console.log(sum(1, 2, undefined, 10)); // 13参数c和d被标记为可选参数。在调用函数时它们可能没有被传入值。因此需要对参数进行类型判断。 typedef 与 param typedef可以声明复杂类型。它和param在语法上有一定的相似性但用途不同。 使用typedef 定义一个包含多个属性的对象类型别名 /*** typedef {Object} Person* property {string} name - The persons name.* property {number} age - The persons age.* property {string[]} hobbies - The persons hobbies.*//*** param {Person} person - A person object.*/ function displayPersonInfo(person) {console.log(Name: ${person.name}, Age: ${person.age}, Hobbies: ${person.hobbies.join(, )}); }param允许使用相似的语法。 注意嵌套的属性名必须使用参数名做为前缀 /*** param {Object} options - The shape is the same as SpecialType above* param {string} options.prop1* param {number} options.prop2* param {number} options.prop3* param {number} [options.prop4]* param {number} [options.prop542]*/ function special(options) {let op5 options.prop5 ?? 0;return (options.prop4 || 1001) op5; }使用typedef声明函数类型的别名 /*** typedef {(a: number, b: number) number} MathOperation*//*** param {MathOperation} operation - A math operation function.* param {number} x - The first number.* param {number} y - The second number.*/ function performMathOperation(operation, x, y) {return operation(x, y); }在这个例子中定义了一个名为MathOperation的函数类型别名代表接受两个数字参数并返回一个数字的函数类型。在函数performMathOperation中使用了MathOperation来注释参数operation。 param {MathOperation} operation - A math operation function.这个参数注释表明参数 operation 的类型是前面定义的 MathOperation即一个特定的函数类型。这意味着在调用这个函数时传入的 operation 参数应该是一个接受两个数字参数并返回一个数字的函数。 callback 在 JSDoc 中callback用于定义回调函数的类型。 语法 callback callbackName - description其中callbackName是回调函数的名称用于在文档中引用这个回调函数类型。description是对回调函数的描述。 在callback的注释块内部可以使用param和returns等标签来描述回调函数的参数和返回值类型。 示例 /*** callback ProcessFunction* param {string} data - The input data.* returns {number} The processed result.*//*** Processes data using a callback function.* param {string} inputData - The data to process.* param {ProcessFunction} callback - The callback function to process the data.*/ function processData(inputData, callback) {const result callback(inputData);return result; }在这个例子中 使用callback定义了一个名为ProcessFunction的回调函数类型它接受一个字符串类型的参数data并返回一个数字类型的值。在函数processData的文档注释中使用这个回调函数类型来注释参数callback表示这个参数应该是一个符合ProcessFunction类型定义的回调函数。 template 在 JSDoc 中template用于描述函数或类的模板参数。 语法 template {typeParam} name - description其中typeParam是模板参数的类型name是模板参数的名称description是对模板参数的描述。 使用template声明泛型 /*** template T* param {T} x - A generic parameter that flows through to the return type* return {T}*/ function someArg(x){ return x }console.log(someArg(5)); // 5 console.log(someArg(hi)); // hi const obj { name: John, age: 30 }; console.log(someArg(obj)); // { name: John, age: 30 }使用 template 声明了一个模板参数 T。 param {T} x表明函数接受一个参数 x其类型为模板参数 T。 return {T}明确了函数的返回值类型也是模板参数 T。 函数换入的参数类型与返回值的类型保持一致。 用逗号或多个标记来声明多个类型参数 /*** template T,U,V* template W,X*/可以在参数名前指定类型约束。 例如对第一个参数的类型进行严格的限制 /*** template {string} K - K must be a string or string literal* template {{ serious(): string }} Seriousalizable - must have a serious method* param {K} key* param {Seriousalizable} object*/ function seriousalize(key, object) {// ???? }template {string} K定义了一个模板参数 K并限制其类型为字符串或字符串字面量。 也就是说在调用函数seriousalize时第一个参数 key 的类型必须是字符串或字符串字面量。 一个综合示例 /*** template T* function mapArray* param {T[]} array - The input array.* param {(item: T) T} callback - The callback function to apply to each item.* returns {T[]} The mapped array.*/function mapArray(array, callback) {return array.map(callback); }const numbers [1, 2, 3]; const doubledNumbers mapArray(numbers, (num) num * 2); console.log(doubledNumbers); // [2, 4, 6]const strings [a, b, c]; const upperCaseStrings mapArray(strings, (str) str.toUpperCase()); console.log(upperCaseStrings); // [A, B, C]在这个例子中template T定义了一个模板参数T表示函数mapArray可以接受任何类型的数组并对数组中的每个元素应用一个回调函数。函数mapArray的参数array被注释为T[]表示一个类型为T的数组参数callback被注释为(item: T) T表示一个接受类型为T的参数并返回类型为T的函数。 class (or constructor) 在 JSDoc 中constructor用于标记一个函数为构造函数。 语法 constructor通常放在函数的文档注释中紧跟在函数的描述之后。示例 /*** A simple class representing a person.* constructor* param {string} name - The persons name.* param {number} age - The persons age.*/ function Person(name, age) {this.name name;this.age age; }const person1 new Person(John, 30); console.log(person1.name); console.log(person1.age);在这个例子中constructor标记了函数Person为构造函数。当使用new关键字调用Person函数时它会创建一个新的对象并将传入的参数赋值给对象的属性。 使用constructor可以明确一个函数是用于创建对象的构造函数。 不幸的是这意味着那些既能构造也能直接调用的构造函数不能使用constructor。 this 编译器通常可以通过上下文来推断出this的类型。 在 JSDoc 中this用于描述函数中 this 的类型。 语法 this {type} - description其中type是 this 的类型description是对 this 的描述。 明确this指向“上下文对象” /*** this {Object} context - The context object.* param {number} a - The first number.* param {number} b - The second number.* returns {number} The sum of the two numbers.*/ function sum(a, b) {return this.a this.b; }const context { a: 5, b: 3 }; const result sum.call(context, context.a, context.b); console.log(result); // 8在这个例子中this {Object} context - The context object.表示在函数 sum 中this 的类型是一个对象描述为“上下文对象”。通过 sum.call(context, context.a, context.b) 调用函数 sum 并将 context 作为 this 的值传入从而可以在函数内部使用 this.a 和 this.b 来访问 context 对象的属性。 明确this指向HTML 元素对象 /*** this {HTMLElement}* param {*} e*/ function callbackForLater(e) {this.style.height parseInt(e) px; }this {HTMLElement} 这个注释表明在函数 callbackForLater 中this 的类型被期望为 HTMLElement。当这个函数被调用时this 应该指向一个 HTML 元素对象。 extends (or augments) 在 JSDoc 中extends用于表示一个类型继承自另一个类型。 语法 extends {type} - description其中type是被继承的类型description是对继承关系的描述。 当JavaScript类继承了一个基类无处指定类型参数的类型。而extends标记提供了这样一种方式 /*** template T* extends {SetT}*/ class SortableSet extends Set {// ... }注意extends只作用于类。当前无法实现构造函数继承类的情况。 enum 在 JSDoc 中enum用于定义枚举类型。 语法 enum {Object} name - description其中name是枚举的名称description是对枚举的描述。在注释块内部可以使用键值对的形式来定义枚举的成员。 enum标记允许创建一个对象字面量它的成员都有确定的类型。与JavaScript里大多数的对象字面量不同它不允许添加额外成员。 /** enum {number} */ const JSDocState {BeginningOfLine: 0,SawAsterisk: 1,SavingComments: 2, }注意JSDoc 的enum与TypeScript的enum大不相同JSDoc 的enum可以是任何类型。这意味着可以根据需要定义枚举成员的值为数字、字符串或其他复杂的数据类型。 例如可以定义一个枚举其中成员的值是对象或函数 /*** enum {Object} MyEnum* property {function(): void} Action1 - Description of Action1.* property {function(): void} Action2 - Description of Action2.*/不支持的写法 对象字面量中标记属性可选是不能使用后缀的 // 错误示例 const obj {prop1: value1,prop2: value2,prop3: value3 // 错误的语法不能用 : 来表示可选属性 };// 正确的写法是使用 ? 表示可选属性 const obj {prop1: value1,prop2: value2,prop3?: value3 // 正确的语法表示 prop3 是可选属性 };Nullable类型只在启用了strictNullChecks检查时才起作用 /*** type {?number}* With strictNullChecks: true -- number | null* With strictNullChecks: off -- number*/ var nullable;type {?number}描述变量 nullable 的类型可以是number或者 null。 Non-nullable类型没有意义以其原类型对待 /*** type {!number}* Just has type number*/ var normal;
http://www.w-s-a.com/news/392020/

相关文章:

  • 公司网站友情链接怎么做副链华为荣耀手机官网
  • 一条龙做网站旅游网页设计模板图凡科
  • 中山网站建设哪家便宜在中国做外国网站怎么收钱
  • 网站优化大计孝感注册公司
  • 设计接单app平台有哪些在线网站seo诊断
  • 兰州网站建设推广现代营销手段有哪些
  • 郴州网站seo优化网络安全哪个培训班比较好
  • 做网站需要记哪些代码企业网站建设思路
  • 重庆自助建站模板网络服务器配置与管理
  • 外贸网站怎样做小程序买量平台
  • 中山精品网站建设机构海外留学网站建设方案
  • 长春网站建设工作如何取消wordpress页脚
  • 忻府网站建设排名网络管理系统官网
  • 张家港外贸网站建设国医堂网站平台建设
  • 水冶那里有做网站的对于网站链接优化有哪些建议
  • 宝安中心地铁站是几号线化妆品网站做的好的
  • 海宁营销型网站设计企业融资是什么意思
  • 淘宝客做网站要钱吗网站开发试题库
  • 10g空间网站做视频网站网站建设找超速云
  • 一元购网站怎么做企业网站源码cms
  • 域名不变 网站改版临沂企业网站建站模板
  • 天河网站建设信科网络外包公司和公司直招哪个好
  • 网站制作哈尔滨聊天系统源码
  • 网站建设朋友圈素材青白江建设网站
  • 红酒网站设计软件设计文档
  • 如何创建网站目录网站申请支付宝接口
  • 网站做区块链然后往里面投钱品牌设计公司收费标准
  • 2022互联网+创新创业项目呼和浩特企业网站排名优化
  • 电子商务类网站建设山西自助建站系统怎么用
  • odoo做网站网站设置专栏有什么好处