Vue-Cli3

創(chuàng)建項(xiàng)目

vue cli是一個(gè)基于vue.js進(jìn)行快速開發(fā)的完整系統(tǒng),通常包含三個(gè)組件,分別是:

  • cli:@vue/cli是全局安裝的NPM包,提供終端vue命令,比如vue createvue serve、vue ui等命令。
  • cli服務(wù):@vue/cli-service是開發(fā)環(huán)境以來,構(gòu)建在webpack和webpack-dev-server之上,提供諸如serve、build、inspect等命令。
  • cli插件,為vue項(xiàng)目提供可選功能的NPM包,比如Babel/TypeScript轉(zhuǎn)譯、ESLint集成、UNIT和E2E測試等。

安裝

  • 安裝 vue-cli3 需要 Node.js 8.9+ 版本,推薦Node.js 8.11.0+版本。
  • vue-cli3 的包名由vue-cli改為@vue/cli,如果已安裝vue-cli1.x或2.x,可先通過npm uninstall -g vue-cli卸載。
  1. 檢查Node.js版本
  2. 卸載Vue-cli2.x
  3. 重新安裝@vue/cli
  4. 創(chuàng)建應(yīng)用
  5. 允許服務(wù)
# 查看Node.js版本
$ node -v
v12.14.0

# 卸載vue-cli
$ npm uninstall -g vue-cli

# 安裝vue腳手架
$ npm i -g @vue/cli

# 查看vue版本
$ vue --version
2.9.6

# 使用腳手架創(chuàng)建項(xiàng)目
$ vue create chat

$ cd chat

$ npm run serve

瀏覽器訪問 http://127.0.0.1:8080

選擇預(yù)設(shè)

創(chuàng)建Vue項(xiàng)目會(huì)提示選取一個(gè)preset預(yù)設(shè),可選默認(rèn)包含基本的Babel + ESLint設(shè)置的預(yù)設(shè),也可手工選擇特性。

Vue CLI v4.1.2
? Please pick a preset:
> default(babel, eslint)
 Manually select features
  • 默認(rèn)預(yù)設(shè):default(babel, eslint)

默認(rèn)設(shè)置適合快速創(chuàng)建新項(xiàng)目的原型,無任何輔助功能的NPM包。

  • 手工選擇特性:Manually select features

手動(dòng)配置,使用方向鍵控制,使用空格鍵選中,使用a鍵選擇。選項(xiàng)是所需面向生產(chǎn)環(huán)境的項(xiàng)目,提供可供選擇功能的NPM包。

手動(dòng)配置提供的NPM包

Vue CLI v4.1.2
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 ( ) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing

VUE CLI使用一套基于插件的架構(gòu),打開package.jsoon會(huì)發(fā)現(xiàn)依賴都是以@vue/cli-plugin-開頭。插件可以修改webpack內(nèi)部配置,也可以向vue-cli-service注入命令。

安裝插件

例如:手工添加eslint插件,命令會(huì)將@vue/eslint解析為完整的包名@vue/cli-plugin-eslint,然后從NPM安裝并調(diào)用其生成器。若不帶@vue前綴,命令會(huì)換做解析一個(gè)unscoped包,可基于一個(gè)指定的scope使用。

$ vue add @vue/eslint
NPM包 描述
Babel 轉(zhuǎn)碼器,將ES6轉(zhuǎn)換為ES5。
TypeScript JS超集擴(kuò)展了JS語法,需編譯輸出為JS。
PWA 漸進(jìn)式Web應(yīng)用程序
Router Vue路由
Vuex Vue狀態(tài)管理模式
CSS Pre-processors CSS預(yù)處理器
Linter/Formatter 代碼風(fēng)格檢查和格式化
Unit Testing 單元測試
E2E Testing e2e測試

babel

Babel是一個(gè)JavaScript編譯器,用于將ECMAScript2015+版本的代碼轉(zhuǎn)換為先后兼容的JavaScript語句。

  • 語法轉(zhuǎn)換
  • 通過Polyfill在目標(biāo)環(huán)境中添加缺失的特性
  • 源碼轉(zhuǎn)換

vue-router

vue-router默認(rèn)采用hash模式,也可選擇history模式。vue-router利用瀏覽器自身的hash模式和history模式的特性來實(shí)現(xiàn)前端路由,通過了瀏覽器提供的接口。

  • hash:瀏覽器URL地址欄中# 符號(hào),hash不被包括在HTTP請求中,對后端完全沒有影響,因此改變hash不會(huì)重新加載頁面。
  • history:利用HTML5 History Interface中新增的pushState()replaceState()方法,需特定瀏覽器支持,適用于單頁客戶端應(yīng)用。history mode徐后臺(tái)配置支持。

vue cli 3中采用src/router.js文件替代了vue cli 2的src/router/index.js文件

vuex

vuex用于狀態(tài)管理,vue cli 3中默認(rèn)使用store.js代替原vue cli 2種store文件夾中的三個(gè)JS文件action、mutations、state以及store的getters用法。

css pre-processors

css預(yù)處理器用于解決瀏覽器兼容并簡化css代碼等問題

目錄結(jié)構(gòu)

  • vue-cli3.x相比vue-cli2.x目錄簡潔了很多,沒有了build和config等文件夾。
  • vue-cli3.x相比vue-cli2.x所創(chuàng)建目錄中已經(jīng)看不到webpack的配置
  • vue-cli3.x中創(chuàng)建vue.config.js文件通過configureWebpack來配置webpack
文件 描述
.browserslistrc 用于指定項(xiàng)目的目標(biāo)瀏覽器范圍
package.json 定義項(xiàng)目所需模塊及項(xiàng)目信息
package-lock.json 鎖定安裝時(shí)的包版本號(hào)
tsconfig.json TypeScript配置文件
babel.config.js Babel配置文件
.eslintrc.js eslint檢測規(guī)則配置
.gitignore GIT配置文件
public 配置ico和index.html
src vue項(xiàng)目文件夾
src/assets/ 用于存放項(xiàng)目靜態(tài)文件,包括圖片、JS、SVG等,生產(chǎn)環(huán)境下會(huì)被WebPack復(fù)制。
src/components/ 存放公用Vue組件頁面
src/styles 存放重寫reset.css以及字體圖標(biāo)CSS文件
src/views 存放較大模塊,比如登錄頁、注冊頁、首頁等。

public

vue cli 3摒棄vue cli2的static文件夾新增了public文件夾,vue cli 2中static文件夾是webpack存放默認(rèn)靜態(tài)資源的文件夾,打包時(shí)會(huì)直接復(fù)制一份到dist文件夾中,且不會(huì)經(jīng)過webpack編譯。vue cli 3中靜態(tài)資源有兩種處理方式:

  • 經(jīng)過webpack處理:在JS被導(dǎo)入或在template/css中通過相對路徑被引用的資源會(huì)編譯并壓縮。
  • 不經(jīng)過webpack處理:放置在public文件夾下或通過絕對路徑被引用的資源將會(huì)直接拷貝一份,且不做任何編譯壓縮處理。

vue cli 3中public/index.html模板會(huì)被html-webpack-plugin處理。

src/views

vue cli 3的src文件夾中新增了views文件夾用于存放頁面,用于區(qū)分components組件。

環(huán)境配置.env

項(xiàng)目中通常包含多種模式,常見比如開發(fā)模式development、生產(chǎn)模式production等,開發(fā)中會(huì)根據(jù)環(huán)境變量process.env.NODE_ENV進(jìn)行區(qū)分。

在根目錄下創(chuàng)建.env.production生產(chǎn)環(huán)境配置和.env.development開發(fā)環(huán)境配置,配置文件以鍵值對的方式,配置項(xiàng)必須以VUE_APP_以前綴。NODE_ENVBASE_URL是兩個(gè)特殊變量,在代碼中始終可用。

$ vim .env.development
BASE_URL = http://127.0.0.1:8080
VUE_APP_API_URL = http://127.0.0.1:4000
VUE_APP_WX_APPID = wx6fe244f7d2197mc1

加載環(huán)境配置文件

vue會(huì)根據(jù)啟動(dòng)命令啟動(dòng)加載對應(yīng)的環(huán)境文件,這是因?yàn)関ue是根據(jù)文件名進(jìn)行加載的。

  • npm run serve 運(yùn)行服務(wù)會(huì)自動(dòng)加載 .env.development 開發(fā)環(huán)境配置文件
  • npm run build 運(yùn)行構(gòu)建會(huì)自動(dòng)加載 .env.production 生產(chǎn)環(huán)境配置文件

運(yùn)行npm run serve啟動(dòng)服務(wù)命令時(shí),若在vue.config.js核心中配置了devServer開發(fā)服務(wù)器選項(xiàng)的proxy代理設(shè)置后,開發(fā)環(huán)境中會(huì)使用proxy代理服務(wù)器訪問接口數(shù)據(jù)。但正式生產(chǎn)環(huán)境下此選項(xiàng)會(huì)失效。因?yàn)榇藭r(shí)vue會(huì)讀取.env.production環(huán)境配置,而忽略vue.config.js中的devServer選項(xiàng)。

環(huán)境配置自定義

通過在package.jsonscripts配置項(xiàng)中添加 --mode xxx來選擇不同環(huán)境。

$ vim package.json
"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "test:unit": "vue-cli-service test:unit",
  "lint": "vue-cli-service lint"
}
"scripts": {
  "serve": "vue-cli-service serve --mode development",
  "build": "vue-cli-service build --mode development",
  "test:unit": "vue-cli-service test:unit --mode development",
  "lint": "vue-cli-service lint --mode development"
},

項(xiàng)目配置vue.config.js

vue.config.js是一個(gè)可選的配置文件,若項(xiàng)目根目錄中存在此文件,則會(huì)被@vue/cli-service自動(dòng)加載。

vue-cli 3.x 創(chuàng)建的目錄下看不到WebPack配置。手工配置webpack可在根目錄下創(chuàng)建vue.config.js文件。在根目錄下創(chuàng)建vue.config.js文件作為Vue項(xiàng)目配置文件,其中配置輸出路徑名、根目錄、預(yù)處理、devServer配置、PWA、DLL、第三方插件等。

$ vim vue.config.js
module.exports = {
    configureWebpack:config=>{
        if(process.env.NODE_ENV === "production"){

        }else{
            
        }

    }
};

配置選項(xiàng)

選項(xiàng) 描述
publicPath 部署應(yīng)用寶的基本URL,和webpack的output.publicPath一致。
outputDir 運(yùn)行vue-cli-service build時(shí)生成的生產(chǎn)環(huán)境構(gòu)建文件的目錄,目標(biāo)目錄在夠堅(jiān)強(qiáng)會(huì)被清除。
assetsDir 靜態(tài)資源目錄
indexPath 指定生成的index.html的輸出路徑
filenameHashing 是否在生成的靜態(tài)資源文件名中包含hash以控制緩存
pages 在多頁模式下構(gòu)建應(yīng)用,每個(gè)頁面對應(yīng)一個(gè)入口文件。
lintOnSave 是否在開發(fā)環(huán)境下通過eslint-loader在每次保存時(shí)lint代碼
runtimeCompiler 是否使用包含運(yùn)行時(shí)編譯器的vue構(gòu)建版本

CSS Pre-processors

VUE CLI支持CSS Modules、PostCSS和SASS、LESS、Stylus在內(nèi)的預(yù)處理器。所有編譯后的CSS會(huì)通過 css-loader 來解析其中的url()引用,并將應(yīng)用作為模塊請求來處理。這意味著可以根據(jù)本地文件結(jié)構(gòu)使用相對路徑引用靜態(tài)資源。若要應(yīng)用NPM以來中的文件,或使用webpack alias,則需在路徑前添加 ~ 前綴來避免歧義。

TypeScript

安裝TypeScript

$ npm i -S typescript
$ npm i -S @vue/cli-plugin-typescript

配置TypeScript

若目錄下存在tsconfig.json文件則意味著該目錄是TypeScript項(xiàng)目的根目錄,tsconfig.json文件中指定了用來編譯項(xiàng)目的根文件和編譯選項(xiàng)。項(xiàng)目可使用tsconfig.json來編譯。

  • 當(dāng)不帶任何輸出文件的情況下調(diào)用tsc文件,編譯器會(huì)從當(dāng)前目錄開始查找tsconfig.json文件,并逐級(jí)向上搜索父級(jí)目錄。
  • 當(dāng)不帶任何輸出文件時(shí)調(diào)用tsc文件且使用命令行參數(shù)--project-p指定一個(gè)包含tsconfig.json文件的目錄。
  • 當(dāng)在命令行上指定了輸入文件時(shí),tsconfig.json文件會(huì)被忽略。

根目錄下創(chuàng)建tsconfig.json,默認(rèn)情況下typescript只負(fù)責(zé)靜態(tài)檢查,即使遇到錯(cuò)誤也僅僅在編譯時(shí)報(bào)錯(cuò)并不會(huì)中斷編譯,最終還是會(huì)生成一份JS文件,如果想要在報(bào)錯(cuò)時(shí)終止JS文件的生成,可在tsconfig.json配置中設(shè)置noEmitOnError選項(xiàng)為true。

$ vim tsconfig.json
{
  //編譯選項(xiàng)
  "compilerOptions": {
    //編譯目標(biāo)版本
    "target": "esnext",
    //指定模塊系統(tǒng)
    "module": "esnext",
    //是否啟用嚴(yán)格類型檢查
    "strict": true,
    //在.tsx文件中支持JSX
    "jsx": "preserve",
    //從tslib導(dǎo)入輔助工具函數(shù)
    "importHelpers": true,
    //模塊處理方式,默認(rèn)classic
    "moduleResolution": "node",
    //是否啟用實(shí)驗(yàn)性的ES裝飾器
    "experimentalDecorators": true,
    //報(bào)錯(cuò)時(shí)不生成輸出文件
    "noEmitOnError":true,
    //通過為所有導(dǎo)入創(chuàng)建名稱空間對象,支持CommonJS和ES模塊之間的互操作性。意味著allowSyntheticDefaultImports。
    "esModuleInterop": true,
    //是否允許從沒有設(shè)置默認(rèn)導(dǎo)出的模塊中默認(rèn)導(dǎo)入,僅用于類型檢查。
    "allowSyntheticDefaultImports": true,
    //是否生成map文件
    "sourceMap": true,
    //工作根目錄
    "baseUrl": ".",
    //指定引入的類型聲明文件,默認(rèn)自動(dòng)引入所有聲明文件,一旦指定則會(huì)禁用自動(dòng)引入,只引入指定的類型。
    "types": [
      "webpack-env",
      "mocha",
      "chai"
    ],
    //指定模塊的路徑,和baseUrl有關(guān)聯(lián),和webpack中resolve.alias配置一樣。
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    //編譯過程中需引入的庫文件列表
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  //指定匹配列表,屬于自動(dòng)指定該路徑下所有TS相關(guān)文件。
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  //指定排除列表,include的反向操作。
  "exclude": [
    "node_modules"
  ]
}

錯(cuò)誤處理

$ npm run serve

> sxyh_web_stats@0.1.0 serve D:\vue\workspace\sxyh_web_stats
> vue-cli-service serve

 INFO  Starting development server...
 ERROR  WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.entry[2] should be a string.
   -> A non-empty string
WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.entry[2] should be a string.
   -> A non-empty string

例如:針對多頁應(yīng)用的項(xiàng)目配置

$ vim vue.config.js
const path = require("path");
const fs = require("fs");
// const glob = require("glob");
const pxtoviewport = require("postcss-px-to-viewport");

//是否開發(fā)調(diào)試模式
const debug = process.env.NODE_ENV === "development" ? true : false;

//獲取文件路徑
const joinPath = (...args)=>path.join(__dirname, ...args);

/*獲取配置*/
const config = (filename,field="")=>{
    let value = require(joinPath("config", filename));
    if(field!==""){
        value = value[field];
    }
    return value;
};

/*獲取多頁面配置選項(xiàng)*/
const getPages = ()=>{
    let pages = {};
    //獲取pages目錄下所有文件夾,即每個(gè)單頁。
    fs.readdirSync(joinPath("src", "pages")).forEach(dirname=>{
        //生成應(yīng)用組件文件
        const app  = joinPath("src", "pages", dirname, "App.vue");
        if(!fs.existsSync(app)){
            //todo 讀取模板內(nèi)容 替換內(nèi)容后寫入
            let code = `
<template>
    <router-view/>
</template>

<script>
    export default {
        name:"app"
    }
</script>

<style scoped>

</style>
`;
            fs.writeFileSync(app, code);
        }
        //生成路由文件
        const router = joinPath("src", "pages", dirname, "router.js");
        if(!fs.existsSync(router)){
            let code = `
import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

export default new Router({routes:[

]});
`;
            fs.writeFileSync(router, code);
        }
        //生成入口文件
        const entry = joinPath("src", "pages", dirname, "main.js");
        if(!fs.existsSync(entry)){
            let code = `
import Vue from "vue";
import Axios from "axios";

import App from "./App.vue";
import router from "./router.js";

Vue.config.productionTip = false;
Vue.prototype.axios = Axios;

new Vue({render:h=>h(App), router}).$mount("#${dirname}");
`;
            fs.writeFileSync(entry, code);
        }
        //單頁配置選項(xiàng)
        const template = "index.html";
        const filename = `${dirname}.html`;
        const chunks = ['chunk-vendors', 'chunk-common', dirname];
        const chunksSortMode = "manual";
        const minify = false;
        const inject = true;
        //自定義頁面數(shù)據(jù)
        const pageData = config("page", dirname) || {};
        if(pageData.title === undefined){
            Object.assign(pageData, {title:dirname});
        }
        if(pageData.idname === undefined){
            Object.assign(pageData, {idname:dirname});
        }
        pages[dirname] = {entry, template, filename, pageData, chunks, chunksSortMode, minify, inject};
    });
    return pages;
};


module.exports = {
    publicPath:debug?"/":"",
    outputDir:"dist",
    assetsDir:"assets",
    filenameHashing:true,
    lintOnSave:!debug,
    runtimeCompiler:!debug,
    pages:getPages(),
    configureWebpack:config=>{
        const extensions = [".js", ".json", ".vue", ".css"];
        const alias = {
            "@":path.join(__dirname, "src"),
            "src":path.join(__dirname, "../src"),
            "assets":path.join(__dirname, "../src/assets"),
            "components":path.join(__dirname, "../src/components")
        };
        config.resolve = {extensions, alias};
    },
    css:{
        loaderOptions:{
            postcss:{
                plugins:[
                    pxtoviewport({
                        unitToConvert:"px",
                        unitPrecision:3,
                        viewportWidth:750,
                        viewportUnit:"vw",
                        fontViewportUnit:"vw",
                        minPixelValue:1,
                        mediaQuery:false,
                        replace:true,
                        propList:["*"],
                        selectorBlackList:[],
                        exclude:/(\/|\\)(node_modules)(\/|\\)/,
                        landscape:false,
                        landscapeUnit:"vh",
                        landscapeWidth:1334
                    })
                ]
            }
        }
    },
    //開發(fā)服務(wù)器
    devServer:{
        //設(shè)置代理
        proxy:{
            "/api":{
                target:"http://127.0.0.1:4000",
                ws:false,
                changeOrigin:true
            }
        }
    }
};

啟動(dòng)入口

Vue2實(shí)例啟動(dòng)入口文件默認(rèn)為main.js

$ vim src/pages/index/main.js
import Vue from 'vue';
import Axios  from "axios";

import App from './App.vue';
import router from "./router.js";

Vue.config.productionTip = false;

Vue.prototype.axios = Axios;
Vue.prototype.apiUrl = process.env.VUE_APP_API_URL;
Vue.prototype.debug = process.env.NODE_ENV === "development";


//創(chuàng)建vue應(yīng)用實(shí)例并掛在到#index元素上
const vm = new Vue({render:h=>h(App), router:router});//未掛載狀態(tài)
//手工掛載vm實(shí)例
vm.$mount('#index');

這里運(yùn)用了Vue2新增的Render方法,為了得到更好地運(yùn)行速度,Vue2也采用了Virtual DOM虛擬DOM技術(shù)。Virtual DOM是一種比瀏覽器原生DOM性能更好的虛擬組件模型。

const vm = new Vue({render:h=>h(App), router:router});//未掛載狀態(tài)

通過import將Vue.js文件引入后創(chuàng)建Vue實(shí)例對象,在Vue實(shí)例中使用Render方法來繪制App這個(gè)Vue組件以完成初始化。

vm.$mount('#index');//手工掛載vm實(shí)例

將Vue實(shí)例綁定到頁面中ID為index的元素上,這樣App Vue程序就引導(dǎo)成功了。

一個(gè)Vue實(shí)例必須與一個(gè)頁面元素綁定,Vue實(shí)例一般用作Vue的全局配置來使用。

$ vim public/index.html
<% const page = htmlWebpackPlugin.options.pageData; %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <!-- 在 head 標(biāo)簽中添加 meta 標(biāo)簽,并設(shè)置 viewport-fit=cover 值 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
    <!-- 開啟 safe-area-inset-bottom 屬性 -->
    <van-number-keyboard safe-area-inset-bottom />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <meta http-equiv="Cache-Control" content="no-cache" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
    <title><%= page.title %></title>
    <style>
        body{
            margin: 0;
            overflow-x: auto;
            color: #323233;
            font-size: 16px;
            font-family: PingFang SC, 'Helvetica Neue', Arial, sans-serif;
            background-color: #f7f8fa;
            -webkit-font-smoothing: antialiased;
        }
    </style>
</head>
<body>
<noscript>
    <strong>很抱歉,如果沒有啟用javascript,vue-cli3無法正常工作。請啟用它以繼續(xù)。</strong>
</noscript>
<div id="app">
    <div id="<%= page.idname %>"></div>
</div>
</body>
</html>

單頁組件

Vue2默認(rèn)Vue組件文件為App.vue,*.vue是Vue特色的文件格式表示是一個(gè)Vue組件,是Vue特色又被稱為單頁式組件。*.vue文件同時(shí)承載視圖模板、樣式定義和組件代碼。

$ vim src/pages/index/App.vue
<template>
    <router-view/>
</template>

<script>
    export default {
        name: "app",
        components:{},
        data(){
            return {
            };
        },
        created(){
            //console.log(this.$route);
        },
        methods:{
        }
    }
</script>

<style scoped>
</style>

Vue的組件系統(tǒng)提供了一種抽象,使用獨(dú)立可復(fù)用的組件來構(gòu)建大型應(yīng)用。因此,幾乎任意類型應(yīng)用的界面都可以抽象為一個(gè)組件樹。

單頁組件由三部分組成

  • <template> 視圖模板
  • <script> 組件定義
  • <style> 組件樣式表
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容