Button組件和Checkbox組件(五)

博客寫的比較細(xì)致, 基本是一個小功能把展示 實(shí)現(xiàn) 樣式都粘貼到博客中了, 一步步完成的, 想看實(shí)現(xiàn)可以直接看代碼地址: Button & Checkbox

這次的目標(biāo)是希望實(shí)現(xiàn)一個下面這樣的 Table 組件, 看起來很美觀, 功能基本滿足日常開發(fā), 后面我們會弄一個用例圖, 一個個功能實(shí)現(xiàn)

  • 基本的表格渲染
  • 可以自由渲染數(shù)據(jù)
  • 可以多選數(shù)據(jù)
  • 可以排序
  • 可以展開行
  • etc...
表格

在實(shí)現(xiàn)上面的功能之前, 我們先搭建開發(fā)環(huán)境, 完善基礎(chǔ)組件 ButtonCheckbox 組件,

  1. 技術(shù)棧: React + Hook + TS + Scss
  2. 環(huán)境: Vite腳手架

搭建開發(fā)環(huán)境

Vite 是一種新型前端構(gòu)建工具, 構(gòu)建我們開發(fā)所需要的語言環(huán)境

如何使用 Vite 搭建 React + Ts 模板的腳手架

# vite 后面跟項(xiàng)目名稱
# template 后面跟 需要的模板
yarn create vite 項(xiàng)目名稱 --template react-ts
yarn create vite demo --template react-ts

# 進(jìn)入項(xiàng)目 .scss .less .styl
yarn add sass/less/stylus # 內(nèi)置了 css 預(yù)處理器

搭建我們的目錄結(jié)構(gòu)

.
├── App.scss
├── App.tsx // 展示組件
├── index.scss
├── lib // 組件源代碼
│   └── Button
├── main.tsx // 入口
└── vite-env.d.ts

初始化項(xiàng)目 & Button 組件

  • button 代碼組織
// lib/Button/button.tsx
import { FC } from "react";

interface ButtonProps {}

const Button: FC<ButtonProps> = (props) => {
  return <div>Button</div>;
};

export default Button;
  • 顯示組件
// App.tsx 顯示組件樣式
import { Button } from "./lib/index";

const App = () => {
  return (
    <div className="App">
      <Button />
    </div>
  );
};

export default App;

Button用例圖 & 使用Button

項(xiàng)目已經(jīng)初始化, 我們思考一下用戶如何使用我們的組件, 既簡單又上手, 以及我們?nèi)绾卧O(shè)計(jì) props, 可以讓用戶方便

  1. 有一個基礎(chǔ)樣式, 比默認(rèn)的好看 => hover/focus/active 效果
  2. 可以有不同的類型展示
  3. 是否可點(diǎn)擊

實(shí)現(xiàn)用例1: 默認(rèn)按鈕變成一個好看的按鈕

// lib/Button/button.tsx
import { FC } from "react";
import "./button.scss";

interface ButtonProps {}

const Button: FC<ButtonProps> = (props) => {
  return <button className="g-button g-button-default">按鈕</button>;
};

export default Button;
.g-button {
  padding: 8px 12px;
  font-size: 14px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  

  &:focus {
    outline: none;
  }

  // 默認(rèn)樣式
  &.g-button-default {
    color: #575757;
    background: #f7f7fa;
    &:hover {
      background: #e5e5ea;
    }
    &:active {
      background: #d9d9d9;
    }
  }
}

實(shí)現(xiàn)用例2: 按鈕展示不同的類型

展示不同的類型, 其實(shí)就是添加不同的 class, 給元素不同的展現(xiàn)

import { Button } from "./lib/index";

const App = () => {
  return (
    <div className="App">
      <Button /> 
      <Button type="primary" /> 
      <Button type="danger" /> 
    </div>
  );
};

export default App;
// 添加 type 屬性
import { ButtonHTMLAttributes, FC } from "react";
import classnames from "classnames";
import "./button.scss";

interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLElement>, "type"> {
  type?: "primary" | "danger" | "default";
}

const Button: FC<ButtonProps> = (props) => {
  const { type = "default", ...restProps } = props;
  const classes = {
    [`g-button-${type}`]: type,
  };
  return (
    <button className={classnames("g-button", classes)} {...restProps}>
      按鈕
    </button>
  );
};

export default Button;
.g-button {
  padding: 8px 12px;
  font-size: 14px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  

  &:focus {
    outline: none;
  }

  // 默認(rèn)樣式
  &.g-button-default {
    color: #575757;
    background: #f7f7fa;
    &:hover {
      background: #e5e5ea;
    }
    &:active {
      background: #d9d9d9;
    }
  }

  // 主要顏色
  &.g-button-primary {
    color: #fff;
    background: #3498ff;
    &:hover {
      background: #2589f5;
    }
    &:active {
      background: #1675e0;
    }
  }

  // 危險(xiǎn)顏色
  &.g-button-danger {
    color: #fff;
    background: #ff7875;
    &:hover {
      background: #e4383a;
    }
    &:active {
      background: #d42926;
    }
  }
}

實(shí)現(xiàn)用例3: 按鈕是否可點(diǎn)擊

同理按鈕是否可點(diǎn)擊, 可以設(shè)置不同的樣式, 并阻止點(diǎn)擊事件觸發(fā)

// props 的使用
import { Button } from "./lib/index";
import "./App.scss";

const App = () => {
  return (
    <div className="App">
      <Button>普通按鈕</Button>
      <Button type="primary">主要按鈕</Button>
      <Button type="danger">危險(xiǎn)按鈕</Button>
      <br />
      <Button disabled>不可點(diǎn)擊按鈕</Button>
      <Button type="primary" disabled>
        不可點(diǎn)擊主要按鈕
      </Button>
      <Button type="danger" disabled>
        不可點(diǎn)擊危險(xiǎn)按鈕
      </Button>
    </div>
  );
};

export default App;

// 實(shí)現(xiàn) props disabled
import { ButtonHTMLAttributes, FC } from "react";
import classnames from "classnames";
import "./button.scss";

interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLElement>, "type"> {
  type?: "primary" | "danger" | "default";
}

const Button: FC<ButtonProps> = (props) => {
  const { type = "default", disabled = false, children, ...restProps } = props;
  // 加了一個 class 的判斷
  const cn = {
    [`g-button-${type}`]: type,
    [`g-button-disabled`]: disabled,
  };

  return (
    <button className={classnames("g-button", cn)} {...restProps}>
      {children}
    </button>
  );
};

export default Button;
.g-button {
  padding: 8px 12px;
  font-size: 14px;
  border-radius: 6px;
  border: none;
  user-select: none;
  cursor: pointer;
  margin-right: 8px;
  margin-top: 20px;

  &:focus {
    outline: none;
  }

  // 默認(rèn)樣式
  &.g-button-default {
    color: #575757;
    background: #f7f7fa;
    &:hover {
      background: #e5e5ea;
    }
    &:active {
      background: #d9d9d9;
    }

    &.g-button-disabled {
      color: #c5c6c7;
      pointer-events: none;
    }
  }

  // 主要顏色
  &.g-button-primary {
    color: #fff;
    background: #3498ff;
    &:hover {
      background: #2589f5;
    }
    &:active {
      background: #1675e0;
    }
    &.g-button-disabled {
      background: #cce9ff;
      pointer-events: none;
    }
  }

  // 危險(xiǎn)顏色
  &.g-button-danger {
    color: #fff;
    background: #ff7875;
    &:hover {
      background: #e4383a;
    }
    &:active {
      background: #d42926;
    }
    &.g-button-disabled {
      background: #eeb4b3;
      pointer-events: none;
    }
  }
}

上面代碼完成, 顯示效果

button.png
show1.png

實(shí)現(xiàn)一個 Checkbox 組件

首先在項(xiàng)目里面添加 Checkbox 文件夾

.
├── README.md
├── index.html
├── package.json
├── src
│   ├── App.scss
│   ├── App.tsx
│   ├── index.scss
│   ├── lib
│   │   ├── Button
│   │   ├── Checkbox
│   │   └── index.ts
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── yarn.lock

用例圖 & props 使用

  1. 一個基本好看的樣式, 用戶可以切換勾選
  2. 不可點(diǎn)擊狀態(tài)
  3. 觸發(fā)事件通知外面

實(shí)現(xiàn)用例1: 好看的勾選框 & 可以切換狀態(tài)

我們默認(rèn)的勾選框比較小, 我們可以設(shè)置默認(rèn)的不可見, 寫一個勾選框來覆蓋默認(rèn)樣式, 來模擬 checkbox 的行為, 為了點(diǎn)擊文字也能觸發(fā) checkbox, 使用label 標(biāo)簽包裹元素, 并觸發(fā) change 事件, 改變 checkbox 的狀態(tài)

import { FC, useState } from "react";
import classNames from "classnames";
import "./checkbox.scss";

interface CheckboxProps {
  checked?: boolean;
}

const Checkbox: FC<CheckboxProps> = (props) => {
  const { checked = false } = props;
  // 當(dāng)前是否被選中
  const [currentChecked, setCurrentChecked] = useState(checked);

  const classes = {
    "g-checkbox-checked": currentChecked,
  };

  const handleChange = () => {
    setCurrentChecked(!currentChecked);
  };

  return (
    <label className="g-checkbox-wrapper">
      <span className="g-checkbox">
        <span className={classNames("g-checkbox-inner", classes)}></span>
        <input
          className="g-checkbox-input"
          type="checkbox"
          checked={currentChecked}
          onChange={handleChange}
        />
      </span>
      <span className="g-checkobox-label">選擇框</span>
    </label>
  );
};

export default Checkbox;
.g-checkbox-wrapper {
  display: inline-flex;
  align-items: center;
  user-select: none;
  cursor: pointer;
  .g-checkbox {
    padding: 10px;
    &-inner {
      position: relative;
      display: block;
      width: 16px;
      height: 16px;
      border: 1px solid #d9d9d9;
      border-radius: 3px;
      background: #fff;
      transition: all 0.3s;

      &.g-checkbox-checked {
        background: #3498ff;
        border: 1px solid #3498ff;
        &::after {
          content: "";
          position: absolute;
          top: 1px;
          left: 5px;
          width: 5px;
          height: 10px;
          transform: rotate(45deg);
          border: 2px solid #fff;
          border-top: none;
          border-left: none;
        }
      }
    }

    &-input {
      position: absolute;
      opacity: 0;
      box-sizing: border-box;
    }
  }
}

實(shí)現(xiàn)用例2: 不可點(diǎn)擊狀態(tài)

不可點(diǎn)擊狀態(tài)和 Button 類似, 加一個不可點(diǎn)擊狀態(tài)的樣式, 不能觸發(fā) checkbox 的 change 事件

  • 給父元素添加 disabled className 設(shè)置樣式
  • change 事件 disabled 不可觸發(fā)
  • 添加 checkbox value props, 可選屬性
// 示例
import { Button, Checkbox } from "./lib/index";
import "./App.scss";

const App = () => {
  return (
    <div className="App">
      {/* 使用選擇框 */}
      <Checkbox value="選擇框" />
      <Checkbox disabled checked value="蘋果" />
    </div>
  );
};

export default App;
// 如何實(shí)現(xiàn)

import { FC, useState } from "react";
import classNames from "classnames";
import "./checkbox.scss";

interface CheckboxProps {
  checked?: boolean;
  disabled?: boolean;
  value?: string;
}

const Checkbox: FC<CheckboxProps> = (props) => {
  const { checked = false, disabled = false, value = "" } = props;
  // 當(dāng)前是否被選中
  const [currentChecked, setCurrentChecked] = useState(checked);

  const classes_inner = {
    "g-checkbox-checked": currentChecked,
  };

  const handleChange = () => {
    // 如果 disabeld 不能觸發(fā) change 事件
    if (disabled) return;
    setCurrentChecked(!currentChecked);
  };

  return (
    {/* 添加 disabled class */}
    <label
      className={classNames("g-checkbox-wrapper", {
        "g-checkbox-disabled": disabled,
      })}
    >
      <span className="g-checkbox">
        <span className={classNames("g-checkbox-inner", classes_inner)}></span>
        <input
          className="g-checkbox-input"
          type="checkbox"
          checked={currentChecked}
          onChange={handleChange}
          value={value}
        />
      </span>
      <span className="g-checkbox-label">{value}</span>
    </label>
  );
};

export default Checkbox;
.g-checkbox-wrapper {
  display: inline-flex;
  align-items: center;
  user-select: none;
  cursor: pointer;
  .g-checkbox {
    padding: 10px;
    &-inner {
      position: relative;
      display: block;
      width: 16px;
      height: 16px;
      border: 1px solid #d9d9d9;
      border-radius: 3px;
      background: #fff;
      transition: all 0.3s;

      &.g-checkbox-checked {
        background: #3498ff;
        border: 1px solid #3498ff;
        &::after {
          content: "";
          position: absolute;
          top: 1px;
          left: 5px;
          width: 5px;
          height: 10px;
          transform: rotate(45deg);
          border: 2px solid #fff;
          border-top: none;
          border-left: none;
        }
      }
    }

    &-input {
      position: absolute;
      opacity: 0;
      box-sizing: border-box;
    }
  }

  // disabled 樣式
  &.g-checkbox-disabled {
    cursor: not-allowed;
    .g-checkbox-inner {
      background: #f7f7fa;
      border: none;
      &.g-checkbox-checked {
        background: #cce9ff;
      }
    }
    .g-checkbox-label {
      color: #c5c6c7;
    }
  }
}

實(shí)現(xiàn)用例3: change事件回調(diào)

  • 我們需要知道 checkbox 的狀態(tài), 傳入 change事件
// 使用

import { Button, Checkbox } from "./lib/index";
import "./App.scss";
import { ChangeEvent } from "react";

const App = () => {
  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    // <input class="g-checkbox-input" type="checkbox" value="選擇框">
    // 選擇框
    // false/true
    console.log(e.target, e.target.value, e.target.checked);
  };

  return (
    <div className="App">
      <Checkbox value="選擇框" onChange={handleChange} />
      <Checkbox disabled checked value="蘋果" />
    </div>
  );
};

export default App;

// 實(shí)現(xiàn)
import { ChangeEvent, FC, useState } from "react";
import classNames from "classnames";
import "./checkbox.scss";

interface CheckboxProps {
  checked?: boolean;
  disabled?: boolean;
  value?: string;
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void; // 傳參
}

const Checkbox: FC<CheckboxProps> = (props) => {
  const { checked = false, disabled = false, value = "", onChange } = props;
  // 當(dāng)前是否被選中
  const [currentChecked, setCurrentChecked] = useState(checked);

  const classes_inner = {
    "g-checkbox-checked": currentChecked,
  };

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    // 如果 disabeld 不能觸發(fā) change 事件
    if (disabled) return;
    setCurrentChecked(!currentChecked);
    // 回調(diào)
    onChange && onChange(e);
  };

  return (
    <label
      className={classNames("g-checkbox-wrapper", {
        "g-checkbox-disabled": disabled,
      })}
    >
      <span className="g-checkbox">
        <span className={classNames("g-checkbox-inner", classes_inner)}></span>
        <input
          className="g-checkbox-input"
          type="checkbox"
          checked={currentChecked}
          onChange={handleChange}
          value={value}
        />
      </span>
      <span className="g-checkbox-label">{value}</span>
    </label>
  );
};

export default Checkbox;

  • 有時候不知道這個元素的類型, 可以把鼠標(biāo)放在元素上, 看一下什么類型
類型

實(shí)現(xiàn) CheckboxGroup 組件

平常我們使用多選框大部分是把多個選擇框放在一起, 成為一組, 選擇多個, CheckboxGroup 組件就是對 Checkbox 組件包裝一下, 當(dāng)觸發(fā) chnage 事件時, 知道我們選擇了哪些選擇框, 而不用給每一個 Checkbox 添加一個 change事件

用例圖 & 使用方式

  • 用戶默認(rèn)選中了哪幾個
  • 用戶改變選中, 返回選中值

下面我們看一下如何讓用戶使用我們的組件, 第一種方案是 讓用戶寫入每一個 Checkbox 組件, 第二種方案是讓用戶通過數(shù)據(jù)的方式我們自己來渲染這些Checkbox, 這次我先嘗試使用 第一種方式來實(shí)現(xiàn) CheckboxGroup

// 1. 元素方式
<CheckboxGroup selected={["11", "33"]} onChange={handleChange}>
  <Checkbox value="11">蘋果</Checkbox>
  <Checkbox value="22">香蕉</Checkbox>
  <Checkbox value="33" disabled>火龍果</Checkbox>
</CheckboxGroup>


// 2. 數(shù)據(jù)方式
const options = [
  {
    label: "電影",
    value: "1",
    disabled: true
  },
  {
    label: "電視劇",
    value: "2",
    disabled: false
  },
  {
    label: "做夢",
    value: "3",
    disabled: false
  }
];

<CheckboxGroup options={options} selected={["1", "3"]} onChange={handleChange} />
  • 第一種方式我們需要使用到 React.Children 這個 API, 我們來渲染我們的 Children, React.Children 提供了用于處理 this.props.children 不透明數(shù)據(jù)結(jié)構(gòu)的實(shí)用方法
// 如何使用最基本的
import { Button, Checkbox, CheckboxGroup } from "./lib/index";
import "./App.scss";
import { ChangeEvent } from "react";

const App = () => {
  return (
    <div className="App">
      <CheckboxGroup>
        <Checkbox value="蘋果" />
        <Checkbox value="香蕉" />
        <Checkbox value="梨子" disabled />
      </CheckboxGroup>
    </div>
  );
};

export default App;

// checkboxGroup.tsx
import React, { FC, ReactElement } from "react";
import Checkbox from "./checkbox";

interface GroupProps {
  children: Array<ReactElement>;
}

const CheckboxGroup: FC<GroupProps> = (props) => {
  const { children } = props;

  const childWithProps = React.Children.map(children, (child, index) => {
    // 確保每一個子元素都是 checkbox
    if (child.type !== Checkbox) {
      throw new Error("復(fù)選框組的子元素必須是 Checkbox");
    }

    // 返回每一個子元素并帶有props
    return React.cloneElement(child, {
      ...child.props,
      key: index,
    });
  });

  return <div>{childWithProps}</div>;
};

export default CheckboxGroup;
  • 可以看到下面的我們可以正確渲染了 多選框組, 但是我們不知道我們選中了哪一個, 如果有默認(rèn)選中的我們也不知道怎么設(shè)置, 下面添加兩個屬性
    1. selected props 用戶初始是否有默認(rèn)選中的值
    2. onChange 當(dāng)用戶觸發(fā)子元素事件, 通知父元素選中一組中的哪幾個
group.png

實(shí)現(xiàn)1: selected 數(shù)組

在父元素 CheckboxGroup 上添加 <CheckboxGroup selected={["11", "33"]}> 時, 把selected 傳遞給 Checkbox, 初始時判斷value 是否在 selected 中, 如果在 checked 為 true, 不在 checked 為 false

// 使用 selected
import { Button, Checkbox, CheckboxGroup } from "./lib/index";
import "./App.scss";
import { ChangeEvent } from "react";

const App = () => {
  return (
    <div className="App" selected=["香蕉"]>
      <CheckboxGroup>
        <Checkbox value="蘋果" />
        <Checkbox value="香蕉" />
        <Checkbox value="梨子" disabled />
      </CheckboxGroup>
    </div>
  );
};

export default App;
// checkboxGroup.tsx
import React, { FC, ReactElement } from "react";
import Checkbox from "./checkbox";

interface GroupProps {
  selected?: string[]; // group 使用, value 值的集合
  children: Array<ReactElement>;
}

const CheckboxGroup: FC<GroupProps> = (props) => {
  const { children, selected = [] } = props;

  const childWithProps = React.Children.map(children, (child, index) => {
    // 確保每一個子元素都是 checkbox
    if (child.type !== Checkbox) {
      throw new Error("復(fù)選框組的子元素必須是 Checkbox");
    }

    return React.cloneElement(child, {
      ...child.props,
      key: index,
      selected, // 添加的 selected props 傳遞給子元素
    });
  });

  return <div>{childWithProps}</div>;
};

export default CheckboxGroup;
// checkbox.tsx

import { ChangeEvent, FC, useEffect, useState } from "react";
import classNames from "classnames";
import "./checkbox.scss";

interface CheckboxProps {
  checked?: boolean;
  disabled?: boolean;
  value?: string;
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;

  // group 傳的 props
  selected?: string[];
}

const Checkbox: FC<CheckboxProps> = (props) => {
  const {
    selected = [],
    checked = false,
    disabled = false,
    value = "",
    onChange,
  } = props;
  // 當(dāng)前是否被選中
  const [currentChecked, setCurrentChecked] = useState(checked);

  // + 初始判斷是否被選中
  useEffect(() => {
    if (selected.length > 0 && selected.indexOf(value) > -1) {
      setCurrentChecked(true);
    }
  }, []);

  const classes_inner = {
    "g-checkbox-checked": currentChecked,
  };

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    // 如果 disabeld 不能觸發(fā) change 事件
    if (disabled) return;
    setCurrentChecked(!currentChecked);
    onChange && onChange(e);
  };

  return (
    <label
      className={classNames("g-checkbox-wrapper", {
        "g-checkbox-disabled": disabled,
      })}
    >
      <span className="g-checkbox">
        <span className={classNames("g-checkbox-inner", classes_inner)}></span>
        <input
          className="g-checkbox-input"
          type="checkbox"
          checked={currentChecked}
          onChange={handleChange}
          value={value}
        />
      </span>
      <span className="g-checkbox-label">{value}</span>
    </label>
  );
};

export default Checkbox;

實(shí)現(xiàn)2: change事件

上面我們實(shí)現(xiàn)了 selected, 現(xiàn)在當(dāng)我們改變選中數(shù)組時告訴父元素哪幾個兄弟被選中了, 所以我們需要根據(jù) selected 的值來為初始值, 當(dāng)改變子元素的 checked, 來改變選中的值

// 使用 onChange
import { Button, Checkbox, CheckboxGroup } from "./lib/index";
import "./App.scss";
import { ChangeEvent } from "react";

const App = () => {
  const handleChange = (values: string[]) => {
    setValues(values);
  };

  return (
    <div className="App" selected=["香蕉"] onChange={handleChange}>
      <CheckboxGroup>
        <Checkbox value="蘋果" />
        <Checkbox value="香蕉" />
        <Checkbox value="梨子" disabled />
      </CheckboxGroup>
    </div>
  );
};

export default App;
// CheckboxGroup.tsx

import React, {
  ChangeEvent,
  FC,
  ReactElement,
  useEffect,
  useState,
} from "react";
import Checkbox from "./checkbox";

interface GroupProps {
  selected?: string[]; // group 使用, value 值的集合
  children: Array<ReactElement>;
  onChange?: (selected: string[]) => void;
}

const CheckboxGroup: FC<GroupProps> = (props) => {
  const { children, selected = [], onChange } = props;

  const [selectedValue, setSelectedValue] = useState(selected);

  // 變化時改變 值
  const handleGroupChange = (e: ChangeEvent<HTMLInputElement>) => {
    const { checked, value } = e.currentTarget;
    if (checked) {
      setSelectedValue([...selectedValue, value]);
    } else {
      setSelectedValue((arr) => arr.filter((i) => i !== value));
    }
  };

  // 值每次變化都暴露出去
  useEffect(() => {
    onChange && onChange(selectedValue);
  }, [selectedValue]);

  const childWithProps = React.Children.map(children, (child, index) => {
    // 確保每一個子元素都是 checkbox
    if (child.type !== Checkbox) {
      throw new Error("復(fù)選框組的子元素必須是 Checkbox");
    }

    return React.cloneElement(child, {
      ...child.props,
      key: index,
      selected,
      onChange: handleGroupChange, // 利用回調(diào)
    });
  });

  return <div>{childWithProps}</div>;
};

export default CheckboxGroup;
selected.png

上面完善了 Button組件和Checkbox組件的基本使用, 可以在后面我們寫Table 組件的時候直接使用, 如果需要其它功能, 自己添加一下 props

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阱扬,一起剝皮案震驚了整個濱河市另假,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌畦娄,老刑警劉巖卓舵,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異跳芳,居然都是意外死亡芍锦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門飞盆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娄琉,“玉大人次乓,你說我怎么就攤上這事∧跛” “怎么了票腰?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長女气。 經(jīng)常有香客問我杏慰,道長,這世上最難降的妖魔是什么炼鞠? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任缘滥,我火速辦了婚禮,結(jié)果婚禮上谒主,老公的妹妹穿的比我還像新娘完域。我一直安慰自己,他們只是感情好瘩将,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凹耙,像睡著了一般姿现。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上肖抱,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天备典,我揣著相機(jī)與錄音,去河邊找鬼意述。 笑死提佣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荤崇。 我是一名探鬼主播拌屏,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼术荤!你這毒婦竟也來了倚喂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瓣戚,失蹤者是張志新(化名)和其女友劉穎端圈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體子库,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舱权,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了仑嗅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宴倍。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡张症,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出啊楚,到底是詐尸還是另有隱情吠冤,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布恭理,位于F島的核電站拯辙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏颜价。R本人自食惡果不足惜涯保,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望周伦。 院中可真熱鬧夕春,春花似錦、人聲如沸专挪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寨腔。三九已至速侈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迫卢,已是汗流浹背倚搬。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乾蛤,地道東北人每界。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像家卖,于是被迫代替她去往敵國和親眨层。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

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