Vue框架快速入门

Vue是现在最流行的前端框架之一,而且相对于其他两个框架React和Angular来说也更加易学,而且它的作者是国人,中文文档也很完善。当然Vue框架算是比较高级的框架,所以在使用过程中还需要JavaScript、JavaScript 2015、WebPack、NodeJS、npm、ESLint、JavaScript单元测试框架等其他知识和框架的使用方法。在学习Vue之前,最好先学习一下这些知识。由于Vue的中文文档比较完善,所以这里只介绍Vue框架的一些核心概念,详细的使用方法还得查看官方文档。

Vue的中文文档可以查看https://cn.vuejs.org/v2/guide/installation.html

Vue路由功能需要导入vue-router,它的中文文档可以查看https://router.vuejs.org/zh-cn/

Vue的状态管理功能需要使用vuex,它的中文文档可以查看https://vuex.vuejs.org/zh-cn/

如果需要更多Vue资料,可以查看awesome-vue,列举了很多Vue资源。

Vue基本概念

从单文件开始

首先,我们来抛开那些复杂的框架配置,先从单文件开始学习Vue最基本的内容。这样做很简单,讲下面的代码复制为一个HTML文件,在浏览器中打开即可。这里引用了Vue框架的CDN,所以不需要任何配置即可使用Vue。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Vue单文件例子</title>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
</body>
</html>

Vue实例

Vue框架中最重要的东西就是Vue实例了,它是Vue框架的核心对象。在创建Vue实例的时候需要传入一些参数,el参数是Vue实例的作用范围;data参数是Vue实例使用的数据。在Vue实例对应的元素中,我们可以使用模板语法{{var}}来使用这些数据。

<h1>Vue实例</h1>
<div id="s1">
  <p>{{data}}</p>
</div>
<script>
  let vm1 = new Vue({
    el: '#s1',
    data: {
      data: '一些数据'
    }
  })
</script>

模板语法

文本插值

上面已经展示了一个小例子。文本需要写在两对花括号之间。当然这里其实不止可以写单个变量,还可以写组合表达式,例如{{text + new Date()}}

所有在构造Vue实例是传入的数据都是可响应的,也就是说只要数据发生改变,那么视图的数据也会发生改变。如果希望数据不发生改变,需要使用v-once指令。所有v-开头的都是Vue独有的指令,这些指令将在后面介绍。

HTML插值

有时候需要操作原始HTML,Vue也提供了支持。要插入的HTML代码需要使用v-html指令来指定,这个指令会将它所在的HTML代码块整个替换为要插入的HTML块。由于可能导致XSS攻击,所以最好不要随便替换HTML块。另外要替换HTML块的话只能使用v-html指令,如果使用前面的文本插值的话,插入的只是一段文本。

属性

文本插值只能插入文本,如果需要设置和修改HTML属性的话,需要使用v-bind指令。

下面是一个简单的例子,将它复制到前面的HTML文件中即可看到效果。

<h1>模板语法</h1>
<div id="s2">
  <button v-on:click='changeText'>修改文本</button>
  <p>文本:{{text}}</p>
  <p>组合表达式:</p>
  <p v-once>只渲染一次的文本:{{text}}</p>
  <p>HTML代码:<span v-html="html"></span></p>
  <p>属性:
    <button v-bind:disabled="disabled">禁用按钮</button>
  </p>
</div>
<script>
  let vm2 = new Vue({
    el: '#s2',
    data: {
      text: 1,
      html: '<del>666</del>',
      disabled: true
    },
    methods: {
      changeText: function (event) {
        this.text += 1
      }
    }
  })
</script>

计算属性

有时候程序逻辑比较复杂,可能需要对一个数据进行一些计算和处理。这时候就需要计算属性了。当然由于模板语法支持表达式,所以也可以直接在{{}}中编写表达式,但是不管从可读性还是可维护的角度来说,计算属性都是更好的选择。

计算属性需要在构造Vue实例的时候传入computed属性,然后在相应的函数中处理复杂逻辑。计算属性可以向普通属性那样在视图中使用。计算属性有个优点就是惰性求值,下面的例子中,toUpper计算属性依赖于words属性,只要words不发生改变,那么多次访问toUpper不会重新出发计算,而是会使用已有的结果。只有当words发生变化时,toUpper才会相应改变。

<h1>计算属性</h1>
<div id="s3">
  <p>单词:{{words}}</p>
  <p>单词大写:{{toUpper}}</p>
</div>
<script>
  let vm3 = new Vue({
    el: '#s3',
    data: {
      words: 'I love you'
    },
    computed: {
      toUpper: function () {
        return this.words.toUpperCase()
      }
    }
  })
</script>

Vue指令

v-once

这个指令让视图只渲染一次,将来就算相应的数据发生变化,也不会重新渲染。该指令主要在希望静态显示不需要更新数据的时候使用。

v-html

这个指令主要在需要操作原始HTML的时候使用。

v-bind

该指令在需要绑定HTML标签属性的时候使用。为了方便,该指令还有一个缩写:,例如:class="myClass"就相当于v-bind:class="myClass"

v-on

该指令主要用于绑定事件处理程序。该指令有缩写@,例如@click="onClick"就相当于v-on:click="onClick"

v-show、v-if、v-else和v-else-if

这几个指令主要用于条件渲染,将在后面进行介绍。

v-for

该指令用于渲染整个列表,将在后面进行介绍。

v-model

该指令可以让页面元素和数据进行双向绑定。默认情况下数据和页面元素是单向绑定的,使用该指令可以让其变成双向绑定。该指令主要用于处理表单等场景。

条件渲染

v-if、v-else和v-else-if这几个指令用于条件渲染,让我们可以按照条件在页面上显示和隐藏某些元素。注意v-else-if指令是Vue 2.1新增的。类似的指令还有v-show,不过v-show指令仅仅改变元素的CSS display属性,也是说隐藏的元素还是存在于页面上,仅仅是不显示而已。而v-if等元素会真正创建和销毁元素。

这些指令的使用方法很简单,直接看例子就行了。

<h1>条件渲染</h1>


<div id="s4">
  <h3>v-if渲染会实际创建和销毁对象</h3>
  <p>分数是:<input type="text" v-model="mark"/></p>
  <p v-if="mark < 60">不及格</p>
  <p v-else-if="mark <80">及格</p>
  <p v-else="">优秀</p>
  <h3>v-show仅仅调用CSS display属性</h3>
  <button @click="toggleShow">改变show状态</button>
  <p v-show="show">可以看到我</p>
</div>
<script>
  let vm4 = new Vue({
    el: '#s4',
    data: {
      mark: 80,
      show: true
    },
    methods: {
      toggleShow: function () {
        this.show = !this.show
      }
    }
  })
</script>

列表渲染

如果需要渲染一组数据,可以使用v-for指令。v-for指令需要一个item in items块来声明迭代那些数据,这里in也可以改为of。如果需要获取迭代的索引的话,可以把迭代块声明为(item, index) in items这样的。另外除了迭代一个列表,也可以迭代一个对象的属性。

<h1>列表渲染</h1>
<div id="s5">
  <h3>名字列表</h3>
  <ul>
    <li v-for="name in names">{{name}}</li>
  </ul>

  <h3>人物表格</h3>
  <table>
    <thead>
    <tr>
      <td>编号</td>
      <td>姓名</td>
      <td>年龄</td>
    </tr>
    </thead>
    <tbody>
    <tr v-for="(person, index) of people" :key="index">
      <td>{{index}}</td>
      <td>{{person.name}}</td>
      <td>{{person.age}}</td>
    </tr>
    </tbody>
  </table>

</div>
<script>
  let vm5 = new Vue({
    el: '#s5',
    data: {
      names: [
        'zhang3',
        'li4',
        'yitian',
        'jojo'
      ],
      people: [
        {name: 'zhang3', age: 24},
        {name: 'li4', age: 25},
        {name: 'yitian', age: 24},
        {name: 'jojo', age: 30}
      ]
    }
  })
</script>

事件处理

v-on指令用于绑定事件处理函数,这里的函数需要在构造Vue实例的时候在methods属性中声明。

针对键盘按键,Vue还定义了一组按键修饰别名,详情请参考官方文档。下面是一个简单的例子。

<h1>事件处理</h1>
<div id="s6">
  <h3>计数器</h3>
  <p>
    <button @click="addCount">增加计数</button>
    <em>{{count}}</em>
  </p>
  <h3>获取按键(单击、回车和空格)</h3>
  <input type="text"
         @keyup.enter="alert('按下了回车')"
         @keyup.space="alert('按下了空格')"
         @click="alert('单击')"/>
</div>
<script>
  let vm6 = new Vue({
    el: '#s6',
    data: {
      count: 0
    },
    methods: {
      addCount: function () {
        this.count++
      }
    }
  })
</script>

绑定表单

如果要将数据和页面元素进行双向绑定,使用v-model指令。这个指令主要用于处理表单输入中。下面是一组表单例子。

<h1>绑定表单</h1>
<div id="s7">
  <p>文本框:{{text}}</p>
  <p>多行文本:{{textArea}}</p>
  <p>单选按钮:{{radio}}</p>
  <p>复选框:{{checkbox}}</p>
  <p>多选框:{{select}}</p>
  <hr>
  <p>文本框:<input type="text" v-model="text"></p>
  <p>多行文本:<textarea v-model="textArea"></textarea></p>
  <p>单选按钮:<input type="radio" v-model="radio" value="1" id="one"><label for="one">1</label>
    <input type="radio" value="2" v-model="radio" id="two"><label for="two">2</label>
  </p>
  <p>复选框:<input type="checkbox" v-model="checkbox" id="checkbox"><label for="checkbox">复选框</label></p>
  <p>多选框:<select id="select" v-model="select">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
  </select>
  </p>
</div>
<script>
  let vm7 = new Vue({
    el: '#s7',
    data: {
      text: 'text',
      textArea: 'textArea',
      radio: '',
      checkbox: '',
      select: '',
    }
  })
</script>

在处理表单输入的时候,还有.lazy.number.trim几个修饰符,它们的作用分别是在change事件中更新、将表单输入转换为数值以及去掉表单中的前后空格。

组件

前面介绍了Vue的各种功能,但是这些功能并不能直接在项目中使用。因为如果直接使用的话,会导致出现一个非常大的Vue实例,这和将所有代码都写在一个文件的道理是一样的。所以Vue引入了组件来进行模块化功能。

定义组件和定义一个Vue实例类似。不同的是,组件需要有自己的模板,而且组件的data属性必须是一个函数。原因是假如一个组件在多个地方复用,那么原本的data属性会导致所有组件实例共用一个属性值。使用函数后,每个组件实例都会有自己独立的数据。更加详细的解释和例子请查看官方文档。

  let component1 = {
    template: '<h3>{{hello}}</h3>',
    data() {
      return {
        hello: 'hello world'
      }
    }
  }

定义好了组件之后,我们还需要在Vue中注册它。第一种方法是全局注册,这样组件就可以在全局范围中使用。

Vue.component('组件标签名', {
  //实际组件
})

第二种方法更常见,就是局部注册。将组建注册到局部Vue实例,那么组件只会在该实例的作用域内可见。局部注册需要在创建Vue实例的时候讲组件传入到components属性中。

  let vm8 = new Vue({
    el: '#s8',
    components: {
      'hello-world': component1,
    }
  })

组件注册完毕之后,我们就可以像使用自定义标签一样使用它了。

<hello-world></hello-world>

如果需要从父组件中传递数据,需要在子组件中声明props属性制定要传入的数据。

  let component1 = {
    template: '<p>{{hello}} {{name}}</p>',
    data() {
      return {
        hello: 'hello world'
      }
    },
    props: [
      'name'
    ]
  }

然后就可以像这样传递数据了。

<hello-world name="zhang3"></hello-world>

如果需要传递动态数据,使用v-bind指令即可。

<hello-world :name="name"></hello-world>

一个完整的例子见下。

<h1>组件</h1>
<div id="s8">
  <h3>hello world组件</h3>
  <hello-world></hello-world>
  <h3>从父组件传递数据</h3>
  <hello-world name="zhang3"></hello-world>
  <h3>动态传递数据</h3>
  <hello-world :name="name"></hello-world>
</div>
<script>
  let component1 = {
    template: '<p>{{hello}} {{name}}</p>',
    data() {
      return {
        hello: 'hello world'
      }
    },
    props: [
      'name'
    ]
  }
  let vm8 = new Vue({
    el: '#s8',
    data: {
      name: 'yitian'
    },
    components: {
      'hello-world': component1,
    }
  })
</script>

过渡效果

最后来说说Vue的过渡效果,这里只说说最基本的进入离开过渡。Vue还支持更加复杂的状态过渡,如果想了解这些更复杂的知识,请直接查看文档。

Vue封装了一个组件transition,当其中的组件被插入、删除,或者发生变化的时候,会自动查看这些组件是否应用了过渡CSS类,然后再恰当的时机插入和删除这些类,从而实现过渡效果。过渡类名在官方文档中有介绍,还有一张过渡示意图,这里我就不再介绍了。

比如说我现在需要一个透明度过渡效果。我可以这样编写CSS类。

    .v-enter-active {
      transition: all 1s;
    }

    .v-leave-active {
      transition: all 1s;
    }

    .v-enter, .v-leave-to {
      opacity: 0;
    }

然后用下面的方法使用,就可以看到实际效果了。

<div id="s9">
  <h3>按钮过渡</h3>
  <button @click="show = !show">改变状态</button>
  <transition>
    <p v-if="show">Hello</p>
  </transition>
</div>
<script>
  let vm9 = new Vue({
    el: '#s9',
    data: {
      show: true
    }
  })

当然对于我这种前端小白来说,自己编写过渡和动画效果还是有点困难。幸好有很多第三方动画库,而且Vue允许我们自定义类名,以便和这些动画库配合使用。比方说Animate.css,我们可以将CDN添加到页面中来使用。

<link href="https://cdn.bootcss.com/animate.css/3.5.2/animate.min.css" rel="stylesheet">

然后自定义类名即可。

  <transition enter-active-class="animated fadeInLeft"
              leave-active-class="animated fadeOutUpBig">
    <p v-if="show">Hello</p>
  </transition>

完整的单文件例子可以查看我的示例项目

Vue工程化

前面介绍了Vue的基本概念,但是这些概念无法直接用在项目中。下面通过Vue和各种工具链的使用,来介绍如何用Vue创建实际前端项目。

从模板创建Vue项目

首先确保你安装了NodeJS,然后安装Vue命令行工具。如果npm速度太慢的话,可以使用淘宝镜像来加速。

npm install -g vue-cli

安装完成之后,使用vue-cli来创建模板项目。由于WebPack打包工具现在非常流行,所以这里选择创建WebPack模板。创建的时候除了Vue之外,其他组件如vue-router、eslint等都不要选。

vue init webpack your-app-name

项目创建完毕之后,切换到项目文件夹中,可以看到已经生成了一堆文件。然后我们使用npm i来安装所有的依赖包。安装完成之后,使用npm run dev来运行测试服务器。这个项目模板支持热重载等特性,所以我们接下来的开发过程可以直接在此基础上进行,不需要重启服务器。这时候我们也可以使用WebStorm的开发工具编辑项目,充分享受IDE带来的便捷。

下面介绍一下模板项目的结构。build和config文件夹存放的是项目的构建文件和配置文件,会有WebPack和npm使用。node_modules是项目所需的模块存放位置。src文件夹下存放着项目所需的源代码,主要是JavaScript和Vue文件。assets文件夹存放的是项目所需的静态文件,例如图片、样式表等。components文件夹是Vue组件的存放位置。App.vue是项目默认的跟组件。main.js是项目的入口JavaScript文件。index.html是项目的默认HTML文件。图里面还有一个sample.html,就是上面我介绍Vue时使用的单HTML文件。

项目结果图

单文件组件

前面介绍了Vue强大的组件功能,但是这种组件是不能扩展的。一般情况下,项目中应该使用单文件组件。在上面创建的项目中,实际上已经包含了一个单文件组件。让我们看看实际的项目应该如何组织这些组件。

先来看看主HTML文件index.html,它的内容很简单。它的真实内容会由WebPack打包进去。一般情况下我们只需要保持不变就好了。当然页面标题之类的属性还是要改的。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>vue-sample</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

然后来看看项目入口文件main.js,它的内容如下。可以看到它的作用很简单,创建根Vue实例,并将根应用组件App注入其中。

import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  components: { App }
})

然后来看看根组件App.vue中写了什么,这是一个单文件组件,它调用了另一个单文件组件<hello-world/>。单文件组件和前面介绍的组件一样,都有一个模板属性,需要注意模板属性中的元素必须有一个根元素,不能出现多个并列的元素。还有一个脚本块,这里是单文件组件中代码逻辑部分,需要注意的是,这个地方必须向外暴露创建Vue实例所需的那个属性对象。这里还有一个样式块,是单文件组件修改样式的地方。

<template>
  <div id="app">
    ![](./assets/logo.png)
    <hello-world/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>

<style>
...
</style>

Vue路由快速入门

安装

最简单的办法就是在前面创建模板项目的时候同时选择使用vue-router。如果没有在创建项目是选择vue-router,就需要手动添加到项目中。

下面用前面创建的没有安装vue-router的模板项目做例子来介绍。首先需要安装vue-router并将其添加到package.json文件中。

npm i -S vue-router

然后创建src/router/index.js文件,并在其中添加如下代码。这样会在全局注册Vue路由组件。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router()

最后在项目入口文件src/main.js中在全局Vue实例中注册路由。

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: {App}
})

这样Vue路由功能就注册好了。

添加路由

下面来添加第一个路由。和Vue实例一样,router实例也可以在构造的时候通过参数来配置。首先在路由构造函数中添加路由属性,每个路由都需要有路径、组件名以及实际组件。

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: HelloWorld
    },
  ],
})

添加好路由之后,为了能让程序随路由变化而显示不同内容,我们还需要使用vue-router预设的组件<router-view/>,它会在运行的时候替换为我们所定义的组件。在这个例子中,只需要将App.vue文件中的hello-world组件替换为router-view即可。

<template>
  <div id="app">
    ![](./assets/logo.png)
    <router-view></router-view>
  </div>
</template>

切换为HTML5历史模式

在使用Vue路由的时候,我们会发现浏览器中的地址长的是这个样子:xxx/#/。这是Vue路由的默认哈希模式,优点就是兼容性强。还有另外一种模式就是HTML历史模式。要使用这种模式很简单,在构造Vue路由的时候,将mode参数设置为history即可。这样一来,浏览器地址栏就会变成正常状态。当然这种模式也有缺点,就是假如后台没配置好,访问某些页面可能会返回404错误。所以具体使用哪种模式还需要自己仔细考虑。

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: HelloWorld
    },
  ],
  mode: 'history'
})

Vue路由相对于Vue核心框架来说,没什么复杂的概念,基本上很容易理解和上手。所以我这里就不做过多介绍了。官方文档介绍的更加完整。

Vue和视图框架

通过以上学习我们可以看到Vue可以算是一个MVVM框架,主要作用就是将前台页面和数据绑定起来。为了做出漂亮的视觉效果,我们还需要和其他视图框架进行集成。

和Bootstrap 4集成

Bootstrap是最著名的前端框架之一,可以帮助我们迅速创建漂亮的页面。现在它的最新版本是4.0.0-beta,基本可以在项目中投入使用了。现在假设我们有一个启用了路由功能的基于WebPack的Vue模板项目,来看看如何安装Bootstrap 4吧。

首先,用npm安装Bootstrap 4和相关的几个依赖包。这里特别注意Bootstrap的版本,这里我们用的是4 。如果不加版本号的话,会安装3的稳定版。不过现在稳定版已经停止更新了,不会再添加任何新功能了,只进行bug修复和维护。

npm install -S bootstrap@4.0.0-beta jquery popper.js

安装好之后,还需要修改WebPack配置文件。在Vue模板中,配置文件有三个,webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.conf.js,分别代表基础配置、开发配置和生产配置。为了让配置在所有条件下生效,我们需要在webpack.base.conf.js中配置。办法也很简单,添加plugins属性和下面的插件即可。如果在该文件中没有导入webpack模块,还需要在开头添加一行const webpack = require('webpack')导入该模块。

  plugins: [
    ...
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery',
        Popper: ['popper.js', 'default'],
      })
    ...
  ]

然后在项目入口文件src/main.js中引入Bootstrap的样式文件和JavaScript文件即可。

import Vue from 'vue'
import App from './App'
import router from './router'
// 引入Bootstrap文件
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
...
})

最后别忘了在index.html中添加Bootstrap的meta标签。

<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

然后在页面中就可以使用Bootstrap样式来开发程序了。

Bootstrap效果图

和ElementUI集成

element-ui是Vue 2.0的一组组件库,可以帮助我们快速开发项目。

首先通过npm安装。

npm i element-ui -S

然后在main.js文件中写入以下内容。

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
import App from './App.vue'

Vue.use(ElementUI)

new Vue({
  el: '#app',
  render: h => h(App)
})

element-ui的效果如图。

element-ui效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容