Vue.js组件

  • 组件用于封装页面的部分功能,将功能的结构,样式,逻辑代码封装为整体
  • 提高功能的复用性和可维护性,更好的专注于业务逻辑
  • 组件使用时为自定义HTML标签形式,通过组件名作为自定义标签名
  <div id="app">
    <!-- 普通HTML标签 -->
    <p>p标签内容</p>
    <!-- Vue.js组件 -->
    <my-com></my-com>
  </div>

组件注册

全局注册

  • 全局注册的组件在注册之后可以用于任意实例或者组件中
Vue.component('组件名',{/*选项对象*/});
  • 注意:全局注册必须设置在根Vue实例创建之前
    例子:
<body>
  <div id="app">
    <p>这是p标签</p>
    <my-component></my-component>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('my-component',{
      template : '<div>这是我们全局注册的组件</div>'
    });

    // 根实例
    new Vue({
      el: '#app',
      data: {

      }
    })
  </script>
</body>

组件基础

  • 本质上,组件是可以复用的Vue实例,可以与new Vue接收相同的选项, 比如data,methods,生命周期钩子等等
  • 仅有的例外是像el这样根实例特有的选项

组件命名规则

  • 组件具有两种命名规则:
    • kebab-case:'my-component'(烤串命名法,短横线链接多个单词的命名方式)
    • PascalCase:'MyComponent'(传统命名法,帕斯卡命名法,每部分内容的首字母大写)


      示例
  • 注意:无论采用什么类型的命名方式,在DOM中都只有kebab-case可以使用

template 选项

  • template 选项用于设置组建的结构,最终被引入根实例或者其他组件中


    模板字符串
  • 注意:组件必须只有一个根元素(一个根元素,比如最外层的div就一对)


    设置了两个根元素就会报错

data 选项

  • data 选项用于存储组件的数据,与根实例不同,组件的data 选项必须为函数,数据设置在返回值对象中
  • 这种实现方式是为了确保每个组件实例可以维护一份被返回对象的独立的拷贝,不会相互影响。
    Vue devtools可以看到清晰的结构

局部注册

  • 局部注册的组件只能用在当前实例或组件中


    使用烤串命令法的时候需要加引号
  • 单独配置组件的选项对象:


  • ES6的对象属性简写:


    使用ES6简写的方式的兼容性没有上面的好

组件通信

  • 父组件向子组件传值
  • 子组件向父组件传值
  • 非父子组件传值
  • 其他通信方式

父组件向子组件传值

  • 通过子组件的props选项接收父组件的传值

    注意:props不要和data存在同名的属性,否则会覆盖
  • 父组件设置方式如下:


    第一行是静态属性设置,第二行是动态设置,第三行是动态设置常用操作
<body>
  <div id="app">
    <!-- 静态属性设置 -->
    <my-component-a 
      title="这是静态的标题"
      content="这是静态的内容"
    ></my-component-a>

    <!-- 动态属性绑定 -->
    <my-component-a
      v-bind:title="'这是静态的标题,这是演示'"
      :content="'这是静态内容'"
    ></my-component-a>

    <!-- 动态属性绑定:常用操作 -->
    <my-component-a
      :title="item.title"
      :content="item.content"
    ></my-component-a>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    // 创建子组件
    Vue.component('my-component-a',{
      props : ['title','content'],
      template : `
      <div>
          <h3>{{ title }}</h3>
          <p>{{ content }}</p>
        </div>
      `
    });

    new Vue({
      el: '#app',
      data: {
        item: {
          title: '这是示例标题',
          content: '这是示例内容'
        }
      }
    });
  </script>
</body>

Props命名规则

  • 建议prop命名使用camelCase,父组件绑定时使用kebab-case


<body>
  <div id="app">
    <my-component
      :item-title="item.title"
      :item-content="item.content"
    ></my-component>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('my-component', {
      props: ['itemTitle', 'itemContent'],
      template: `
        <div>
          <h3>{{ itemTitle }}</h3>
          <p>{{ itemContent }}</p>
        </div>
      `
    })
    new Vue({
      el: '#app',
      data: {
        item: {
          title: '这是示例标题',
          content: '这是示例内容'
        }
      }
    })
  </script>
</body> 

props练习

  • 通过v-for创建组件
<body>
  <div id="app">
    <!-- 通过 v-for 遍历数据 items,创建组件并生成内容 -->
    <demo-item
      v-for="item in items"
      :item-title="item.title"
      :item-content="item.content"
      :key="item.id"

      :item="item"
    ></demo-item>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('demoItem', {
      props: ['itemTitle', 'itemContent', 'item'],
      template: `
        <div>
          <h3>{{ itemTitle }}</h3>
          <p> {{ itemContent }} </p>
        </div>
      `
    })

    new Vue({
      el: '#app',
      data: {
        // 准备给子组件使用的数据
        items: [
          {
            id : 1,
            title: '示例标题1',
            content: '示例内容1'
          },
          {
            id : 2,
            title: '示例标题2',
            content: '示例内容2'
          },
          {
            id : 3,
            title: '示例标题3',
            content: '示例内容3'
          },
        ]
      }
    })
  </script>
</body>

单向数据流

  • 父子组件间的所有prop都是单向下行绑定的,不能反向影响父组件
  • 如果子组件要处理prop数据,应当存储在data中再操作


  • 如果prop为数组或者对象的时候,子组件操作将会影响到父组件的状态
<body>
  <div id="app">
    <my-component
      :initial-title="title"
      :obj="obj"
      :arr = 'arr'
    ></my-component>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('my-component', {
      props: ['initialTitle', 'obj','arr'],
      template: `
        <div>
          {{ title }}
          {{ obj }}
          {{ arr }}
          <button @click="fn">按钮</button>
        </div>
      `,
      data () {
        return {
          title: this.initialTitle
        }
      },
      methods: {
        fn () {
          // title只是个字符串,不会反向影响到父组件的状态
          this.title = '这是新的标题';
          // this.initialTitle = '这是新的标题'; // 不会影响父组件
          // obj是对象,会反向影响到父组件
          this.obj.name = 'jack';
          this.obj.age = '20';
          // arr是数组,也会反向影响到父组件
          this.arr[0] = 4;
        }
      }
    });

    new Vue({
      el: '#app',
      data: {
        title: '这是示例标题',
        obj: {
          name: 'william',
          age: 18
        },
        arr : [1,2,3]
      }
    });
  </script>
</body>

props类型

  • Prop 可以设置类型检查,这时需要将 props 更改为一个带有验证需求的对象,并指定对应类型。
如果当前传入的值不满足props类型设置的值,就会弹出警告
  • prop还可以同时指定多个类型,通过数组方式保存就可以了
    String或者Number都可以

    设置这个内容检测仅仅是检测,如果忽略这个错误也是可以渲染内容上去的,所以设置之后要看控制台检查错误

props验证

  • 当 prop 需要设置多种规则时,可以将 prop 的值设置为选项对象
  • 之前的类型检测功能通过 type 选项设置


  • required 用于设置数据为必填项


  • default 用于给可选项指定默认值,当父组件未传递数据时生效


  • 当默认值是数组或者对象的时候,必须为工厂函数返回的形式,避免引用类型在多个组件中产生相互影响的情况


  • validator 用于给传入的 prop 设置校验函数,return 值为false 时 Vue.js 会发出警告

    验证函数中没法使用实例的methods,data等功能

非props属性

  • 当父组件给子组件设置了属性,此属性在props不存在,这时就会自动绑定到子组件的根元素上


    image.png
  • 如果组件根元素已经存在了对应属性,则会替换组件内部的值
  • class 与 style 是例外,当内外都设置时,属性会自动合并


  • 如果不希望继承父组件设置的属性,可以设置inheritAttrs:false,但只适用于普通属性,class 与 style 不受影响


子组件向父组件传值

子组件传向父组件需要通过自定义事件来实现

  • 举个例子:商品为子组件,购物车为父组件,父组件需要统计商品个数,就需要在子组件个数变化时传值给父组件



  • 子组件数据变化时,通过$emit()触发自定义事件


  • 事件的名称建议使用kebab-case命名方式
  • 父组件监听子组件的自定义事件,设置好处理程序


自定义事件传值

  • 子组件触发事件时可以向父组件传值


    第一个参数就是事件名,第二个参数就是传递的数据信息
  • 父组件在监听事件时需要接收子组件传递的数据


  • 也可以写成自定义事件,对应处理的程序


组件与v-model

  • v-model用于组件时,需要通过props与自定义事件实现




    实践案例:

<body>
  <div id="app">
    <p>输入框内容: {{ iptValue }}</p>
    <com-input v-model = 'iptValue'></com-input>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    var comInput = {
      props : ['value'],
      template : `
        <input 
          type="text"
          :value="value"
          @input = "onInput"
          >
      `
      ,
      methods : {
        onInput(event){
          this.$emit('input',event.target.value)
        }
      }
    }

    new Vue({
      el: '#app',
      data: {
        iptValue : ''
      },
      components : {
        comInput
      }
    })
  </script>
</body>

非父子组件传值

什么是非父子组件?兄弟组件或者完全无关的两个组件

兄弟组件传值

兄弟组件之间是可以通过父组件进行数据中转的

<body>
  <div id="app">
    <!-- 父组件接收子组件A的数据 -->
    <com-a
      @value-change="value = $event"
    ></com-a>
    <!-- 父组件将数据传递给子组件B -->
    <com-b
      :value="value"
    ></com-b>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    // 子组件A:发送数据
    Vue.component('ComA', {
      template: `
        <div>
          组件A的内容: {{ value }}
          <button
            @click="$emit('value-change', value)"
          >发送</button>
        </div>
      `,
      data () {
        return {
          value: '这是组件A中的数据'
        }
      }
    });

    // 子组件B:接收数据
    Vue.component('ComB', {
      props: ['value'],
      template: `
        <div>
          组件B接收到: {{ value }}
        </div>  
      `
    });


    // 根实例(父组件)
    new Vue({
      el: '#app',
      data: {
        // 用于数据中转
        value: ''
      }
    })
  </script>
</body>

EventBus

  • 当组件嵌套关系复杂的时候,根据组件关系传值会比较繁琐
  • 如果组件为了数据中转,data中会存在许多与当前组件功能无关的数据
  • EventBus (事件总线)是一个独立的事件中心,用于管理不同组件间的传值操作
  • EventBus 通过一个新的 Vue 实例来管理组件传值操作,组件通过给实例注册事件、调用事件来实现数据传递
// 将新的Vue实例bus存放在一个叫做EventBus.js的文件中
var bus = new Vue();
  • 发送数据的组件触发bus事件,接收的组件给bus注册对应的事件


  • 给 bus 注册对应事件通过 $on() 操作


  • 最后创建根实例执行代码即可

<body>
  <div id="app">
    <h3>购物车</h3>
    <product-item></product-item>
    <product-total></product-total>
  </div>
  <script src="lib/vue.js"></script>
  <!-- 引入EventBus.js要在vue.js引入之后 -->
  <script src="EventBus.js"></script>
  <script>
    // 商品组件
    Vue.component('ProductItem', {
      template: `
        <div>
          <span>商品名称:苹果,商品个数:{{ count }}</span>
          <button
            @click="countIns"
          >+1</button>
        </div>
      `,
      data () {
        return {
          count: 0
        }
      },
      methods: {
        countIns () {
          // 给bus触发自定义事件,传递数据
          bus.$emit('countChange', 1);
          this.count++;
        }
      }
    });

    // 计数组件
    Vue.component('ProductTotal', {
      template: `
        <p>总个数为: {{ totalCount }}</p>
      `,
      data () {
        return {
          totalCount: 0
        }
      },
      created () {
        // 给 bus 注册事件,并接收数据
        bus.$on('countChange', (productCount) => {
          // 实例创建完毕,可以使用 data 等功能
          // 使用箭头函数,直接使用this
          this.totalCount += productCount;
        });

      }
    })

    // 根实例
    new Vue({
      el: '#app',
      data: {

      }
    });
  </script>
</body>

其他通信方式

$root

  • $root 用于访问当前组件树根实例,设置简单的Vue应用时可以通过此方式 进行组件传值


    注册两个局部组件comA和comB

    根据内部的子组件直接访问到了根实例的数据

    进一步证明是根实例的证据:(组件B是子组件A的子组件)

<body>
  <div id="app">
    <com-a></com-a>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    // 根实例的子组件A的子组件B
    var ComB = {
      template: `
        <div>
          组件B: {{ $root.count }}
          <button @click="clickFn">按钮</button>
        </div>
      `,
      methods: {
        clickFn () {
          this.$root.count = 200;
        }
      }
    };

    // 子组件A
    var ComA = {
      template: `
        <div>
          组件A: {{ $root.count }}
          <button @click="clickFn">按钮</button>
          <com-b></com-b>
        </div>
      `,
      methods: {
        clickFn () {
          this.$root.count = 100;
        }
      },
      components: {
        ComB
      }
    };


    // 根实例
    new Vue({
      el: '#app',
      data: {
        count: 0
      },
      components: {
        ComA
      }
    });
  </script>
</body>
  • 除了 $root , Vue.js 中还提供了 $parent$children 用于 便捷访问父子组件

$refs

  • $refs用于获取设置了ref属性的HTML标签或者子组件
  • 给普通HTML标签设置ref属性,$refs可以获取DOM对象
  • 给子组件设置ref属性,渲染后可以通过$refs获取子组件实例
    mouted确认组件已经挂载完毕,生命周期函数

组件插槽

便捷的设置组件内容

单个插槽

  • 如果我们希望组件标签可以像 HTML 标签一样设置内容,那么组件的使用灵活度会很高


  • 但平常我们书写的组件,组件首尾标签中书写的内容会被抛弃


  • 这个时候我们需要通过 <slot> 进行插槽设置


    slot标签就代表了内容区域
  • 需要注意模板内容的渲染位置


    在父组件视图模板中不能使用子组件的数据
  • 我们可以在 <slot> 中为插槽设置默认值,也称为后备内容


具名插槽

  • 如果组件中有多个位置需要设置插槽,据需要给 <slot> 设置name,称为具名插槽



    default可以省略掉



    简写模式:
<body>
  <div id="app">
    <com-a>
      <template v-slot:header>
        <h3>组件的头部内容</h3>
      </template>

      <!-- <template v-slot:default>
        <p>组件的主体内容1</p>
        <p>组件的主体内容2</p>
      </template> -->

      <p>组件的主体内容1</p>
      <p>组件的主体内容2</p>

      <template #footer>
        <p>组件底部内容</p>
      </template>
    </com-a>
  </div>


  <script src="lib/vue.js"></script>
  <script>
    // 子组件 
    Vue.component('ComA', {
      template: `
        <div>
          <header>
            <slot name="header"></slot>
          </header>
          <main>
            <slot></slot>
          </main>
          <footer>
            <slot name="footer"></slot>
          </footer>
        </div>
      `
    });

    new Vue({
      el: '#app',
      data: {

      }
    });
  </script>
</body>

作用域插槽

用于让插槽可以使用子组件的数据

  • 组件将需要被插槽使用的数据通过 v-bind 绑定给 <slot>,这种用于给插槽传递数据的属性称为插槽 prop


  • 组件绑定数据后,插槽中需要通过 v-slot 接收数据


    dataObj指的是所有插槽prop的对象
  • 如果只存在默认插槽,同时又需要接收数据,可以进行简写



    default也是可以省略掉的

    还可以通过 ES6 的解构操作进行数据接收
   <!-- 只具有默认插槽的作用域插槽书写方式 -->
    <!-- <com-b v-slot="dataObj"> -->
    <com-b #default="dataObj">
      {{ dataObj }}
    </com-b>

    <!-- 通过 ES6 的解构操作接收作用域插槽的数据 -->
    <com-b v-slot="{ value, num }">
      {{ value }}
      {{ num }}
    </com-b>

内置组件

动态组件

动态组件适用于多个组件频繁切换的处理

  • <component> 用于将一个‘元组件’渲染为动态组件,以 is 属性值决定渲染哪个组件


    类似于v-if
  • 可以用来实现多个组件的快速切换,比如说选项卡效果
<body>
  <div id="app">
    <!-- 按钮代表选项卡的标题功能 -->
    <button
      v-for="title in titles"
      :key="title"
      @click="currentCom = title"
    >
      {{ title }}
    </button>

    <!-- component 设置动态组件 -->
    <component :is="currentCom"></component>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    // 设置要切换的子组件选项对象
    var ComA = {
      template: `<p>这是组件A的内容:<input type="text"></p>`
    };  
    var ComB = {
      template: `<p>这是组件B的内容:<input type="text"></p>`
    };
    var ComC = {
      template: `<p>这是组件C的内容:<input type="text"></p>`
    };

    new Vue({
      el: '#app',
      data: {
        // 所有组件名称
        titles: ['ComA', 'ComB', 'ComC'],
        // 当前组件名称
        currentCom: 'ComA'
      },
      components: {
        ComA, ComB, ComC
      }
    });
  </script>
</body>

is 属性会在每次切换组件时,Vue 都会创建一个新的组件实例意思就是销毁了再创建,无法进行保留

keep-alive组件

主要用于保留组件状态或避免组件重新渲染


  • include 属性用于指定哪些组件会被缓存,具有多种设置方式


    第一种方式,注意,每一个组件之间是不能有空格的

    第二种

    第三种,正则表达式
  • exclude 属性用于指定哪些组件不会被缓存


  • max属性用于设置最大的缓存数


    值得一提的是,不是选择与否,而是参与缓存就算一次

过渡组件

用于在Vue插入,更新,或者移除DOM的时候,提供多种不同方式的应用过渡,动画效果

transition组件
  • 用于给元素和组件添加进入/离开过渡
    • 条件渲染(v-if)
    • 条件展示(使用v-show)
    • 动态组件
    • 组件根节点
  • 组件提供了6个class,用于设置过渡的具体效果
  • 进入的类名:
    • v-enter
    • v-enter-to
    • v-enter-active
  • 离开的类名
    • v-leave
    • v-leave-to
    • v-leave-active
<style>
    /* 用于设置出场的最终状态 */
    .v-leave-to {
      opacity: 0;
    }

    /* 用于设置过渡的执行过程 */
    .v-leave-active {
      transition: opacity 1s;
    }

    /* 用于设置入场的初始状态 */
    .v-enter {
      opacity: 0;
    }

    /* 用于设置入场的最终状态 */
    .v-enter-to {
      opacity: 0.5;
    }

    /* 用于设置入场的过程 */
    .v-enter-active {
      transition: all 1s;
    }
  </style>
<body>
  <div id="app">
    <button @click="show = !show">切换</button>

    <transition>
      <p v-if="show">hello world</p>
    </transition>
  </div>  
  <script src="./lib/vue.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: {
        show: true
      }
    });
  </script>
</body>
transition组件
  • 给组件设置name属性,可以给多个元素,组件设置不同的过渡效果,需要将v-更改为name-的形式
    比如:
    <transition name="demo"> 的对应类名前缀为:

    • demo-enter
    • demo-leave....等等
  • 通过 appear 属性,可以让组件在初始渲染时实现过渡


自定义过渡类名

自定义类名比普通类名优先级更高,在使用第三方 CSS 动画库时非常有用

  • 用于设置自定义过渡类名的属性如下
    • enter-class
    • enter-active-class
    • enter-to-class
    • leave-class
    • leave-active-class
    • leave-to-class
  • 用于设置初始过渡类名的属性如下
    • appear-class
    • appear-to-class
    • appear-active-class
  <style>
    .v-enter, .v-leave-to {
      opacity: 0;
    }

    .v-enter-active, .v-leave-active {
      transition: all .5s;
    }

/* 自定义过渡效果优先级更高 */
    .test {
      transition: all 3s;
    }

  </style>
</head>
<body>
  <div id="app">
    <button @click="show = !show">切换</button>

    <transition
      enter-active-class="test"
      leave-active-class="test"
    >
      <p v-if="show">这是 p 标签</p>
    </transition>
  </div>  
  <script src="./lib/vue.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: {
        show: true
      }
    });
  </script>
</body>

Animate.css 是一个第三方 CSS 动画库,通过设置类名来给元素添加各种动画效果
使用注意

  • animate_ 前缀与compat版本
  • 基础类名animated
    使用animate.css的一个简单案例:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
  />

  <!-- 不需要添加 animate__ 的兼容版本,但是官方建议使用完整版本 -->
  <!-- "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.compat.css" -->
</head>
<body>
  <div id="app">
    <button @click="show = !show">按钮</button>

    <!-- 通过自定义过渡类名设置,给组件添加第三方动画库的类名效果 -->
    <transition
      enter-active-class="animate__bounceInDown"
      leave-active-class="animate__bounceOutDown"
    >
      <!-- 必须给要使用动画的元素设置基础类名 animate__animated -->
      <p 
        v-if="show"
        class="animate__animated"  
      >hello world</p>
    </transition>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: {
        show: true
      }
    });
  </script>
</body>
</html>

transition-group组件

  • <transition-group> 用于给列表统一设置过渡动画
    • tag属性用于设置容器元素,默认为<span>
    • 过渡会应用于内部元素,而不是容器
    • 子节点必须要有独立的key,动画才能正常工作
  • 当列表元素变更导致元素位移,可以使用.v-move类名设置移动时的效果
    列表移除添加小案例:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    ul {
      position: relative;
    }

    .v-enter, .v-leave-to {
      opacity: 0;
      transform: translateX(100px);
    }

    .v-enter-active, .v-leave-active {
      transition: all .5s;
    }

    /* 让元素在离场的过程中脱离标准流 */
    .v-leave-active {
      position: absolute;
    }

    .v-move {
      transition: all .5s;
    }

  </style>
</head>
<body>
  <div id="app">
    <input type="text"
      v-model="newTitle"
      @keyup.enter="addItem"
    >

    <transition-group
      tag="ul"
    >
      <li
        v-for="item in items"
        :key="item.id"
        @click="removeItem(item)"
      >
        {{ item.title }}
      </li>
    </transition-group>
  </div>  
  <script src="./lib/vue.js"></script>
  <script>
    new Vue({
      el: '#app',
      data: {
        items: [
          { id: 1, title: '示例内容1'},
          { id: 2, title: '示例内容2'},
          { id: 3, title: '示例内容3'},
          { id: 4, title: '示例内容4'},
          { id: 5, title: '示例内容5'},
        ],
        newTitle: '',
        latestId: 5
      },
      methods: {
        addItem () {
          this.items.push({
            id: this.latestId + 1,
            title: this.newTitle
          });
          this.latestId++;
          this.newTitle = '';
        },
        removeItem (item) {
          var i = this.items.indexOf(item);
          this.items.splice(i, 1);
        }
      }
    });
  </script>
</body>
</html>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容