dva的入門和使用

dva的入門和使用

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

  1. 安裝cli npm i dva-cli -g
  2. 創(chuàng)建新項(xiàng)目 dva new [project name]
  3. 啟動(dòng)項(xiàng)目 npm run start

目錄介紹

    |- mock                     // 存放用于 mock 數(shù)據(jù)的文件
    |- node_modules
    |- package.json
    |- public                   // 一般用于存放靜態(tài)文件,打包時(shí)會(huì)被直接復(fù)制到輸出目錄(./dist)
    |- src                      // 文件夾用于存放項(xiàng)目源代碼
        |- asserts                  // 用于存放靜態(tài)資源,打包時(shí)會(huì)經(jīng)過(guò) webpack 處理
        |- components               // 用于存放 React 組件,一般是該項(xiàng)目公用的無(wú)狀態(tài)組件
        |- models                   // 用于存放模型文件
        |- routes                   // 用于存放需要 connect model 的路由組件
        |- services                 // 用于存放服務(wù)文件丁逝,一般是網(wǎng)絡(luò)請(qǐng)求等
        |- utils                    // 工具類庫(kù)
        |- router.js                // 路由文件
        |- index.js                 // 項(xiàng)目的入口文件
        |- index.css                // 一般是共用的樣式
    |- .editorconfig            // 編輯器配置文件
    |- .eslintrc                // ESLint配置文件
    |- .gitignore               // Git忽略文件
    |- .roadhogrc.mock.js       // Mock配置文件
    |- .webpackrc               // 自定義的webpack配置文件膀值,JSON格式

使用antd

  1. 安裝 npm i antd babel-plugin-import -S
  2. 配置 .roadhogrc 文件 / 或者 .webpackrc 文件
        "extraBabelPlugins": [
              "transform-runtime",
              ["import", {"libraryName":"antd", "style":"css"}]
          ]
    

配置代理

    // 在 .roadhogrc 文件, 加上 “proxy” 配置 / 或者 `.webpackrc` 文件
    "proxy": {
        "/api": {
            "target": "http://localhost:9093/",
            "changeOrigin": true,
            "pathRewrite": {"^/api": ""}
        }
    }

HMR熱更新替換

    // 在 .webpackrc 中添加如下配置

    "env": {
        "development": {
            "extraBabelPlugins": [
                "dva-hmr"
            ]
        }
    }
    // 如果無(wú)效亚情,請(qǐng)嘗試更新一下 babel-plugin-dva-hmr

開(kāi)發(fā)簡(jiǎn)單的項(xiàng)目示例

  1. 創(chuàng)建項(xiàng)目, 完成上述配置

  2. 創(chuàng)建后臺(tái)接口, 也可mock數(shù)據(jù)

    • 我自己是用nodejs創(chuàng)建的接口
        // 創(chuàng)建與src同級(jí)的文件夾 server
        // 在server下創(chuàng)建server.js  model.js   api.js
        
        // server.js ===============================================================
    
        const express = require('express')
        const bodyParser = require('body-parser')   // 解析傳輸?shù)腷ody
        const apiRoute = require('./api')    // 引入路由
    
        // 創(chuàng)建app
        const app = express()
    
        // 使用中間件
        app.use(bodyParser.json())
        app.use(bodyParser.urlencoded({ extended: false }))
    
        // 使用路由
        app.use('/api', apiRoute)
    
        // 開(kāi)啟服務(wù)
        app.listen(9093, () => {
            console.log('Node app start at port 9093')
        })
    
    
        // model.js ===============================================================
    
         // 引入mongoose庫(kù), 該庫(kù)是nodejs來(lái)操作mongodb的
         const mongoose = require('mongoose')
    
         // 連接mongo, 并且使用dva-todo這個(gè)集合
         const DB_URL = 'mongodb://localhost:27017/dva-todo'
         mongoose.connect(DB_URL)
    
        // 定義表結(jié)構(gòu)
        const models = {
            todo: {
                'text': {type: String, require: true},
                'checked': {type: Boolean, require: true},
            }
        }
    
        // 快速生成對(duì)應(yīng)結(jié)構(gòu)的表
        for (let m in models){
            mongoose.model(m, new mongoose.Schema(models[m]))
        }
    
        // 輸出獲取數(shù)據(jù)庫(kù)的方法
        module.exports = {
            getModel(name) {
                return mongoose.model(name)
            }
        }
    
    
        // api.js ================================================================
        
        const express = require('express')  // 加載express框架
        const Router = express.Router()     // 使用express的路由
        const apiModel = require('./model')    // 引入數(shù)據(jù)庫(kù)操作
        const todo = apiModel.getModel('todo') // 使用數(shù)據(jù)庫(kù)的todo表
        const multipart = require('connect-multiparty') // 使得post請(qǐng)求能支持formdata
        const multipartMiddleware = multipart()
    
        // 查詢數(shù)據(jù)
        Router.get('/get', (req, res) => {
            todo.find({}, (err, doc) => {
                if(err) return res.json({code: 1, msg: '獲取數(shù)據(jù)失敗!'})
                return res.json({code: 0, data: doc})
            })
        })
    
        // 添加數(shù)據(jù)
        Router.post('/add', multipartMiddleware, (req, res) => {
            const {text} = req.body
            const newTodo = new todo({text: text, checked: false})
            newTodo.save((err, doc) => {
                if(err) return res.json({code: 1, msg: '添加數(shù)據(jù)失敗!'})
                return res.json({code: 0, data: doc})
            })
        })
    
        // 選中
        Router.post('/check', (req, res) => {
            const {id, checked} = req.body
            todo.findByIdAndUpdate(id, {checked: checked}, (err, doc) => {
                if(err) return res.json({code: 1, msg: '刪除數(shù)據(jù)失敗!'})
                return res.json({code: 0, data: doc})
            })
        })
    
        // 全選或反選
        Router.post('/checkAll', (req, res) => {
            const {checked} = req.body
            todo.update({}, {'$set': {checked: checked}}, { multi: true }, (err, doc) => {
                if(err) return res.json({code: 1, msg: '刪除數(shù)據(jù)失敗!'})
                return res.json({code: 0})
            })
        })
    
    
        // 刪除
        Router.post('/delete', (req, res) => {
            const {id} = req.body
            todo.remove({_id:id}, (err, doc) => {
                if(err) return res.json({code: 1, msg: '刪除數(shù)據(jù)失敗!'})
                return res.json({code: 0})
            })
        })
    
        // 清空
        Router.get('/clear', (req, res) => {
            todo.remove({}, (err, doc) => {
                if(err) return res.json({code: 1, msg: '清空數(shù)據(jù)失敗!'})
                return res.json({code: 0})
            })
        })
    
        // 輸出路由
        module.exports = Router
    
  3. src/index.js => dva的入口

import dva from 'dva'
import './index.css'
import createLoading from 'dva-loading'  // 需要npm安裝
import { createBrowserHistory } from 'history'

// 1. Initialize
const app = dva({
    history: createBrowserHistory()
})

// 2. Plugins
// app.use({});
app.use(createLoading())

// 3. Model
app.model(require('./models/main').default)

// 4. Router
app.router(require('./router').default)

// 5. Start
app.start('#root')
  1. src/index.css => 公共的css
html, body, :global(#root) {
  height: 100%;
}
  1. src/router.js => 路由配置
import React from 'react'
import { Router, Route, Switch } from 'dva/router'
import All from './routes/all/all'
import Active from './routes/active/active'
import Completed from './routes/completed/completed'

function RouterConfig ({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/all" exact component={All} />
        <Route path="/active" exact component={Active} />
        <Route path="/completed" exact component={Completed} />
        <Route component={All} />
      </Switch>
    </Router>
  )
}

export default RouterConfig
  1. src/utils/request.js => fetch請(qǐng)求數(shù)據(jù)的配置
import fetch from 'dva/fetch'

function parseJSON(response) {
  return response.json()
}

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response
  }

  const error = new Error(response.statusText)
  error.response = response
  throw error
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default function request(url, options) {
  const defaultOptions = {
    credentials: 'include',
  }
  const newOptions = { ...defaultOptions, ...options }

  if (newOptions.method === 'POST' || newOptions.method === 'PUT' || newOptions.method === 'DELETE') {
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers,
      }
      newOptions.body = JSON.stringify(newOptions.body)
    } else {
      // newOptions.body is FormData
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers,
      }
    }
  }


  return fetch(url, newOptions)
    .then(checkStatus)
    .then(parseJSON)
    .then(data => ({ data }))
    .catch(err => ({ err }))
}
  1. src/services/main.js => 配置各種接口
import request from '../utils/request'
import {stringify} from 'qs'

export function get() {
  return request('/api/get')
}

export function add(obj) {
  return request('/api/add', {method: 'POST', body: obj})
}

export function remove(obj) {
  return request('/api/delete', {method: 'POST', body: obj})
}

export function check(obj) {
  return request('/api/check', {method: 'POST', body: obj})
}

export function clear() {
  return request('/api/clear')
}

export function checkAll(obj) {
  return request('/api/checkAll', {method: 'POST', body: obj})
}
  1. src/routes => 路由頁(yè)面
// src/routes/all/all.js ====================================================
import React from 'react'
import { connect } from 'dva'
import { Row, Col } from 'antd'
import Header from '../../components/header'
import Footer from '../../components/footer'
import MainList from '../../components/main'

class All extends React.Component{
    render (){
      return (
        <div style={{height: '100%'}}>
          <Row type="flex" justify="center" style={{height: '10%', alignItems: 'center', background: '#001529'}}>
            <Col>
              <Header></Header>
            </Col>
          </Row>

          <Row type="flex" justify="center" style={{height: '80%', background: '#f0f2f5'}}>
            <MainList dataType='all'/>
          </Row>

          <Row type="flex" justify="center" style={{height: '10%', alignItems: 'center', background: '#f0f2f5'}}>
            <Col>
              <Footer></Footer>
            </Col>
          </Row>
        </div>
      )
    }
}

All.propTypes = {}

export default connect()(All)



// src/routes/active/active.js========================================================================
import React from 'react'
import { connect } from 'dva'
import { Row, Col } from 'antd'
import Header from '../../components/header'
import Footer from '../../components/footer'
import MainList from '../../components/main'

class Active extends React.Component{
    render (){
      return (
        <div style={{height: '100%'}}>
          <Row type="flex" justify="center" style={{height: '10%', alignItems: 'center', background: '#001529'}}>
            <Col>
              <Header></Header>
            </Col>
          </Row>

          <Row type="flex" justify="center" style={{height: '80%', background: '#f0f2f5'}}>
            <MainList dataType='active'/>
          </Row>

          <Row type="flex" justify="center" style={{height: '10%', alignItems: 'center', background: '#f0f2f5'}}>
            <Col>
              <Footer></Footer>
            </Col>
          </Row>
        </div>
      )
    }
}

Active.propTypes = {}

export default connect()(Active)



// src/routes/completed/completed.js=====================================================================
import React from 'react'
import { connect } from 'dva'
import { Row, Col } from 'antd'
import Header from '../../components/header'
import Footer from '../../components/footer'
import MainList from '../../components/main'

class Completed extends React.Component{
    render (){
      return (
        <div style={{height: '100%'}}>
          <Row type="flex" justify="center" style={{height: '10%', alignItems: 'center', background: '#001529'}}>
            <Col>
              <Header></Header>
            </Col>
          </Row>

          <Row type="flex" justify="center" style={{height: '80%', background: '#f0f2f5'}}>
            <MainList dataType='completed'/>
          </Row>

          <Row type="flex" justify="center" style={{height: '10%', alignItems: 'center', background: '#f0f2f5'}}>
            <Col>
              <Footer></Footer>
            </Col>
          </Row>
        </div>
      )
    }
}

Completed.propTypes = {}

export default connect()(Completed)
  1. src/models/main.js => dva最重要的部分, 將redux全都集中在一個(gè)文件進(jìn)行操作
import {add, get, remove, check, clear, checkAll} from '../services/main'

export default {

  // 命名空間, 以命名空間來(lái)區(qū)分不同的model
  namespace: 'todo',   

  // 初始state
  state: [],    

  // 監(jiān)聽(tīng)任務(wù) => 一般用來(lái)監(jiān)聽(tīng)路由變化
  subscriptions: {    
    setup({ dispatch, history }) {  // eslint-disable-line
      history.listen(location => {
        // console.log(1, location)
      })
    },
  },

  // 進(jìn)行各種異步操作, 組件內(nèi)可以dispatch來(lái)觸發(fā), 但是此處不能修改state, 只有reducers可以
  effects: {
    *get({ payload }, { call, put }) {  // eslint-disable-line
      const response = yield call(get, payload)
      const data = response.data.code === 0 ? response.data.data : []
      yield put({ type: 'getData' , payload: data})
    },
    *clear({ payload }, { call, put }) {
      const response = yield call(clear, payload)
      if(response.data.code === 0){
        yield put({ type: 'clearData'})
      }else{
        console.error(response.data.msg)
      }
    },
    *add({ payload }, { call, put }) {
      const response = yield call(add, payload)
      if(response.data.code === 0){
        yield put({ type: 'addData', payload: response.data.data})
      }else{
        console.error(response.data.msg)
      }
    },
    *remove({ payload }, { call, put }) {
      const response = yield call(remove, payload)
      if(response.data.code === 0){
        yield put({ type: 'removeData', payload: payload})
      }else{
        console.error(response.data.msg)
      }
    },
    *check({ payload }, { call, put }) {
      const response = yield call(check, payload)
      if(response.data.code === 0){
        yield put({ type: 'checkData', payload: response.data.data})
      }else{
        console.error(response.data.msg)
      }
    },
    *checkAll({ payload }, { call, put }) {
      const response = yield call(checkAll, payload)
      if(response.data.code === 0){
        yield put({ type: 'checkAllData', payload: payload})
      }else{
        console.error(response.data.msg)
      }
    }
  },

  // 修改state的各種操作, 可以通過(guò)effects進(jìn)行調(diào)用, 也可以通過(guò)組件dispatch進(jìn)行調(diào)用
  reducers: {
    getData(state, action) {
      return [ ...state, ...action.payload ]
    },
    clearData(state) {
      state = []
      return state
    },
    addData(state, action) {
      return [...state, {_id: action.payload._id, text: action.payload.text, checked: false}]
    },
    removeData(state, action) {
      const id = action.payload.id
      return state.filter(v => v._id !== id)
    },
    checkData(state, action) {
      const {_id, checked} = action.payload
      state.forEach(v => {
        if(v._id === _id){
          v.checked = !checked
        }
      })
      return state
    },
    checkAllData(state, action) {
      state.forEach(v => {
        v.checked = action.payload.checked
      })
      return state
    }
  },
}
  1. src/components => 各個(gè)組件
 // src/components/header.js=============================================================
import React from 'react'

const Header = () => {
  return (
    <div>
      <h1 style={{color: '#fff'}}>todos</h1>
    </div>
  )
}

Header.propTypes = {
}

export default Header


// src/components/footer.js=============================================================
import React from 'react'

const Footer = () => {
  return (
    <div>
      <a style={{color: '#999'}}>todo list</a>
    </div>
  )
}

Footer.propTypes = {}

export default Footer


// src/components/main.js================================================================
import React from 'react'
import { connect } from 'dva'
import { Link } from 'dva/router'
import PropTypes from 'prop-types'
import { Row, Col, Form, Input, Checkbox, Button, List, Icon } from 'antd'

// 此處的connect是裝飾器的寫法, 需要配置裝飾器
@connect(state => ({
  data: state
}))

export default class MainList extends React.Component{
  static propTypes = {
    dataType: PropTypes.string.isRequired
  }

  constructor(props){
    super(props)
    this.state = {
      showClose: true
    }
    this.handleAdd = this.handleAdd.bind(this)
    this.deleteItem = this.deleteItem.bind(this)
    this.clearData = this.clearData.bind(this)
    this.checkAll = this.checkAll.bind(this)
  }

  componentDidMount(){
    const { dispatch } = this.props
    this.props.data.todo = []
    dispatch({
      type: 'todo/get',
      payload: {}
    })
  }

  clearData(){
    this.props.dispatch({type: 'todo/clear'})
    this.props.dispatch({type: 'todo/get',payload: {}})
  }

  handleAdd(e){
    if(e.keyCode !== 13) return
    const text = e.target.value
    e.target.value = ''
    const { dispatch } = this.props
    dispatch({
      type: 'todo/add',
      payload: {text}
    })
  }

  deleteItem(id){
    this.props.dispatch({
      type: 'todo/remove',
      payload: {id}
    })
  }

  handleCheck(id, checked) {
    this.props.dispatch({
      type: 'todo/check',
      payload: {id, checked: !checked}
    })
  }

  checkAll() {
    const tempData = Object.values(this.props.data.todo)
    const flag = tempData.every(v => v.checked === true)
    this.props.dispatch({
      type: 'todo/checkAll',
      payload: {checked: !flag}
    })
  }

  render() {
    const FormItem = Form.Item
    const ListItem = List.Item
    let allData = []
    allData = Object.values(this.props.data.todo)
    
    const leftNum = allData.filter(v => v.checked === false).length

    if(this.props.dataType === 'active'){
      allData = allData.filter(v => v.checked === false)
    }else if(this.props.dataType === 'completed'){
      allData = allData.filter(v => v.checked === true)
    }

    return (
      <div style={{width: '100%'}}>
        <Row style={{minHeight: 50}}></Row>
        <Row>
          <Col span={12} offset={6}>
            <Form>
              <FormItem>
                <Button icon="down" onClick={this.checkAll}></Button>
                <Input style={{width: 'calc(100% - 32px)'}} onKeyDown={this.handleAdd}></Input>
              </FormItem>

              <FormItem>
                <List bordered
                  pagination={{
                    onChange: (page) => {
                      console.log(page)
                    },
                    pageSize: 5,
                  }}
                  dataSource={allData}
                  renderItem={v => (
                    <ListItem style={{position: 'relative', paddingLeft: 22}}  key={v._id} onMouseEnter={() => (this.setState({showClose: v._id}))} onMouseLeave={() => (this.setState({showClose: -1}))}>
                      <Checkbox style={{position: 'absolute', top: 13, left: 0}} checked={v.checked} onChange={() => this.handleCheck(v._id, v.checked)}></Checkbox>
                      <ListItem.Meta description={v.text} title=''/>
                      {this.state.showClose === v._id ? <Icon type='close' style={{cursor: 'pointer', color: 'red'}} onClick={() => this.deleteItem(v._id)}/> : <Icon type='check' style={{color: 'rgb(240, 242, 245)'}}/>}
                    </ListItem>
                  )}
                >
                </List>
              </FormItem>

              <FormItem>
                <span style={{float: 'left'}}>{leftNum} items left</span>
                <span style={{float: 'left', marginLeft: '22%'}}>
                  <Link style={{margin: '0 25px', color: '#666'}} to='/all'>all</Link>
                  <Link style={{margin: '0 25px', color: '#666'}} to='/active'>active</Link>
                  <Link style={{margin: '0 25px', color: '#666'}} to='/completed'>completed</Link>
                </span>
                <span style={{float: 'right',cursor: 'pointer'}} onClick={this.clearData}>clear all</span>
              </FormItem>
            </Form>
          </Col>
        </Row>
        <Row style={{minHeight: 50}}></Row>
      </div>
    )
  }
}
  1. 附package.json
{
  "private": true,
  "scripts": {
    "start": "roadhog server",
    "build": "roadhog build",
    "lint": "eslint --ext .js src test",
    "precommit": "npm run lint"
  },
  "dependencies": {
    "antd": "^3.6.6",
    "body-parser": "^1.18.3",
    "cookie-parser": "^1.4.3",
    "dva": "^2.3.1",
    "express": "^4.16.3",
    "mongoose": "^5.2.3",
    "react": "^16.2.0",
    "react-dom": "^16.2.0"
  },
  "devDependencies": {
    "babel-plugin-dva-hmr": "^0.3.2",
    "babel-plugin-import": "^1.8.0",
    "connect-multiparty": "^2.1.1",
    "dva-loading": "^2.0.3",
    "eslint": "^4.14.0",
    "eslint-config-umi": "^0.1.1",
    "eslint-plugin-flowtype": "^2.34.1",
    "eslint-plugin-import": "^2.6.0",
    "eslint-plugin-jsx-a11y": "^5.1.1",
    "eslint-plugin-react": "^7.1.0",
    "history": "^4.7.2",
    "husky": "^0.12.0",
    "qs": "^6.5.2",
    "redbox-react": "^1.4.3",
    "roadhog": "^2.0.0"
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末命浴,一起剝皮案震驚了整個(gè)濱河市装悲,隨后出現(xiàn)的幾起案子厕倍,更是在濱河造成了極大的恐慌寡壮,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異况既,居然都是意外死亡这溅,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門棒仍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悲靴,“玉大人,你說(shuō)我怎么就攤上這事莫其●校” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵乱陡,是天一觀的道長(zhǎng)浇揩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)憨颠,這世上最難降的妖魔是什么胳徽? 我笑而不...
    開(kāi)封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮烙心,結(jié)果婚禮上膜廊,老公的妹妹穿的比我還像新娘。我一直安慰自己淫茵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蹬跃。 她就那樣靜靜地躺著匙瘪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝶缀。 梳的紋絲不亂的頭發(fā)上丹喻,一...
    開(kāi)封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音翁都,去河邊找鬼碍论。 笑死,一個(gè)胖子當(dāng)著我的面吹牛柄慰,可吹牛的內(nèi)容都是我干的鳍悠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼坐搔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼藏研!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起概行,我...
    開(kāi)封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蠢挡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體业踏,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡禽炬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勤家。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腹尖。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖却紧,靈堂內(nèi)的尸體忽然破棺而出桐臊,到底是詐尸還是另有隱情,我是刑警寧澤晓殊,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布断凶,位于F島的核電站,受9級(jí)特大地震影響巫俺,放射性物質(zhì)發(fā)生泄漏认烁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一介汹、第九天 我趴在偏房一處隱蔽的房頂上張望却嗡。 院中可真熱鬧,春花似錦嘹承、人聲如沸窗价。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撼港。三九已至,卻和暖如春骤竹,著一層夾襖步出監(jiān)牢的瞬間帝牡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工蒙揣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留靶溜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓懒震,卻偏偏與公主長(zhǎng)得像罩息,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挎狸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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