Vite 搭建 Vue3 项目

VueCli和Vite

构建项目

  • VueCli
    Vue CLI 4.x 需要 Node.js v8.9 或更高版本 (推荐 v10 以上)

    npm install -g @vue/cli
    # OR
    yarn global add @vue/cli
    
    vue --version   查看vue-cli版本
    
    vue create [projectName]  通过vue-cli创建项目
    
    
  • Vite
    Vite 需要 Node.js 版本 14.18+,16+

    npm create vite@latest
    

Vite路由

配置路由

npm install vue-router@next -S 安装到生产环境
or
npm install vue-router@4
or 
yarn add vue-router@4

src 新建 router/index.js

import { createRouter, createWebHistory } from 'vue-router'
// 还有 createWebHashHistory 和 createMemoryHistory

createRouter({
  history: createWebHistory(),
  routes: [],
})

映射路由、渲染组件

import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/home',
    name: 'Home',
    component: () => import('../views/Home/index.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

新建src/views/Home/index.vue

<template>
  <div>这是Home组件</div>
</template>

src/App.vue 设置渲染区域

<script setup>
</script>

<template>
  <router-view></router-view>
</template>

<style scoped>
</style>

main.js 引入路由

import { createApp } from 'vue'
import App from './App.vue'
// 引入路由
import router from './router'

const app = createApp(App)
app.use(router).mount('#app')

Vite Vuex

安装vuex

npm install vuex@next --S  安装到生产环境
or
yarn add vuex

main.js 引入路由

import { createApp } from 'vue'
import App from './App.vue'
// 引入路由
import router from './router'

+  // 引入store
+  import store from './store'

const app = createApp(App)
-  app.use(router).mount('#app')
M  app.use(router).use(store).mount('#app')

新建store文件,src/store/index.js

import { createStore } from 'vuex'

const store = createStore({
  state () {
    return { }
  },
 mutations: {},
 getters:{},
 actions:{},
 modules:{}
})

export default store

Vuex的基础知识


数据主要存在State中

  • 组件直接调用Actions,Actions再去调用Mutations,Mutations再去修改State
  • 或者组件直接调用Mutations,Mutations再去修改State
  • 要更改 state 必须通过 Mutations 去做更新

定义number,通过 Mutations 去更新,src/store/index.js

import { createStore } from 'vuex'

const store = createStore({
  state () {
    return {
+     number: 0
    }
  },
 mutations: {
+  UPDATE_NUMBER (state, value) {
+    state.number = value
+  }
 },
 getters:{},
 actions:{},
 modules:{}
})

export default store

使用mutations(commit): src/views/Home/index.vue

<template>
  <div>这是Home组件</div>
+ <div>这是Store的数据:{{number}}</div>
</template>
+ <script setup>
+   import { computed } from 'vue'
+   import { useStore } from 'vuex'

+   const store = useStore()

+   setTimeout(() => {
+    store.commit('UPDATE_NUMBER',50)
+   }, 2000)
+   const number = computed(() => store.state.number)
+ </script>

Vuex的Actions

  • mutations 是同步的
  • actions 是异步的

src/store/index.js

import { createStore } from 'vuex'

const store = createStore({
  state () {
    return {
     number: 0
    }
  },
+ getters:{},
+ // 同步
 mutations: {
+ // store.commit('UPDATE_NUMBER',50)
  UPDATE_NUMBER (state, value) {
    state.number = value
  }
 },
- getters:{},
 // 异步
 actions:{
+ // store.dispatch("NUMBERACTION",200)  调用
+ // 方法一:
+ // NUMBERACTION(context,payload){
+ // context.commit('UPDATE_NUMBER',payload)
+ // console.log(111,context.state.number) // 想获取state的数据
+ // }
+ // 方法二(拓展方式):
M NUMBERACTION({state,commit},payload){
M  commit('UPDATE_NUMBER',payload)
M  console.log(111,state.number) // 想获取state的数据
M }
 },
 modules:{}
})

export default store

使用actions(dispatch): src/views/Home/index.vue

<template>
  <div>这是Home组件</div>
  <div>这是Store的数据:{{number}}</div>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
const store = useStore()

setTimeout(() => {
M // store.commit('UPDATE_NUMBER',50)
+ store.dispatch('NUMBERACTION',200)
}, 2000)
const number = computed(() => store.state.number)
</script>

Vuex的Actions异步 Promise

import { createStore } from 'vuex'

const store = createStore({
  state () {
    return {
     number: 0
    }
  },
getters:{},
// 同步
 mutations: {
  UPDATE_NUMBER (state, value) {
    state.number = value
  }
 },
 // 异步
 actions:{
  NUMBERACTION({state,commit},payload){
+  return new Promise((resolve,reject)=>{
    commit('UPDATE_NUMBER',payload)
    console.log(111,state.number) // 想获取state的数据
+   resolve() // 成功回调
+   // reject()  // catch回调
+  })
  }
 },
 modules:{}
})

export default store

使用Promise:src/views/Home/index.vue

<template>
  <div>这是Home组件</div>
  <div>这是Store的数据:{{number}}</div>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

setTimeout(() => {
  // store.commit('UPDATE_NUMBER',50)
M  store.dispatch('NUMBERACTION',200).then(response => {
+    console.log(response)
+  }).catch((error)=>{
+    console.log(error)
+  })
}, 2000)
const number = computed(() => store.state.number)
</script>

Vuex的Getters 计算属性

import { createStore } from 'vuex'

const store = createStore({
  state () {
    return {
     number: 0
    }
  },
+ // 可以做一些计算属性,最终返回的是最新的结果,不会影响state里面数据
 getters:{
+  getNumber:(state) => {
+    return state.number + 10
+  }
 },
 // 同步
 mutations: {
  UPDATE_NUMBER (state, value) {
    state.number = value
  }
 },
 // 异步
 actions:{
  NUMBERACTION({state,commit},payload){
    return new Promise((resolve,reject)=>{
      commit('UPDATE_NUMBER',payload)
      console.log(111,state.number) // 想获取state的数据
      resolve() // 成功回调
      // reject()  // catch回调
    })
  }
 },
 modules:{}
})

export default store

使用Vuex的Getters

  • src/views/Home/index.vue
<template>
  <div>这是Home组件</div>
  <div>这是Store的数据:{{number}}</div>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

setTimeout(() => {
  // store.commit('UPDATE_NUMBER',50)
M // store.dispatch('NUMBERACTION',200).then(response => {
M //   console.log(response)
M // }).catch((error)=>{
M //  console.log(error)
M // })
+  const result = store.getters['getNumber']
+  console.log('result',result)
}, 2000)
const number = computed(() => store.state.number)
</script>

Vuex的Modules模块化
解决多业务模块在做state存储时,字段命名冲突

  • 新建store/modules/文件夹,并新建文件a.js,b.js:
a.js:
+ const state = {
+  name: 10
+ }
+ const getters = {}
+ const mutations = { 
+   UPDATE_NUMBER (state, value) {
+     state.number = value
+   }
+ }
+ const actions = {
+   NUMBERACTION (context, payload) {
+    return new Promise((resolve,reject)=>{
+      commit('UPDATE_NUMBER',payload)
+      console.log(111,state.number) // 想获取state的数据
+      resolve(1000) // 成功回调
+      // reject(1000)  // catch回调
+    })
+   }
+ }

+ export default {
+   namespaced: true, // 命名空间
+   state,
+   getters,
+   mutations,
+   actions
+ }
b.js:
+ const state = {
+  name: 20
+ }
+ const getters = {}
+ const mutations = { }
+ const actions = { }

+ export default {
+   namespaced: true, // 命名空间
+   state,
+   getters,
+   mutations,
+   actions
+ }
  • 在store/index.js下导入a.js,b.js:
import { createStore } from 'vuex'

+ import A from "./modules/a"
+ import B from "./modules/b"

const store = createStore({
-   state () {
-     return {
-      number: 0
-     }
-   },
-  // 可以做一些计算属性,最终返回的是最新的结果,不会影响state里面数据
-  getters:{
-   getNumber:(state) => {
-     return state.number + 10
-   }
-  },
-  // 同步
-  mutations: {
-   UPDATE_NUMBER (state, value) {
-     state.number = value
-   }
-  },
-  // 异步
-  actions:{
-   NUMBERACTION({state,commit},payload){
-     return new Promise((resolve,reject)=>{
-     commit('UPDATE_NUMBER',payload)
-     console.log(111,state.number) // 想获取state的数据
-      resolve() // 成功回调
-      // reject()  // catch回调
-     })
-   }
-  },
 modules:{
+  A,
+  B
 }
})

export default store

使用modules:src/views/Home/index.vue

<template>
  <div>这是Home组件</div>
  <div>这是Store的数据:{{number}}</div>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

setTimeout(() => {
+  store.commit('A/UPDATE_NUMBER',50)
  // store.commit('UPDATE_NUMBER',50)
M  store.dispatch('A/NUMBERACTION',200).then(response => {
M    console.log(response)
M  }).catch((error)=>{
M   console.log(error)
M  })
M  // const result = store.getters['getNumber']
M  // console.log('result',result)
}, 2000)
const number = computed(() => store.state.number)
</script>

Vite 配置 stylus

安装依赖

npm install -D stylus-loader stylus

新建stylus变量:src/assets/style/stylConfig.styl

+ $red = red

根目录新建vite.config.js

+ import { defineConfig } from 'vite'
+ import vue from '@vitejs/plugin-vue'
+ import path from 'path'

+ // https://vitejs.dev/config/
+ export default defineConfig(({ command, mode }) => {
+  return {
+    plugins: [vue()],
+    css: {
+     preprocessorOptions: {
+      stylus: {
+         imports: [path.resolve(__dirname, 'src/assets/style/stylConfig.styl')]
+       }
+     }
+   },
+  }
+ })

使用stylus:src/views/Home/index.vue

<template>
M <div class="red-home">这是Home组件</div>
  <div>这是Store的数据:{{number}}</div>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

const store = useStore()

setTimeout(() => {
  store.commit('A/UPDATE_NUMBER',50)
  // store.commit('UPDATE_NUMBER',50)
  store.dispatch('A/NUMBERACTION',200).then(response => {
    console.log(response)
  }).catch((error)=>{
   console.log(error)
  })
  // const result = store.getters['getNumber']
  // console.log('result',result)
}, 2000)

const number = computed(() => store.state.number)
</script>

+ <style lang="stylus">
+ .red-home
+   color $red
+ </style>

Vite配置路径别名

引入配置根目录vite.config.js:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [vue()],
    css: {
      preprocessorOptions: {
       stylus: {
         imports: [path.resolve(__dirname, 'src/assets/style/stylConfig.styl')]
        }
      }
     },
+    resolve: {
+      alias: {
+        '@': path.resolve(__dirname, 'src')
+      }
+    }
  }
})

Vite esLint

初始化esLint

// 安装
npm install eslint -D

// 初始化配置
npx eslint --init
// to check syntax, find problems, and enforce code style
// JavaScript modules (import/export)
// Vue.js
// No Use TypeScript
// Browser Node
// Use a popular style guide
// Standard
// JavaScript
// install them now? Yes
// use npm
// 执行完之后,会在根目录生成 .eslintrc.cjs 文件

自动生成的.eslintrc.cjs

+ module.exports = {
+   env: {
+     browser: true,
+     es2021: true,
+     node: true
+   },
+   extends: [
+     'standard',
+     'plugin:vue/vue3-essential'
+   ],
+   parserOptions: {
+     ecmaVersion: 'latest',
+     sourceType: 'module',
+     ecmaFeatyres: {
+       modules: true
+     },
+     requireConfigFile: false,
+     parser: '@babel/eslint-parser'
+   },
+   plugins: [
+     'vue'
+   ],
+   rules: {
+   }
+ }

自动格式化esLint

// 安装
npm install vite-plugin-eslint @babel/eslint-parser -D

配置vite.config.js文件

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
+ import eslintPlugin from 'vite-plugin-eslint'

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [
      vue(),
+     // 添加下面这块
+     eslintPlugin({
+       include: ['src/**/*.js', 'src/**/*.vue', 'src/*.js', 'src/*.vue']
+     })
    ],
    css: {
      preprocessorOptions: {
       stylus: {
         imports: [path.resolve(__dirname, 'src/assets/style/stylConfig.styl')]
        }
      }
     },
   resolve: {
     alias: {
       '@': path.resolve(__dirname, 'src')
     }
   }
  }
})

.eslintrc.cjs 添加规则

//  规则:http://eslint.cn/docs/rules/
+ module.exports = {
+   env: {
+     browser: true,
+     es2021: true,
+     node: true
+   },
+   extends: [
+     'standard',
+     'plugin:vue/vue3-essential'
+   ],
+   parserOptions: {
+     ecmaVersion: 'latest',
+     sourceType: 'module',
+     ecmaFeatyres: {
+       modules: true
+     },
+     requireConfigFile: false,
+     parser: '@babel/eslint-parser'
+   },
+   plugins: [
+     'vue'
+   ],
+   rules: {
+    semi: [2, 'never'], // 禁止尾部使用分号“;”
+    'no-var': 'error', // 禁止使用 var
+    indent: ['error', 2], // 缩进2格
+    'no-mixed-spaces-and-tabs': 'error', // 不能空格与tab混用
+    quotes: [2, 'single'], // 使用单引号
+    'vue/html-closing-bracket-newline': 'off', // 不强制换行,
+    'vue/singleline-html-element-content-newline': 'off', // 不强制换行
+    'vue/multi-word-component-names': 'off',
+    'vue/max-attributes-per-line': ['error', {
+      singleline: { max: 5 },
+      multiline: { max: 5 }
+    }]
+   }
+ }

vscode配置:文件→首选项→设置→settings.json

{
+  "[vue]": {
+    "editor.defaultFormatter": "octref.vetur"
+  },
+  "eslint.options":{ // 指定vscode的eslint所处理的文件的后缀
+    "extensions":[
+      ".js",
+      ".vue",
+      ".ts",
+      ".tsx"
+    ]
+  },
+  // 自动修复
+  "editor.codeActionsOnSave": {
+    "source.fixAll.eslint": true
+  }
}

Vite 配置跨域Proxy

本地环境跨域

server:{
  proxy:{
    '/api':{
      target: 'xxxxx', // 代理的目标地址
      changeOrigin: true,
      secure: true, // 是否https接口
      ws: true, // 是否代理websockets
      rewrite: (path) => path.replace(/^\/api/,'')
    }
  }
}

初始化axios

// 安装
npm install axios -S

删减:src/views/Home/index.vue

<template>
  <div class="red-home">这是Home组件</div>
  <div>这是Store的数据:{{number}}</div>
</template>
<script setup>
- import { computed } from 'vue'
- import { useStore } from 'vuex'

- const store = useStore()

- setTimeout(() => {
-   store.commit('A/UPDATE_NUMBER',50)
-   store.dispatch('A/NUMBERACTION',200).then(response => {
-    console.log(response)
-  }).catch((error)=>{
-   console.log(error)
-  })
- }, 2000)

- const number = computed(() => store.state.number)
</script>

<style lang="stylus">
 .red-home
   color $red
</style>

关于旧的全局挂在axios方式:

app.config.globalProperties
一个用于注册能够被应用内所有组件实例访问到的全局属性的对象。
这是对 Vue 2 中 Vue.prototype 使用方式的一种替代,此写法在 Vue 3 已经不存在了。
与任何全局的东西一样,应该谨慎使用。
由此可知,vue3其实并不支持这种写法,但是也可以用,这里只做知识拓展,不建议使用

main.js:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

+ import axios from 'axios'

const app = createApp(App)
// 全局载入
+ app.config.globalProperties.$_api = axios
app.use(router).use(store).mount('#app')

--------------------------------

src/views/Home/index.vue:
<script setup>
+ import { getCurrentInstance } from 'vue'

+ const { proxy } = getCurrentInstance()

+ proxy.$axios.post('/xxx)
</script>

了解同源策略

/**
* 同源策略
* 1.http\https
* 2.端口
* 3.www.baidu.com\mail.163.com
*/

跨域重定向:配置vite.config.js文件

// https://cn.vitejs.dev/config/server-options.html#server-proxy
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import eslintPlugin from 'vite-plugin-eslint'

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [
      vue(),
     // 添加下面这块
     eslintPlugin({
       include: ['src/**/*.js', 'src/**/*.vue', 'src/*.js', 'src/*.vue']
     })
    ],
    css: {
      preprocessorOptions: {
       stylus: {
         imports: [path.resolve(__dirname, 'src/assets/style/stylConfig.styl')]
        }
      }
    },
    resolve: {
     alias: {
       '@': path.resolve(__dirname, 'src')
      }
    },
+   server: {
+     proxy: {
+       /**
+        * 1、匹配接口地址前面的字符是 /api,如果成功便会进入重定向
+        * 2、接口组合,用target属性的地址拼接请求地址
+        */
+       '/api': {
+         // 前两个必填
+         target: 'http://xxx.cn',
+         changeOrigin: true,
+         // secure: true, // 是否https接口
+         // ws: true // 是否代理websockets
+         // rewrite: (path) => path.replace(/^\/api/, '')  // 匹配开头为/api 替换为空
+       }
+     }
+   },
  }
})

Vite 配置环境变量

了解环境变量
开发项目时环境主要分为:
1、本地环境 == 在电脑开发项目
2、开发环境 == 部署在服务器环境(可以是,公司内部搭建的服务)// 192.168.110.184:8000
3、测试环境 == 部署在服务器环境(可以是,公司内部搭建的服务)// 192.168.110.184:8001
4、生产环境 == 部署在服务器环境,已经是对外公布的环境,可通过正式域名访问的环境
5、灰色环境 == 比较小型数据应用(公司内部测试,也是属于生产环境的一种)

参考文档:Vite 官方中文文档-环境变量和模式

Vite 在一个特殊的 import.meta.env对象上暴露环境变量:

// 通过内建变量来判断运行环境
console.log('import.meta.env.MODE', import.meta.env.MODE)
console.log('import.meta.env.PROD', import.meta.env.PROD)
console.log('import.meta.env.DEV', import.meta.env.DEV)
console.log('import.meta.env.SSR', import.meta.env.SSR)

环境变量定义
.env文件:

运行 npm run dev ,会自动读取 .env.development 文件
运行 npm run build ,会自动读取 .env.production 文件

tips:为了防止意外地将一些环境变量泄漏到客户端,只有以VITE_为前缀的变量才会暴露给经过 vite 处理的代码:

VITE_SOME_KEY=123
DB_PASSWORD=foobar

只有VITE_SOME_KEY会被暴露为import.meta.env.VITE_SOME_KEY提供给客户端源码,而DB_PASSWORD则不会。

根目录新建.env.development文件

+ VITE_API = http://xx.dev.cn

根目录新建.env.production文件

+ VITE_API = http://xx.pro.cn

配置不同环境的变量
在某些情况下,若想在vite build时运行不同的模式来渲染不同的标题,你可以通过传递--mode选项标志来覆盖命令使用的默认模式。例如,如果你想在 staging (预发布)模式下构建应用:

vite build --mode staging

还需要新建一个 .env.staging 文件:

# .env.staging
VITE_APP_TITLE=My App (staging)

模式
在某些情况下,若想在vite build时运行不同的模式来渲染不同的标题,你可以通过传递--mode选项标志来覆盖命令使用的默认模式。

1、本地环境  npm run dev
2、开发环境  package.json: "build:dev" npm run build --mode dev
3、测试环境  package.json: "build:test" npm run build --mode test
4、生产环境  npm run build 自动读取.env.production
5、灰度环境

--mode dev 需要新建一个 .env.dev 文件:

+ VITE_API = 192.168.110.184:8000

--mode test需要新建一个 .env.test 文件:

+ VITE_API = 192.168.110.184:8001

在vite.config.js中应用:

// https://cn.vitejs.dev/config/server-options.html#server-proxy
M import { defineConfig,loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import eslintPlugin from 'vite-plugin-eslint'

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
+ // 根据当前工作目录中的 `mode` 加载 .env 文件
+ // 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。

+ // js ts 文件需要引入loadEnv
+ // .vue 文件直接用 import.meta.env.DEV

+ const env = loadEnv(mode, process.cwd(), '')
+ console.log('env', env)
  return {
    plugins: [
      vue(),
     // 添加下面这块
     eslintPlugin({
       include: ['src/**/*.js', 'src/**/*.vue', 'src/*.js', 'src/*.vue']
     })
    ],
    css: {
      preprocessorOptions: {
       stylus: {
         imports: [path.resolve(__dirname, 'src/assets/style/stylConfig.styl')]
        }
      }
    },
    resolve: {
     alias: {
       '@': path.resolve(__dirname, 'src')
      }
    },
   server: {
     proxy: {
       /**
        * 1、匹配接口地址前面的字符是 /api,如果成功便会进入重定向
        * 2、接口组合,用target属性的地址拼接请求地址
        */
       '/api': {
         // 前两个必填
M        target: env.VITE_API, //  192.168.110.184:8000/8001
         changeOrigin: true,
         // secure: true, // 是否https接口
         // ws: true // 是否代理websockets
         // rewrite: (path) => path.replace(/^\/api/, '')  // 匹配开头为/api 替换为空
       }
     }
   },
  }
})
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容