Vite-Vue3.x-TS-Eslint項(xiàng)目初始化(2022-05-02)

Vite-Vue3.x-TS-Eslint項(xiàng)目初始化

Lzq811/Vue3.x-vite-ts-eslint-prettier: vue3大屏基礎(chǔ)框架 (github.com)

1. init

yarn create vite demo-product --template vue-ts
cd ./demo-product
yarn
yarn dev
# 能正常方法 localhost:3000 頁(yè)面,說(shuō)明 init 成功

2. 使用 element-plus UI 庫(kù)

yarn add element-plus
  • 推薦使用 按需引入 文檔地址

    # 需要安裝下面兩個(gè)依賴
    yarn add unplugin-vue-component unplugin-auto-import
    
  • 然后再 vite.config.ts 文件中修改

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import AutoImport from 'unplugin-auto-import/vite'
    import Component from 'unplugin-vue-components/vite'
    import {ElementPlusResolver } from 'unplugin-vue-components/resolvers'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [
        vue(),
        AutoImport({
          resolvers: [ElementPlusResolver()]
        }),
        Component({
          resolvers: [ElementPlusResolver()]
        })
      ]
    })
    
    
  • 然后在使用的組件中直接調(diào)用

    <el-button type="primary">hello element btn</el-button>
    
  • 自定義主題 文檔地址

  • 使用 Less

    # 安裝依賴
    yarn add less less-loader -D
    # 然后vite.config.js, 要require('path'), 如果require 和 __dirname報(bào)ts錯(cuò), 使用 @ts-ignore 或者安裝 @types/node 依賴
    css: {
        preprocessorOptions: {
          less: {
            modifyVars: {
              hack: `true; @import (reference) "${path.resolve(__dirname, 'src/assets/base.less')}"` // 全局定義的less文件
            },
            javascriptEnabled: true
          }
        }
      }
      
     # 在組件內(nèi)使用
     <style lang="less" scoped></style>
    

3. 使用 Eslint 、 Prettier 做代碼校驗(yàn)和自動(dòng)格式化

  • 安裝 eslint 以及相關(guān)依賴

    yarn add eslint eslint-plugin-vue vue-eslint-parser @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-airbnb-base eslint-plugin-import -D
    
  • vscode 編輯器 也要安裝 Eslint 和 Prettier 拓展

  • 根目錄添加 .eslintrc.js文件,并添加下面代碼

    module.exports = {
      root: true,
      globals: {
          defineEmits: 'readonly',
          defineProps: 'readonly'
      },
      extends: [
          'plugin:@typescript-eslint/recommended',
          'plugin:vue/vue3-recommended',
          'airbnb-base'
      ],
      parserOptions: {
          parser: '@typescript-eslint/parser',
          ecmaVersion: 2020
      },
      rules: {
          'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用 debugger
          'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 禁用 console
          'no-bitwise': 'off', // 禁用按位運(yùn)算符
          'no-tabs': 'off', // 禁用 tab
          'array-element-newline': ['error', 'consistent'], // 強(qiáng)制數(shù)組元素間出現(xiàn)換行
          indent: [
              'error',
              2,
              { MemberExpression: 0, SwitchCase: 1, ignoredNodes: ['TemplateLiteral'] }
          ], // 強(qiáng)制使用一致的縮進(jìn)
          quotes: ['error', 'single'], // 強(qiáng)制使用一致的反勾號(hào)、雙引號(hào)或單引號(hào)
          'comma-dangle': ['error', 'always-multiline'], // 要求或禁止末尾逗號(hào)
          'object-curly-spacing': ['error', 'always'], // 強(qiáng)制在大括號(hào)中使用一致的空格
          'max-len': ['error', 120], // 強(qiáng)制一行的最大長(zhǎng)度
          'no-new': 'off', // 禁止使用 new 以避免產(chǎn)生副作用
          'linebreak-style': 'off', // 強(qiáng)制使用一致的換行風(fēng)格
          'import/extensions': 'off', // 確保在導(dǎo)入路徑中統(tǒng)一使用文件擴(kuò)展名
          'eol-last': 'off', // 要求或禁止文件末尾存在空行
          'no-shadow': 'off', // 禁止變量聲明與外層作用域的變量同名
          'no-unused-vars': 'warn', // 禁止出現(xiàn)未使用過(guò)的變量
          'import/no-cycle': 'off', // 禁止一個(gè)模塊導(dǎo)入一個(gè)有依賴路徑的模塊回到自己身上
          'arrow-parens': 'off', // 要求箭頭函數(shù)的參數(shù)使用圓括號(hào)
          semi: ['error', 'never'], // 要求或禁止使用分號(hào)代替 ASI
          eqeqeq: 'on', // 要求使用 === 和 !==
          'no-param-reassign': 'off', // 禁止對(duì) function 的參數(shù)進(jìn)行重新賦值
          'import/prefer-default-export': 'off', // 如果模塊只輸入一個(gè)名字,則傾向于默認(rèn)輸出
          'no-use-before-define': 'on', // 禁止在變量定義之前使用它們,則傾向于默認(rèn)輸出
          'no-continue': 'off', // 禁用 continue 語(yǔ)句
          'prefer-destructuring': 'off', // 優(yōu)先使用數(shù)組和對(duì)象解構(gòu)
          'no-plusplus': 'off', // 禁用一元操作符 ++ 和 --
          'prefer-const': 'warn', // 要求使用 const 聲明那些聲明后不再被修改的變量
          'global-require': 'on', // 要求 require() 出現(xiàn)在頂層模塊作用域中
          'no-prototype-builtins': 'off', // 禁止直接調(diào)用 Object.prototypes 的內(nèi)置屬性
          'consistent-return': 'off', // 要求 return 語(yǔ)句要么總是指定返回的值,要么不指定
          'one-var-declaration-per-line': 'off', // 要求或禁止在變量聲明周?chē)鷵Q行
          'one-var': 'off', // 強(qiáng)制函數(shù)中的變量要么一起聲明要么分開(kāi)聲明
          'import/named': 'off', // 確保命名導(dǎo)入與遠(yuǎn)程文件中的命名導(dǎo)出相對(duì)應(yīng)
          'object-curly-newline': 'off', // 強(qiáng)制大括號(hào)內(nèi)換行符的一致性
          'default-case': 'off', // 要求 switch 語(yǔ)句中有 default 分支
          'no-trailing-spaces': 'on', // 禁用行尾空格
          'func-names': 'off', // 要求或禁止使用命名的 function 表達(dá)式
          radix: 'off', // 強(qiáng)制在 parseInt() 使用基數(shù)參數(shù)
          'no-unused-expressions': 'off', // 禁止出現(xiàn)未使用過(guò)的表達(dá)式
          'no-underscore-dangle': 'off', // 禁止標(biāo)識(shí)符中有懸空下劃線
          'no-nested-ternary': 'off', // 禁用嵌套的三元表達(dá)式
          'no-restricted-syntax': 'off', // 禁用特定的語(yǔ)法
          'no-await-in-loop': 'off', // 禁止在循環(huán)中出現(xiàn) await
          'import/no-extraneous-dependencies': 'off', // 禁止使用外部包
          'import/no-unresolved': 'off', // 確保導(dǎo)入指向一個(gè)可以解析的文件/模塊
          'template-curly-spacing': ['error', 'always'], // 要求或禁止模板字符串中的嵌入表達(dá)式周?chē)崭竦氖褂?      '@typescript-eslint/no-var-requires': 'off', // 除import語(yǔ)句外,禁止使用require語(yǔ)句
          '@typescript-eslint/no-empty-function': 'off', // 不允許空函數(shù)
          '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 類(lèi)型
          'guard-for-in': 'off', // 要求 for-in 循環(huán)中有一個(gè) if 語(yǔ)句
          'class-methods-use-this': 'off', // 強(qiáng)制類(lèi)方法使用 this
          'vue/html-indent': ['error', 2], // 在<template>中強(qiáng)制一致縮進(jìn)
          'vue/html-self-closing': 'off', // 執(zhí)行自閉合的風(fēng)格
          'vue/max-attributes-per-line': [
              // 強(qiáng)制每行屬性的最大數(shù)量
              'warn',
              {
                  singleline: {
                      max: 3,
                      allowFirstLine: true
                  },
                  multiline: {
                      max: 1,
                      allowFirstLine: false
                  }
              }
          ],
          'vue/singleline-html-element-content-newline': 'off' // 要求單行元素的內(nèi)容前后有一個(gè)換行符
      }
    }
    
    
  • 根目錄添加 prettier.config.js文件,并添加下面代碼

    // prettier.config.js or .prettierrc.js
    module.exports = {
      // 一行最多 100 字符
      printWidth: 100,
      // 使用 2 個(gè)空格縮進(jìn)
      tabWidth: 2,
      // 不使用縮進(jìn)符,而使用空格
      useTabs: false,
      // 行尾需要有分號(hào)
      semi: false,
      // 使用單引號(hào)
      singleQuote: true,
      // 對(duì)象的 key 僅在必要時(shí)用引號(hào)
      quoteProps: 'as-needed',
      // jsx 不使用單引號(hào),而使用雙引號(hào)
      jsxSingleQuote: false,
      // 末尾不需要逗號(hào)
      trailingComma: 'none',
      // 大括號(hào)內(nèi)的首尾需要空格
      bracketSpacing: true,
      // jsx 標(biāo)簽的反尖括號(hào)需要換行
      jsxBracketSameLine: false,
      // 箭頭函數(shù),只有一個(gè)參數(shù)的時(shí)候,也需要括號(hào)
      arrowParens: 'always',
      // 每個(gè)文件格式化的范圍是文件的全部?jī)?nèi)容
      rangeStart: 0,
      rangeEnd: Infinity,
      // 不需要寫(xiě)文件開(kāi)頭的 @prettier
      requirePragma: false,
      // 不需要自動(dòng)在文件開(kāi)頭插入 @prettier
      insertPragma: false,
      // 使用默認(rèn)的折行標(biāo)準(zhǔn)
      proseWrap: 'preserve',
      // 根據(jù)顯示樣式?jīng)Q定 html 要不要折行
      htmlWhitespaceSensitivity: 'css',
      // 換行符使用 lf
      endOfLine: 'lf'
    }
    
    
  • 根目錄 添加 .eslintignore 并寫(xiě)入下面代碼

    /build/
    /config/
    /dist/
    /*.js
    /*.zip
    /*.rar
    
    

4. 配置環(huán)境變量

  • 在根目錄新建文件夾 env-config,然后在文件夾下新增文件并錄入內(nèi)容

    所有的環(huán)境變量必須以 VITE_ 開(kāi)頭

    # 新增 .env 文件 寫(xiě)入下面內(nèi)容
      VITE_ENV = DEV
      VITE_APP_BASE_URL = 'http://DEV.com'
      
    # 新增 .env.test 文件并寫(xiě)入內(nèi)容
      VITE_ENV = TEST
      VITE_APP_BASE_URL = 'http://TEST.com'
      
    # 新增 .env.prod 文件并寫(xiě)入內(nèi)容
      VITE_ENV = PROD
      VITE_APP_BASE_URL = 'http://PROD.com'
    
  • vite.config.js文件夾中配置 envDir

    // @ts-ignore 如果提示錯(cuò)誤 使用 @ts-ignore 或者 yarn add @types/node 只有node里面才有 require 和 __dirname
    const path = require('path')
    function _resolve(dir) {
      // @ts-ignore
      return path.resolve(__dirname, dir)
    }
    
    // https://vitejs.dev/config/
    export default defineConfig({
      envDir: _resolve('env-config'),
      ...
    })
    
  • 修改 package.json 的命令(我比較喜歡用 start 代替 dev)

      "scripts": {
        "dev": "vite",
        "start": "vite --mode env",
        "start-test": "vite --mode test",
        "start-prod": "vite --mode prod",
        "build": "vue-tsc --noEmit && vite build",
        "build-test": "vue-tsc --noEmit && vite build --mode test",
        "build-prod": "vue-tsc --noEmit && vite build --mode prod",
        "preview": "vite preview"
      },
    
  • 使用 import.meta.env 來(lái)獲取環(huán)境變量信息

    # 組件里面調(diào)用測(cè)試
    onMounted(() => {console.log(import.meta.env)})
    
  • 執(zhí)行start命令

    yarn start # 執(zhí)行 dev 環(huán)境
    # OR
    yarn start-test # 執(zhí)行 test 環(huán)境
    # OR
    yarn start-prod # 執(zhí)行 orod 環(huán)境
    
    #demo
    yarn start-test
    # 調(diào)取 import.meta.env 的結(jié)果
      BASE_URL: "/"
      DEV: true
      MODE: "test"
      PROD: false
      VITE_APP_BASE_URL: "http://TEST.com"
      VITE_ENV: "TEST"
    
  • 執(zhí)行build命令

    #demo
    yarn build-test
    # 調(diào)取 import.meta.env 的結(jié)果
      BASE_URL: "/"
      DEV: true
      MODE: "test"
      PROD: false
      VITE_APP_BASE_URL: "http://TEST.com"
      VITE_ENV: "TEST"
    

5. 使用 axios 封裝 ajax 請(qǐng)求

  • 安裝 axios

    yarn add axios
    
  • 配置封裝

    1. 新建文件src/api/index.tsx
    // index.tsx 文件
    import ajax from './ajax'
    /*
     * ajax 從 ajax.js 引入 需要
     * 第一個(gè) 參數(shù) 是 url 必填
     * 第二個(gè) 參數(shù) 是 params對(duì)象 默認(rèn) {} 非必填
     * 第三個(gè) 參數(shù) 是 GET、POST 請(qǐng)求方式, 默認(rèn) POST, 非必填
     */
    // 后臺(tái)地址
    const BASE_URL: string = import.meta.env.VITE_APP_BASE_URL || '' // 環(huán)境變量后臺(tái)地址
    // const BASE_URL: string = `http:xxxx/api`
    // const BASE_URL_OTHER:string = `http:xxx2.api` // 多個(gè)后臺(tái)地址
    
    interface IParams {}
    
    // 登陸接口
    export const ReqLogin = (params: IParams) => ajax(`${BASE_URL}login`, params, 'POST') // POST 是默認(rèn)值,可以不寫(xiě)
    
    // export const ReqOther = (params:IParams) => ajax(`${BASE_URL_OTHER}login`, params)
    
    
  1. 新建文件 src/api/ajax.tsx

    // ajax.tsx 文件
    import axios from 'axios'
    
    // 可以在這里做一下請(qǐng)求攔截,設(shè)置公共請(qǐng)求頭等
    
    export default function ajax(url: string, data: any = {}, type: string = 'POST') {
      // 判斷 url 地址, 在多個(gè)后臺(tái)地址時(shí)候使用, 可以在這里攔截使用不同的請(qǐng)求頭,傳入不同token等操作
    
      return new Promise((resolve, reject) => {
        let promise: any // 返回一個(gè) promise 對(duì)象
        if (type === 'GET') {
          promise = axios.get(url, { params: data })
    
          // 多個(gè)后臺(tái)地址時(shí)候,傳入不同的token值
          promise = axios.get(url, {
            params: data,
            headers: { access_totken: sessionStorage.getItem('token_other') || '' }
          })
        } else if (type === 'POST') {
          promise = axios.post(url, data)
    
          // 多個(gè)后臺(tái)地址時(shí)候,傳入不同的token值
          promise = axios.get(url, data)
        }
        // 統(tǒng)一處理 response
        promise
          .then((response: any) => {
            response && response.data ? resolve(response.data) : reject(response)
          })
          .catch((error: any) => {
            console.log(error)
          })
      })
    }
    
    
  2. 組件內(nèi)調(diào)用

 ```tsx
 import {ReqLogin} from './src/api'
 
 const ajaxDemo = async () => {
    const res:any = await ReqLogin({}) // res就是ajax返回的結(jié)果
 }
 ```

6. 頁(yè)面彈性布局

  • 新建 src/utils/comfort_page.tsx

    /*
     * 做頁(yè)面自適應(yīng)
     * 0. 項(xiàng)目跟元素 id = root
     * 1. width 為適應(yīng)基準(zhǔn)
     * 2. 無(wú)論 width height 如何變化,都要輸出 16 / 9 比例的頁(yè)面
     * 3. 客戶的設(shè)備分辨率 1920 * 1080
     */
    
    // @ts-nocheck
    
    const W = 1920
    const H = 1080
    
    export default () => {
      const root = document.getElementById('root')?.style
      window.onresize = () => {
        root.transform = `scale(${document.body.offsetWidth / W})`
        root.transformOrigin = `left top 0px`
        root.width = `${W}px`
        root.height = `${H}px`
      }
      root.transform = `scale(${document.body.offsetWidth / W})`
      root.transformOrigin = `left top 0px`
      root.width = `${W}px`
      root.height = `${H}px`
    }
    
    
  • App.vue 組件引入

    import ComfortPage from './utils/comfort_page'
    onMounted(() => {
      ComfortPage()
    })
    

7. 路由

  • 路由要用 4 版本的,才對(duì)應(yīng) vue3版本

    yarn add vue-router@4
    
  • 新增 src/routes/index.tsx

    import { createRouter, createWebHistory } from 'vue-router'
    
    const routes: any = [
      {
        path: '/',
        redirect: 'home'
      },
      {
        path: '/home',
        name: 'home',
        component: () => import('../Home.vue') // 要提前注冊(cè)號(hào)該組件
      },
      {
        path: '/first',
        name: 'first',
        component: () => import('../First.vue') // 要提前注冊(cè)號(hào)該組件
      }
    ]
    
    const router = createRouter({
      history: createWebHistory(),
      routes: routes
    })
    
    router.beforeEach((to, from) => {
      const { path: toPath } = to
      const { path: fromPath } = from
      if (toPath === fromPath) {
        return false
      }
    })
    
    export default router
    
    
  • 修改 main.ts 文件

    import router from './routes'
    
    const app = createApp(App)
    app.use(router)
    app.mount('#app')
    
  • 修改 App.vue 文件

    <template>
        <router-view></router-view>
    </template>
    
  • 跳轉(zhuǎn)

    import {useRouter} from 'vue-router'
    
    const router = useRouter()
    
    router.push('./first')
    

8. 路徑別名

  • 修改 vite.config.js 內(nèi)容

    export default defineConfig({
      envDir: path.resolve(__dirname, 'env-config'),
      plugins: [
        vue(),
        AutoImport({
          resolvers: [ElementPlusResolver()]
        }),
        Component({
          resolvers: [ElementPlusResolver()]
        })
      ],
      css: {
        preprocessorOptions: {
          less: {
            modifyVars: {
              hack: `true; @import (reference) "${path.resolve(__dirname, 'src/assets/base.less')}"` // 全局定義的less文件
            },
            javascriptEnabled: true
          }
        }
      },
      resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          '@api': _resolve('src/api'),
          '@components': _resolve('src/components'),
          '@': _resolve('src')
        }
      }
    })
    
  • 新增 src/ts.extends.json 文件

    {
      "compilerOptions": {
        "baseUrl": ".",
        "paths": {
          "@/*": [
            "*"
          ],
          "@api/*": [
            "src/api/*"
          ]
        }
      }
    }
    
  • 修改 tsconfig.json 文件

    {
      ...
      "extends": "./ts.extends.json" # 添加該屬性
    }
    
  • 使用

    import { ReqLogin } from '@api/index'
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容