TS + React 工程化實(shí)踐

1. TypeScript工程化開發(fā)

  • 前端工程化就是通過流程規(guī)范化炸庞、標(biāo)準(zhǔn)化提升團(tuán)隊(duì)協(xié)作效率
  • 通過組件化燕雁、模塊化提升代碼質(zhì)量
  • 使用構(gòu)建工具、自動(dòng)化工具提升開發(fā)效率
  • 編譯 => 打包(合并) => 壓縮 => 代碼檢查 => 測(cè)試 => 持續(xù)集成

2.初始化項(xiàng)目

mkdir zhufeng_typescript_development
cd zhufeng_typescript_development
npm init
package name: (zhufeng_typescript_development)
version: (1.0.0)
description: TypeScript工程化開發(fā)
entry point: (index.js)
test command:
git repository: https://gitee.com/zhufengpeixun/zhufeng_typescript_development
keywords: typescript,react
author: zhangrenyang
license: (ISC) MIT

3. git規(guī)范和changelog

3.1 良好的git commit好處

  • 可以加快code review 的流程
  • 可以根據(jù)git commit 的元數(shù)據(jù)生成changelog
  • 可以讓其它開發(fā)者知道修改的原因

3.2 良好的commit

  • commitizen是一個(gè)格式化commit message的工具

  • validate-commit-msg 用于檢查項(xiàng)目的 Commit message 是否符合格式

  • conventional-changelog-cli可以從git metadata生成變更日志

  • 統(tǒng)一團(tuán)隊(duì)的git commit 標(biāo)準(zhǔn)

  • 可以使用angulargit commit日志作為基本規(guī)范

    • 提交的類型限制為 feat僧免、fix捏浊、docs、style浊洞、refactor法希、perf靶瘸、test怨咪、chore、revert等
    • 提交信息分為兩部分唉匾,標(biāo)題(首字母不大寫巍膘,末尾不要加標(biāo)點(diǎn))峡懈、主體內(nèi)容(描述修改內(nèi)容)
  • 日志提交友好的類型選擇提示 使用commitize工具

  • 不符合要求格式的日志拒絕提交 的保障機(jī)制

    • 需要使用validate-commit-msg工具
  • 統(tǒng)一changelog文檔信息生成

    • 使用conventional-changelog-cli工具
cnpm i commitizen  validate-commit-msg conventional-changelog-cli -D
commitizen init cz-conventional-changelog --save --save-exact
git cz

3.3 提交的格式

<type>(<scope>):<subject/>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
  • <type>代表某次提交的類型,比如是修復(fù)bug還是增加feature
  • <scope>表示作用域,比如一個(gè)頁(yè)面或一個(gè)組件
  • <subject> 主題 梅鹦,概述本次提交的內(nèi)容
  • <body> 詳細(xì)的影響內(nèi)容
  • <footer> 修復(fù)的bug和issue鏈接
類型 含義
feat 新增feature
fix 修復(fù)bug
docs 僅僅修改了文檔齐唆,比如README箍邮、CHANGELOG叨叙、CONTRIBUTE等
style 僅僅修改了空格、格式縮進(jìn)擂错、偏好等信息味滞,不改變代碼邏輯
refactor 代碼重構(gòu),沒有新增功能或修復(fù)bug
perf 優(yōu)化相關(guān)钮呀,提升了性能和體驗(yàn)
test 測(cè)試用例剑鞍,包括單元測(cè)試和集成測(cè)試
chore 改變構(gòu)建流程,或者添加了依賴庫(kù)和工具
revert 回滾到上一個(gè)版本
ci CI 配置爽醋,腳本文件等更新

3.4 husky

  • validate-commit-msg可以來檢查我們的commit規(guī)范
  • husky可以把validate-commit-msg作為一個(gè)githook來驗(yàn)證提交消息
cnpm i husky  validate-commit-msg --save-dev
  "husky": {
    "hooks": {
      "commit-msg": "validate-commit-msg"
    }
  }

3.5 生成CHANGELOG.md

  • conventional-changelog-cli 默認(rèn)推薦的 commit 標(biāo)準(zhǔn)是來自angular項(xiàng)目
  • 參數(shù)-i CHANGELOG.md表示從 CHANGELOG.md 讀取 changelog
  • 參數(shù) -s 表示讀寫 CHANGELOG.md 為同一文件
  • 參數(shù) -r 表示生成 changelog 所需要使用的 release 版本數(shù)量蚁署,默認(rèn)為1光戈,全部則是0
cnpm i conventional-changelog-cli -D
"scripts": {
    "changelogs": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
}

4. 支持Typescript

tsc --init

基本參數(shù)

參數(shù) 解釋
target 用于指定編譯之后的版本目標(biāo)
module 生成的模塊形式:none、commonjs镇饺、amd奸笤、system监右、umd健盒、es6惰帽、es2015 或 esnext 只有 amd 和 system 能和 outFile 一起使用 target 為 es5 或更低時(shí)可用 es6 和 es2015
lib 編譯時(shí)引入的 ES 功能庫(kù)该酗,包括:es5 、es6莱衩、es7操骡、dom 等册招。如果未設(shè)置是掰,則默認(rèn)為: target 為 es5 時(shí): ["dom", "es5", "scripthost"] target 為 es6 時(shí): ["dom", "es6", "dom.iterable", "scripthost"]
allowJs 是否允許編譯JS文件键痛,默認(rèn)是false,即不編譯JS文件
checkJs 是否檢查和報(bào)告JS文件中的錯(cuò)誤丁频,默認(rèn)是false
jsx 指定jsx代碼用于的開發(fā)環(huán)境 preserve指保留JSX語(yǔ)法,擴(kuò)展名為.jsx,react-native是指保留jsx語(yǔ)法席里,擴(kuò)展名js,react指會(huì)編譯成ES5語(yǔ)法 詳解
declaration 是否在編譯的時(shí)候生成相應(yīng)的.d.ts聲明文件
declarationDir 生成的 .d.ts 文件存放路徑,默認(rèn)與 .ts 文件相同
declarationMap 是否為聲明文件.d.ts生成map文件
sourceMap 編譯時(shí)是否生成.map文件
outFile 是否將輸出文件合并為一個(gè)文件,值是一個(gè)文件路徑名繁疤,只有設(shè)置module的值為amdsystem模塊時(shí)才支持這個(gè)配置
outDir 指定輸出文件夾
rootDir 編譯文件的根目錄,編譯器會(huì)在根目錄查找入口文件
composite 是否編譯構(gòu)建引用項(xiàng)目
removeComments 是否將編譯后的文件中的注釋刪掉
noEmit 不生成編譯文件
importHelpers 是否引入tslib里的輔助工具函數(shù)
downlevelIteration 當(dāng)target為ES5ES3時(shí),為for-of褐啡、spreaddestructuring中的迭代器提供完全支持
isolatedModules 指定是否將每個(gè)文件作為單獨(dú)的模塊,默認(rèn)為true

嚴(yán)格檢查

參數(shù) 解釋
strict 是否啟動(dòng)所有類型檢查
noImplicitAny 不允許默認(rèn)any類型
strictNullChecks 當(dāng)設(shè)為true時(shí)懂盐,null和undefined值不能賦值給非這兩種類型的值
strictFunctionTypes 是否使用函數(shù)參數(shù)雙向協(xié)變檢查
strictBindCallApply 是否對(duì)bind莉恼、call和apply綁定的方法的參數(shù)的檢測(cè)是嚴(yán)格檢測(cè)的
strictPropertyInitialization 檢查類的非undefined屬性是否已經(jīng)在構(gòu)造函數(shù)里初始化
noImplicitThis 不允許this表達(dá)式的值為any類型的時(shí)候
alwaysStrict 指定始終以嚴(yán)格模式檢查每個(gè)模塊

額外檢查

參數(shù) 解釋
noUnusedLocals 檢查是否有定義了但是沒有使用的變量
noUnusedParameters 檢查是否有在函數(shù)體中沒有使用的參數(shù)
noImplicitReturns 檢查函數(shù)是否有返回值
noFallthroughCasesInSwitch 檢查switch中是否有case沒有使用break跳出

模塊解析檢查

參數(shù) 解釋
moduleResolution 選擇模塊解析策略,有nodeclassic兩種類型,詳細(xì)說明
baseUrl 解析非相對(duì)模塊名稱的基本目錄
paths 設(shè)置模塊名到基于baseUrl的路徑映射
rootDirs 可以指定一個(gè)路徑列表捶惜,在構(gòu)建時(shí)編譯器會(huì)將這個(gè)路徑列表中的路徑中的內(nèi)容都放到一個(gè)文件夾中
typeRoots 指定聲明文件或文件夾的路徑列表
types 用來指定需要包含的模塊
allowSyntheticDefaultImports 允許從沒有默認(rèn)導(dǎo)出的模塊中默認(rèn)導(dǎo)入
esModuleInterop 為導(dǎo)入內(nèi)容創(chuàng)建命名空間,實(shí)現(xiàn)CommonJS和ES模塊之間的互相訪問
preserveSymlinks 不把符號(hào)鏈接解析為其真實(shí)路徑

sourcemap檢查

參數(shù) 解釋
sourceRoot 調(diào)試器應(yīng)該找到TypeScript文件而不是源文件位置
mapRoot 調(diào)試器找到映射文件而非生成文件的位置,指定map文件的根路徑
inlineSourceMap 指定是否將map文件的內(nèi)容和js文件編譯在一個(gè)同一個(gè)js文件中
inlineSources 是否進(jìn)一步將.ts文件的內(nèi)容也包含到輸出文件中

試驗(yàn)選項(xiàng)

參數(shù) 解釋
experimentalDecorators 是否啟用實(shí)驗(yàn)性的裝飾器特性
emitDecoratorMetadata 是否為裝飾器提供元數(shù)據(jù)支持

試驗(yàn)選項(xiàng)

參數(shù) 解釋
files 配置一個(gè)數(shù)組列表,里面包含指定文件的相對(duì)或絕對(duì)路徑吝岭,編譯器在編譯的時(shí)候只會(huì)編譯包含在files中列出的文件
include include也可以指定要編譯的路徑列表苍碟,但是和files的區(qū)別在于微峰,這里的路徑可以是文件夾颜凯,也可以是文件
exclude exclude表示要排除的症概、不編譯的文件彼城,他也可以指定一個(gè)列表
extends extends可以通過指定一個(gè)其他的tsconfig.json文件路徑募壕,來繼承這個(gè)配置文件里的配置
compileOnSave 在我們編輯了項(xiàng)目中文件保存的時(shí)候舱馅,編輯器會(huì)根據(jù)tsconfig.json的配置重新生成文件
references 一個(gè)對(duì)象數(shù)組,指定要引用的項(xiàng)目

5. 支持React

5.1 安裝

cnpm i typescript webpack webpack-cli webpack-dev-server ts-loader cross-env webpack-merge clean-webpack-plugin html-webpack-plugin -D
cnpm i babel-loader @babel/core @babel/cli @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread @babel/preset-env @babel/preset-typescript -D

5.2 webpack.config.js

webpack.config.js

const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
  mode: "development",
  devtool:false,
  entry: "./src/index.tsx",
  output: {
    filename: "[name].[hash].js",
    path: path.join(__dirname, "dist"),
  },
  devServer: {
    hot: true,
    contentBase: path.join(__dirname, "dist"),
    historyApiFallback: {
      index: "./index.html",
    },
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".json"],
    alias: {
      "@": path.resolve("src"), // 這樣配置后 @ 可以指向 src 目錄
    },
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "ts-loader"
      }
    ],
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html"
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
};

5.3 src\index.tsx

src\index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
let root = document.getElementById('root');

let props = { className: 'title' };
let element= React.createElement('div', props, 'hello');
ReactDOM.render(element, root);

5.4 src\index.html

src\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>typescript</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

5.5 package.json

{
  "scripts": {
+    "start": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js",
+    "build": "cross-env NODE_ENV=production npm run eslint && webpack --config ./config/webpack.prod.js",
    "eslint": "eslint src --ext .ts",
    "eslint:fix": "eslint src --ext .ts --fix",
    "changelogs": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
    "test": "mocha --require ts-node/register test/**/*"
  }
}

6. 代碼規(guī)范

  • 規(guī)范的代碼可以促進(jìn)團(tuán)隊(duì)合作
  • 規(guī)范的代碼可以降低維護(hù)成本
  • 規(guī)范的代碼有助于 code review(代碼審查)

6.1 常見的代碼規(guī)范文檔

6.2 代碼檢查

  • Eslint 是一款插件化的 JavaScript 靜態(tài)代碼檢查工具干毅,ESLint 通過規(guī)則來描述具體的檢查行為
6.2.1 模塊安裝
cnpm i eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
6.2.2 eslintrc配置文件

.eslintrc.js

module.exports = {
    "parser":"@typescript-eslint/parser",
    "plugins":["@typescript-eslint"],
    "rules":{
        "no-var":"error",
        "no-extra-semi":"error",
        "@typescript-eslint/indent":["error",2]
    },
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
          "modules": true
        }
    }
}
6.2.3 代碼檢查

package.json

"scripts": {
    "start": "webpack",
    "build": "tsc",
    "eslint": "eslint src --ext .ts",
    "eslint:fix": "eslint src --ext .ts --fix"
  }

src/1.ts

var name2 = 'zhufeng';;;
if(true){
    let a = 10;
}

執(zhí)行命令

npm run eslint
1:1   error  Unexpected var, use let or const instead      no-var
1:23  error  Unnecessary semicolon                         no-extra-semi
1:24  error  Unnecessary semicolon                         no-extra-semi
3:1   error  Expected indentation of 2 spaces but found 4  @typescript-eslint/indent
6.2.4 配置自動(dòng)修復(fù)
  • 安裝vscode的eslint插件
  • 配置自動(dòng)修復(fù)參數(shù)

.vscode\settings.json

{
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        "typescript",
        "typescriptreact"
    ],
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    }
  }

7.單元測(cè)試

7.1 安裝配置

cnpm i jest @types/jest ts-jest -D
npx ts-jest config:init

7.2 src\calculator.tsx

src\calculator.tsx

function sum(a: number, b: number) {
    return a + b;
}
function minus(a: number, b: number) {
    return a - b;
}
module.exports = {
    sum,
    minus
}

7.3 tests\calculator.spec.tsx

tests\calculator.spec.tsx

let math = require('../src/calculator');
test('1+1=2', () => {
    expect(math.sum(1, 1)).toBe(2);
});
test('1-1=0', () => {
    expect(math.minus(1, 1)).toBe(0);
});

7.4 package.json

package.json

  "scripts": {
+    "test": "jest"
  },

8. 持續(xù)集成

  • Travis CI 提供的是持續(xù)集成服務(wù)(Continuous Integration符隙,簡(jiǎn)稱 CI)霹疫。它綁定 Github 上面的項(xiàng)目猎拨,只要有新的代碼吧恃,就會(huì)自動(dòng)抓取硬毕。然后,提供一個(gè)運(yùn)行環(huán)境,執(zhí)行測(cè)試节腐,完成構(gòu)建箱熬,還能部署到服務(wù)器
  • 持續(xù)集成指的是只要代碼有變更赤炒,就自動(dòng)運(yùn)行構(gòu)建和測(cè)試,反饋運(yùn)行結(jié)果表悬。確保符合預(yù)期以后卤恳,再將新代碼集成到主干
  • 持續(xù)集成的好處在于,每次代碼的小幅變更本今,就能看到運(yùn)行結(jié)果,從而不斷累積小的變更挪凑,而不是在開發(fā)周期結(jié)束時(shí),一下子合并一大塊代碼

8.1 登錄并創(chuàng)建項(xiàng)目

  • Travis CI 只支持 Github,所以你要擁有GitHub帳號(hào)
  • 該帳號(hào)下面有一個(gè)項(xiàng)目,面有可運(yùn)行的代碼,還包含構(gòu)建或測(cè)試腳本
  • 你需要激活了一個(gè)倉(cāng)庫(kù)菇绵,Travis 會(huì)監(jiān)聽這個(gè)倉(cāng)庫(kù)的所有變化

8.2 .travis.yml

  • Travis 要求項(xiàng)目的根目錄下面咬最,必須有一個(gè).travis.yml文件惑申。這是配置文件圈驼,指定了 Travis 的行為
  • 該文件必須保存在 Github 倉(cāng)庫(kù)里面绩脆,一旦代碼倉(cāng)庫(kù)有新的 Commit靴迫,Travis 就會(huì)去找這個(gè)文件,執(zhí)行里面的命令
  • 這個(gè)文件采用 YAML 格式慌随。下面是一個(gè)最簡(jiǎn)單的 Node 項(xiàng)目的.travis.yml文件
language: node_js
node_js:
  - "11"
install: npm install
script:  npm test  

8.3 實(shí)戰(zhàn)

8.3.1 生成項(xiàng)目并上傳github

npx create-react-app zhufeng-typescript-development

8.3.2 同步倉(cāng)庫(kù)

8.3.3 設(shè)置倉(cāng)庫(kù)環(huán)境變量

變量名 含義
GH_TOKEN 用戶生成的令牌
GH_REF 倉(cāng)庫(kù)地址 github.com/zhufengnodejs/zhufeng_typescript_development.git

8.3.4 Github生成訪問令牌 (即添加授權(quán))

  • 訪問令牌的作用就是授權(quán)倉(cāng)庫(kù)操作權(quán)限
  • Github>settings>Personal access tokens> Generate new token > Generate token> Copy Token

8.3.5 .travis.yml

language: node_js
node_js: 
    - '11'
install:
  - npm install
script:
  - hexo g
after_script:
  - cd ./public
  - git init
  - git config user.name "${USERNAME}"
  - git config user.email "${UESREMAIL}"
  - git add -A
  - git commit -m "Update documents"
  - git push --force  "https://${GH_TOKEN}@${GH_REF}" "master:${GH_BRANCH}"
branches:
  only:
    - master

9.React元素

DetailedReactHTMLElements.jpg

8.1 原生組件

src\index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
let root: HTMLElement | null = document.getElementById('root');
interface Props {
  className: string
}
let props: Props = { className: 'title' };
let element: React.DetailedReactHTMLElement<Props, HTMLDivElement> = (
  React.createElement<Props, HTMLDivElement>('div', props, 'hello')
)
ReactDOM.render(element, root);

src\typings.tsx

export interface DOMAttributes {
  children?: ReactNode;
}
export interface HTMLAttributes extends DOMAttributes {
  className?: string;
}

export interface ReactElement<P = any,T extends string> {
  type: T;
  props: P;
}
export interface DOMElement extends ReactElement{}
export interface ReactHTML { div:  HTMLDivElement }
export interface DetailedReactHTMLElement extends DOMElement{
  type: keyof ReactHTML;
}

export type ReactText = string | number;
export type ReactChild = ReactElement | ReactText;
export type ReactNode = ReactChild | boolean | null | undefined;

export declare function createElement<P extends {}>(
  type: string,
  props?: P,
  ...children: ReactNode[]): ReactElement;

8.2 函數(shù)組件

src\index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
let root: HTMLElement | null = document.getElementById('root');
interface Props {
  className: string
}
let props: Props = { className: 'title' };
function Welcome(props: Props):React.DetailedReactHTMLElement<Props, HTMLDivElement> {
  return React.createElement<Props, HTMLDivElement>('div', props, 'hello');
}
let element: React.FunctionComponentElement<Props> = (
  React.createElement<Props>(Welcome, props)
)
ReactDOM.render(element, root);

src\typings.tsx

export interface DOMAttributes {
  children?: ReactNode;
}
export interface HTMLAttributes extends DOMAttributes {
  className?: string;
}
+export type JSXElementConstructor<P> = ((props: P) => ReactElement | null)
+export interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string> {
  type: T;
  props: P;
}
export interface DOMElement extends ReactElement{}
export interface ReactHTML { div:  HTMLDivElement }
export interface DetailedReactHTMLElement extends DOMElement{
  type: keyof ReactHTML;
}

export type ReactText = string | number;
export type ReactChild = ReactElement | ReactText;
export type ReactNode = ReactChild | boolean | null | undefined;

+type PropsWithChildren<P> = P & { children?: ReactNode };
+interface FunctionComponent<P = {}> {
+  (props: PropsWithChildren<P>): ReactElement | null;
+}
+interface FunctionComponentElement<P> extends ReactElement<P, FunctionComponent<P>> {}
+export declare function createElement<P extends {}>(
+  type: FunctionComponent<P>,
+  props?: P,
+  ...children: ReactNode[]): FunctionComponentElement<P>;
export declare function createElement<P extends {}>(
  type: string,
  props?: P,
  ...children: ReactNode[]): ReactElement;

8.3 類組件

src\index.tsx

import * as React from 'react';
import * as ReactDOM from 'react-dom';
let root: HTMLElement | null = document.getElementById('root');
interface Props {
  className: string
}
interface State {
  count:number
}
class Welcome extends React.Component<Props, State> {
  state = { count: 0 }
  render():React.DetailedReactHTMLElement<Props, HTMLDivElement> {
    return React.createElement<Props, HTMLDivElement>('div', this.props, this.state.count);
  }
}
let props: Props = { className: 'title' };
let element = (
  React.createElement<Props>(Welcome, props)
)
ReactDOM.render(element, root);

src\typings.tsx

export interface DOMAttributes {
  children?: ReactNode;
}
export interface HTMLAttributes extends DOMAttributes {
  className?: string;
}
export type JSXElementConstructor<P> =  
| ((props: P) => ReactElement | null)
| (new (props: P) => Component<P, any>);

export interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string> {
  type: T;
  props: P;
}
export interface DOMElement extends ReactElement{}
export interface ReactHTML { div:  HTMLDivElement }
export interface DetailedReactHTMLElement extends DOMElement{
  type: keyof ReactHTML;
}

export type ReactText = string | number;
export type ReactChild = ReactElement | ReactText;
export type ReactNode = ReactChild | boolean | null | undefined;

type PropsWithChildren<P> = P & { children?: ReactNode };
interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>): ReactElement | null;
}
interface FunctionComponentElement<P> extends ReactElement<P, FunctionComponent<P>> {}

type ComponentState = any;
declare class Component<P, S> {
  setState(state: any): void;
  render(): ReactNode;
}
interface ComponentClass<P = {}, S = ComponentState> {
  new(props: P): Component<P, S>;
}
interface ComponentElement<P> extends ReactElement<P, ComponentClass<P>> {}
export declare function createElement<P extends {}>(
  type:  ComponentClass<P>,
  props?: P,
  ...children: ReactNode[]): ComponentElement<P>;
export declare function createElement<P extends {}>(
  type: FunctionComponent<P>,
  props?: P,
  ...children: ReactNode[]): FunctionComponentElement<P>;
export declare function createElement<P extends {}>(
  type: string,
  props?: P,
  ...children: ReactNode[]): ReactElement;

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市畏邢,隨后出現(xiàn)的幾起案子舒萎,更是在濱河造成了極大的恐慌臂寝,老刑警劉巖败徊,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件集嵌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡凤粗,警方通過查閱死者的電腦和手機(jī)嫌拣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來插掂,“玉大人酝润,你說我怎么就攤上這事要销∈韪溃” “怎么了凳鬓?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)仅孩。 經(jīng)常有香客問我辽慕,道長(zhǎng)公浪,這世上最難降的妖魔是什么欠气? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮袁梗,結(jié)果婚禮上淋袖,老公的妹妹穿的比我還像新娘即碗。我一直安慰自己拜姿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布蛤肌。 她就那樣靜靜地躺著,像睡著了一般炒俱。 火紅的嫁衣襯著肌膚如雪权悟。 梳的紋絲不亂的頭發(fā)上峦阁,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天驹闰,我揣著相機(jī)與錄音嘹朗,去河邊找鬼。 笑死曾掂,一個(gè)胖子當(dāng)著我的面吹牛溜歪,可吹牛的內(nèi)容都是我干的蝴猪。 我是一名探鬼主播自阱,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼加派!你這毒婦竟也來了芍锦?” 一聲冷哼從身側(cè)響起娄琉,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤檬输,失蹤者是張志新(化名)和其女友劉穎丧慈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體簇搅,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吟税,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了异旧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吮蛹。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倚喂,靈堂內(nèi)的尸體忽然破棺而出雳攘,到底是詐尸還是另有隱情枫笛,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布啊楚,位于F島的核電站恭理,受9級(jí)特大地震影響颜价,放射性物質(zhì)發(fā)生泄漏夕春。R本人自食惡果不足惜及志,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锌畸。 院中可真熱鬧潭枣,春花似錦盆犁、人聲如沸谐岁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)议薪。三九已至斯议,卻和暖如春哼御,著一層夾襖步出監(jiān)牢的瞬間艇搀,已是汗流浹背焰雕。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工矩屁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烁峭。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鬓梅,于是被迫代替她去往敵國(guó)和親绽快。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坊罢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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