- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > web開(kāi)發(fā) > JavaScript >
- Vue新搭檔TypeScript快速入門(mén)實(shí)踐記錄
Vue
官方從2.6.X
版本開(kāi)始就部分使用Ts
重寫(xiě)了。
我個(gè)人對更嚴格類(lèi)型限制沒(méi)有積極的看法,畢竟各類(lèi)轉類(lèi)型的騷寫(xiě)法寫(xiě)習慣了。
最近的一個(gè)項目中,是TypeScript
+ Vue
,毛計喇,學(xué)之...…真香!
注意此篇標題的“前”,本文旨在講Ts
混入框架的使用,不講Class API
npm install -g @vue/cli # OR yarn global add @vue/cli
新的Vue CLI
工具允許開(kāi)發(fā)者 使用 TypeScript
集成環(huán)境 創(chuàng )建新項目。
只需運行vue create my-app
。
然后,命令行會(huì )要求選擇預設。使用箭頭鍵選擇Manually select features
。
接下來(lái),只需確保選擇了TypeScript
和Babel
選項,如下圖:
完成此操作后,它會(huì )詢(xún)問(wèn)你是否要使用class-style component syntax
。
然后配置其余設置,使其看起來(lái)如下圖所示。
Vue CLI工具現在將安裝所有依賴(lài)項并設置項目。
接下來(lái)就跑項目
通過(guò)tree
指令查看目錄結構后可發(fā)現其結構和正常構建的大有不同。
這里主要關(guān)注shims-tsx.d.ts
和 shims-vue.d.ts
兩個(gè)文件
兩句話(huà)概括:
shims-tsx.d.ts
,允許你以.tsx
結尾的文件,在Vue
項目中編寫(xiě)jsx
代碼shims-vue.d.ts
主要用于 TypeScript
識別.vue
文件,Ts
默認并不支持導入 vue
文件,這個(gè)文件告訴ts
導入.vue
文件都按VueConstructor<Vue>
處理。此時(shí)我們打開(kāi)親切的src/components/HelloWorld.vue
,將會(huì )發(fā)現寫(xiě)法已大有不同
<template> <div class="hello"> <h1>{{ msg }}</h1> <!-- 省略 --> </div> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped></style>
至此,準備開(kāi)啟新的篇章 TypeScript
極速入門(mén) 和 vue-property-decorator
Typescript
與Javascript
共享相同的基本類(lèi)型,但有一些額外的類(lèi)型。
Tuple
enum
Any
與Void
1. 基本類(lèi)型合集
// 數字,二、八、十六進(jìn)制都支持 let decLiteral: number = 6; let hexLiteral: number = 0xf00d; // 字符串,單雙引都行 let name: string = "bob"; let sentence: string = `Hello, my name is ${ name }. // 數組,第二種方式是使用數組泛型,Array<元素類(lèi)型>: let list: number[] = [1, 2, 3]; let list: Array<number> = [1, 2, 3]; let u: undefined = undefined; let n: null = null;
2. 特殊類(lèi)型
1. 元組 Tuple
想象 元組 作為有組織的數組,你需要以正確的順序預定義數據類(lèi)型。
const messyArray = [' something', 2, true, undefined, null]; const tuple: [number, string, string] = [24, "Indrek" , "Lasn"]
如果不遵循 為元組 預設排序的索引規則,那么Typescript
會(huì )警告。
(tuple
第一項應為number
類(lèi)型)
2. 枚舉 enum
enum
類(lèi)型是對JavaScript標準數據類(lèi)型的一個(gè)補充。 像C#等其它語(yǔ)言一樣,使用枚舉類(lèi)型可以為一組數值賦予友好的名字。
// 默認情況從0開(kāi)始為元素編號,也可手動(dòng)為1開(kāi)始 enum Color {Red = 1, Green = 2, Blue = 4} let c: Color = Color.Green; let colorName: string = Color[2]; console.log(colorName); // 輸出'Green'因為上面代碼里它的值是2
另一個(gè)很好的例子是使用枚舉來(lái)存儲應用程序狀態(tài)。
3. Void
在Typescript
中,你必須在函數中定義返回類(lèi)型。像這樣:
若沒(méi)有返回值,則會(huì )報錯:
我們可以將其返回值定義為void
:
此時(shí)將無(wú)法 return
4. Any
emmm...就是什么類(lèi)型都行,當你無(wú)法確認在處理什么類(lèi)型時(shí)可以用這個(gè)。
但要慎重使用,用多了就失去使用Ts的意義。
let person: any = "前端勸退師" person = 25 person = true
主要應用場(chǎng)景有:
5. Never
用很粗淺的話(huà)來(lái)描述就是:"Never
是你永遠得不到的爸爸。"
具體的行為是:
throw new Error(message)
return error("Something failed")
while (true) {} // 存在無(wú)法達到的終點(diǎn)
3. 類(lèi)型斷言
簡(jiǎn)略的定義是:可以用來(lái)手動(dòng)指定一個(gè)值的類(lèi)型。
有兩種寫(xiě)法,尖括號和as
:
let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; let strLength: number = (someValue as string).length;
使用例子有:
當 TypeScript 不確定一個(gè)聯(lián)合類(lèi)型的變量到底是哪個(gè)類(lèi)型的時(shí)候,我們只能訪(fǎng)問(wèn)此聯(lián)合類(lèi)型的所有類(lèi)型里共有的屬性或方法:
function getLength(something: string | number): number { return something.length; } // index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'. // Property 'length' does not exist on type 'number'.
如果你訪(fǎng)問(wèn)長(cháng)度將會(huì )報錯,而有時(shí)候,我們確實(shí)需要在還不確定類(lèi)型的時(shí)候就訪(fǎng)問(wèn)其中一個(gè)類(lèi)型的屬性或方法,此時(shí)需要斷言才不會(huì )報錯:
function getLength(something: string | number): number { if ((<string>something).length) { return (<string>something).length; } else { return something.toString().length; } }
軟件工程的一個(gè)主要部分就是構建組件,構建的組件不僅需要具有明確的定義和統一的接口,同時(shí)也需要組件可復用。支持現有的數據類(lèi)型和將來(lái)添加的數據類(lèi)型的組件為大型軟件系統的開(kāi)發(fā)過(guò)程提供很好的靈活性。
在C#
和Java
中,可以使用"泛型"來(lái)創(chuàng )建可復用的組件,并且組件可支持多種數據類(lèi)型。這樣便可以讓用戶(hù)根據自己的數據類(lèi)型來(lái)使用組件。
1. 泛型方法
在TypeScript里,聲明泛型方法有以下兩種方式:
function gen_func1<T>(arg: T): T { return arg; } // 或者 let gen_func2: <T>(arg: T) => T = function (arg) { return arg; }
調用方式也有兩種:
gen_func1<string>('Hello world'); gen_func2('Hello world'); // 第二種調用方式可省略類(lèi)型參數,因為編譯器會(huì )根據傳入參數來(lái)自動(dòng)識別對應的類(lèi)型。
2. 泛型與Any
Ts
的特殊類(lèi)型 Any
在具體使用時(shí),可以代替任意類(lèi)型,咋一看兩者好像沒(méi)啥區別,其實(shí)不然:
// 方法一:帶有any參數的方法 function any_func(arg: any): any { console.log(arg.length); return arg; } // 方法二:Array泛型方法 function array_func<T>(arg: Array<T>): Array<T> { console.log(arg.length); return arg; }
arg
參數的length
屬性。因為any
可以代替任意類(lèi)型,所以該方法在傳入參數不是數組或者帶有length
屬性對象時(shí),會(huì )拋出異常。Array
的泛型類(lèi)型,肯定會(huì )有length
屬性,所以不會(huì )拋出異常。3. 泛型類(lèi)型
泛型接口:
interface Generics_interface<T> { (arg: T): T; } function func_demo<T>(arg: T): T { return arg; } let func1: Generics_interface<number> = func_demo; func1(123); // 正確類(lèi)型的實(shí)際參數 func1('123'); // 錯誤類(lèi)型的實(shí)際參數
Interface
,國內翻譯成接口。
Type alias
,類(lèi)型別名。
1. 相同點(diǎn)
都可以用來(lái)描述一個(gè)對象或函數:
interface User { name: string age: number } type User = { name: string age: number }; interface SetUser { (name: string, age: number): void; } type SetUser = (name: string, age: number): void;
都允許拓展(extends):
interface
和 type
都可以拓展,并且兩者并不是相互獨立的,也就是說(shuō)interface
可以 extends type
, type
也可以 extends interface
。 雖然效果差不多,但是兩者語(yǔ)法不同。
interface extends interface
interface Name { name: string; } interface User extends Name { age: number; }
type extends type
type Name = { name: string; } type User = Name & { age: number };
interface extends type
type Name = { name: string; } interface User extends Name { age: number; }
type extends interface
interface Name { name: string; } type User = Name & { age: number; }
2. 不同點(diǎn)
type
可以而 interface
不行
type
可以聲明基本類(lèi)型別名,聯(lián)合類(lèi)型,元組等類(lèi)型
// 基本類(lèi)型別名 type Name = string // 聯(lián)合類(lèi)型 interface Dog { wong(); } interface Cat { miao(); } type Pet = Dog | Cat // 具體定義數組每個(gè)位置的類(lèi)型 type PetList = [Dog, Pet]
type
語(yǔ)句中還可以使用 typeof
獲取實(shí)例的 類(lèi)型進(jìn)行賦值
// 當你想獲取一個(gè)變量的類(lèi)型時(shí),使用 typeof let div = document.createElement('div'); type B = typeof div
其他騷操作
type StringOrNumber = string | number; type Text = string | { text: string }; type NameLookup = Dictionary<string, Person>; type Callback<T> = (data: T) => void; type Pair<T> = [T, T]; type Coordinates = Pair<number>; type Tree<T> = T | { left: Tree<T>, right: Tree<T> };
interface
可以而 type
不行
interface
能夠聲明合并
interface User { name: string age: number } interface User { sex: string } /* User 接口為 { name: string age: number sex: string } */
interface
有可選屬性和只讀屬性
可選屬性
接口里的屬性不全都是必需的。 有些是只在某些條件下存在,或者根本不存在。 例如給函數傳入的參數對象中只有部分屬性賦值了。帶有可選屬性的接口與普通的接口定義差不多,只是在可選屬性名字定義的后面加一個(gè)?
符號。如下所示
interface Person { name: string; age?: number; gender?: number; }
只讀屬性
顧名思義就是這個(gè)屬性是不可寫(xiě)的,對象屬性只能在對象剛剛創(chuàng )建的時(shí)候修改其值。 你可以在屬性名前用 readonly
來(lái)指定只讀屬性,如下所示:
interface User { readonly loginName: string; password: string; }
上面的例子說(shuō)明,當完成User對象的初始化后loginName就不可以修改了。
extends
很明顯就是ES6里面的類(lèi)繼承,那么implement
又是做什么的呢?它和extends
有什么不同?
implement
,實(shí)現。與C#或Java里接口的基本作用一樣,TypeScript
也能夠用它來(lái)明確的強制一個(gè)類(lèi)去符合某種契約
implement基本用法:
interface IDeveloper { name: string; age?: number; } // OK class dev implements IDeveloper { name = 'Alex'; age = 20; } // OK class dev2 implements IDeveloper { name = 'Alex'; } // Error class dev3 implements IDeveloper { name = 'Alex'; age = '9'; }
而extends
是繼承父類(lèi),兩者其實(shí)可以混著(zhù)用:
class A extends B implements C,D,E
搭配 interface
和type
的用法有:
前面我們講到Vue項目中的shims-tsx.d.ts
和shims-vue.d.ts
,其初始內容是這樣的:
// shims-tsx.d.ts import Vue, { VNode } from 'vue'; declare global { namespace JSX { // tslint:disable no-empty-interface interface Element extends VNode {} // tslint:disable no-empty-interface interface ElementClass extends Vue {} interface IntrinsicElements { [elem: string]: any; } } } // shims-vue.d.ts declare module '*.vue' { import Vue from 'vue'; export default Vue; }
declare
:當使用第三方庫時(shí),我們需要引用它的聲明文件,才能獲得對應的代碼補全、接口提示等功能。
這里列舉出幾個(gè)常用的:
declare var 聲明全局變量
declare function 聲明全局方法
declare class 聲明全局類(lèi)
declare enum 聲明全局枚舉類(lèi)型
declare global 擴展全局變量
declare module 擴展模塊
namespace
:“內部模塊”現在稱(chēng)做“命名空間”
module X {
相當于現在推薦的寫(xiě)法 namespace X {
)
跟其他 JS 庫協(xié)同
類(lèi)似模塊,同樣也可以通過(guò)為其他 JS 庫使用了命名空間的庫創(chuàng )建 .d.ts
文件的聲明文件,如為 D3
JS 庫,可以創(chuàng )建這樣的聲明文件:
declare namespace D3{ export interface Selectors { ... } } declare var d3: D3.Base;
所以上述兩個(gè)文件:
shims-tsx.d.ts
, 在全局變量 global
中批量命名了數個(gè)內部模塊。shims-vue.d.ts
,意思是告訴 TypeScript
*.vue
后綴的文件可以交給 vue
模塊來(lái)處理。其實(shí)很好理解:
public
private
時(shí),它就不能在聲明它的類(lèi)的外部訪(fǎng)問(wèn),比如:class Animal { private name: string; constructor(theName: string) { this.name = theName; } } let a = new Animal('Cat').name; //錯誤,‘name'是私有的
protected
和private
類(lèi)似,但是,protected
成員在派生類(lèi)中可以訪(fǎng)問(wèn)
class Animal { protected name: string; constructor(theName: string) { this.name = theName; } } class Rhino extends Animal { constructor() { super('Rhino'); } getName() { console.log(this.name) //此處的name就是Animal類(lèi)中的name } }
可選參數
function buildName(firstName: string, lastName?: string) { return firstName + ' ' + lastName } // 錯誤演示 buildName("firstName", "lastName", "lastName") // 正確演示 buildName("firstName") // 正確演示 buildName("firstName", "lastName")
非空斷言操作符:
能確定變量值一定不為空時(shí)使用。
與可選參數 不同的是,非空斷言操作符不會(huì )防止出現 null 或 undefined。
let s = e!.name; // 斷言e是非空并訪(fǎng)問(wèn)name屬性
拓展
1. 屬性或參數中使用 ?:表示該屬性或參數為可選項
2. 屬性或參數中使用 ?。罕硎緩娭平馕觯ǜ嬖Vtypescript編譯器,這里一定有值),常用于vue-decorator中的@Prop
3. 變量后使用 ?。罕硎绢?lèi)型推斷排除null、undefined
從 vue2.5 之后,vue 對 ts 有更好的支持。根據官方文檔,vue 結合 typescript ,有兩種書(shū)寫(xiě)方式:
Vue.extend
import Vue from 'vue' const Component = Vue.extend({ // type inference enabled })
vue-class-component
import { Component, Vue, Prop } from 'vue-property-decorator' @Component export default class Test extends Vue { @Prop({ type: Object }) private test: { value: string }
理想情況下,Vue.extend
的書(shū)寫(xiě)方式,是學(xué)習成本最低的。在現有寫(xiě)法的基礎上,幾乎 0 成本的遷移。
但是Vue.extend
模式,需要與mixins
結合使用。在 mixin 中定義的方法,不會(huì )被 typescript 識別到
,這就意味著(zhù)會(huì )出現丟失代碼提示、類(lèi)型檢查、編譯報錯等問(wèn)題。
菜鳥(niǎo)才做選擇,大佬都挑最好的。直接講第二種吧:
我們回到
src/components/HelloWorld.vue
<template> <div class="hello"> <h1>{{ msg }}</h1> <!-- 省略 --> </div> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped></style>
有寫(xiě)過(guò)python
的同學(xué)應該會(huì )發(fā)現似曾相識:
vue-property-decorator
這個(gè)官方支持的庫里,提供了函數 **裝飾器(修飾符)**語(yǔ)法
1. 函數修飾符 @
“@”,與其說(shuō)是修飾函數倒不如說(shuō)是引用、調用它修飾的函數。
或者用句大白話(huà)描述:@
: "下面的被我包圍了。"
舉個(gè)栗子,下面的一段代碼,里面兩個(gè)函數,沒(méi)有被調用,也會(huì )有輸出結果:
test(f){ console.log("before ..."); f() console.log("after ..."); } @test func(){ console.log("func was called"); }
直接運行,輸出結果:
before ...
func was called
after ...
上面代碼可以看出來(lái):
test
和func
,沒(méi)有調用它們。但是,解釋器讀到函數修飾符“@”的時(shí)候,后面步驟會(huì )是這樣:
test
函數,test
函數的入口參數就是那個(gè)叫“func
”的函數;test
函數被執行,入口參數的(也就是func
函數)會(huì )被調用(執行);換言之,修飾符帶的那個(gè)函數的入口參數,就是下面的那個(gè)整個(gè)的函數。有點(diǎn)兒類(lèi)似JavaScrip
t里面的 function a (function () { ... });
2. vue-property-decorator
和vuex-class
提供的裝飾器
vue-property-decorator
的裝飾器:
vuex-class
的裝飾器:
我們拿原始Vue組件模版來(lái)看:
import {componentA,componentB} from '@/components'; export default { components: { componentA, componentB}, props: { propA: { type: Number }, propB: { default: 'default value' }, propC: { type: [String, Boolean] }, } // 組件數據 data () { return { message: 'Hello' } }, // 計算屬性 computed: { reversedMessage () { return this.message.split('').reverse().join('') } // Vuex數據 step() { return this.$store.state.count } }, methods: { changeMessage () { this.message = "Good bye" }, getName() { let name = this.$store.getters['person/name'] return name } }, // 生命周期 created () { }, mounted () { }, updated () { }, destroyed () { } }
以上模版替換成修飾符寫(xiě)法則是:
import { Component, Vue, Prop } from 'vue-property-decorator'; import { State, Getter } from 'vuex-class'; import { count, name } from '@/person' import { componentA, componentB } from '@/components'; @Component({ components:{ componentA, componentB}, }) export default class HelloWorld extends Vue{ @Prop(Number) readonly propA!: number | undefined @Prop({ default: 'default value' }) readonly propB!: string @Prop([String, Boolean]) readonly propC!: string | boolean | undefined // 原data message = 'Hello' // 計算屬性 private get reversedMessage (): string[] { return this.message.split('').reverse().join('') } // Vuex 數據 @State((state: IRootState) => state . booking. currentStep) step!: number @Getter( 'person/name') name!: name // method public changeMessage (): void { this.message = 'Good bye' }, public getName(): string { let storeName = name return storeName } // 生命周期 private created ():void { }, private mounted ():void { }, private updated ():void { }, private destroyed ():void { } }
正如你所看到的,我們在生命周期 列表那都添加private XXXX
方法,因為這不應該公開(kāi)給其他組件。
而不對method
做私有約束的原因是,可能會(huì )用到@Emit
來(lái)向父組件傳遞信息。
引入全局模塊,需要改main.ts
:
import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; Vue.config.productionTip = false; new Vue({ router, store, render: (h) => h(App), }).$mount('#app');
npm i VueI18n
import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; // 新模塊 import i18n from './i18n'; Vue.config.productionTip = false; new Vue({ router, store, i18n, // 新模塊 render: (h) => h(App), }).$mount('#app');
但僅僅這樣,還不夠。你需要動(dòng)src/vue-shim.d.ts
:
// 聲明全局方法 declare module 'vue/types/vue' { interface Vue { readonly $i18n: VueI18Next; $t: TranslationFunction; } }
之后使用this.$i18n()
的話(huà)就不會(huì )報錯了。
Axios
的封裝千人千面
如果只是想簡(jiǎn)單在Ts里體驗使用Axios
,可以安裝vue-axios
簡(jiǎn)單使用Axios
$ npm i axios vue-axios
main.ts
添加:
import Vue from 'vue' import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)
然后在組件內使用:
Vue.axios.get(api).then((response) => { console.log(response.data) }) this.axios.get(api).then((response) => { console.log(response.data) }) this.$http.get(api).then((response) => { console.log(response.data) })
1. 新建文件request.ts
文件目錄:
-api - main.ts // 實(shí)際調用 -utils - request.ts // 接口封裝
2. request.ts
文件解析
import * as axios from 'axios'; import store from '@/store'; // 這里可根據具體使用的UI組件庫進(jìn)行替換 import { Toast } from 'vant'; import { AxiosResponse, AxiosRequestConfig } from 'axios'; /* baseURL 按實(shí)際項目來(lái)定義 */ const baseURL = process.env.VUE_APP_URL; /* 創(chuàng )建axios實(shí)例 */ const service = axios.default.create({ baseURL, timeout: 0, // 請求超時(shí)時(shí)間 maxContentLength: 4000, }); service.interceptors.request.use((config: AxiosRequestConfig) => { return config; }, (error: any) => { Promise.reject(error); }); service.interceptors.response.use( (response: AxiosResponse) => { if (response.status !== 200) { Toast.fail('請求錯誤!'); } else { return response.data; } }, (error: any) => { return Promise.reject(error); }); export default service;
為了方便,我們還需要定義一套固定的 axios 返回的格式,新建ajax.ts
:
export interface AjaxResponse { code: number; data: any; message: string; }
3. main.ts
接口調用:
// api/main.ts import request from '../utils/request'; // get export function getSomeThings(params:any) { return request({ url: '/api/getSomethings', }); } // post export function postSomeThings(params:any) { return request({ url: '/api/postSomethings', methods: 'post', data: params }); }
5. 編寫(xiě)一個(gè)組件
為了減少時(shí)間,我們來(lái)替換掉src/components/HelloWorld.vue
,做一個(gè)博客帖子組件:
<template> <div class="blogpost"> <h2>{{ post.title }}</h2> <p>{{ post.body }}</p> <p class="meta">Written by {{ post.author }} on {{ date }}</p> </div> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; // 在這里對數據進(jìn)行類(lèi)型約束 export interface Post { title: string; body: string; author: string; datePosted: Date; } @Component export default class HelloWorld extends Vue { @Prop() private post!: Post; get date() { return `${this.post.datePosted.getDate()}/${this.post.datePosted.getMonth()}/${this.post.datePosted.getFullYear()}`; } } </script> <style scoped> h2 { text-decoration: underline; } p.meta { font-style: italic; } </style>
然后在Home.vue
中使用:
<template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <HelloWorld v-for="blogPost in blogPosts" :post="blogPost" :key="blogPost.title" /> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import HelloWorld, { Post } from '@/components/HelloWorld.vue'; // @ is an alias to /src @Component({ components: { HelloWorld, }, }) export default class Home extends Vue { private blogPosts: Post[] = [ { title: 'My first blogpost ever!', body: 'Lorem ipsum dolor sit amet.', author: 'Elke', datePosted: new Date(2019, 1, 18), }, { title: 'Look I am blogging!', body: 'Hurray for me, this is my second post!', author: 'Elke', datePosted: new Date(2019, 1, 19), }, { title: 'Another one?!', body: 'Another one!', author: 'Elke', datePosted: new Date(2019, 1, 20), }, ]; } </script>
這時(shí)候運行項目:
這就是簡(jiǎn)單的父子組件
而關(guān)于
Class API
撤銷(xiāo),其實(shí)還是挺舒服的。 用class
來(lái)編寫(xiě)Vue
組件確實(shí)太奇怪了。 (所以本篇Ts
入門(mén)壓根沒(méi)寫(xiě)Class API
)
以上就是Vue新搭檔TypeScript快速入門(mén)實(shí)踐的詳細內容,更多關(guān)于Vue TypeScript快速入門(mén)的資料請關(guān)注腳本之家其它相關(guān)文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站