antd vue select 实现组件多选

效果图

组件的引用

<Multiplecascader

          :value="arrData"

          :allowClear="true"

          placeholder="请选择"

          :selectOptionsConfig="{

            key: 'code',

            value: 'code',

            text: 'name',

            children: 'child',

          }"

          allText=""

          noDataText="暂无数据"

          :treeData="binData"

          @change="change"

        />

      </div>

<script>

import Multiplecascader from "@/components/MultipleCascader/index.vue";

export default {

  name: "personSelect",

  data() {

binData:[

           {"name":"AA","code":"AA",

         "child":[

                     {"name":"BB","code":"BB","child":[]},

                    {"name":"CC","code":"CC","child":[]},

                    {"name":"DD","code":"DD","child":[]}

                  ]

              }

           ],

arrData:[],

}

}

<script/>


组件的代码


<template>

  <div

    class="gb-ant-select-multiple-cascader"

    :class="{ 'multiple-cascader-outside': !isClickOutSide }"

    v-clickoutside="handleDropDownOutSide"

  >

    <a-select

      v-bind="$attrs"

      mode="multiple"

      :maxTagTextLength="maxTagTextLength"

      :maxTagCount="maxTagCount"

      style="width: 100%"

      :placeholder="placeholder"

      :value="selectedValueArr"

      :notFoundContent="null"

      :open="isOpen"

      showArrow

      :allowClear="allowClear"

      optionLabelProp="text"

      :dropdownMatchSelectWidth="false"

      :getPopupContainer="(tirggerNode) => tirggerNode.parentNode"

      @focus="handleFocus"

      @deselect="handleDeselect"

    >

      <a-icon

        type="close-circle"

        slot="clearIcon"

        theme="filled"

        @click="handleClearAll"

      />

      <template slot="dropdownRender" slot-scope="menu">

        <v-nodes :vnodes="menu" />

        <div :class="dropdownClassName">

          <div class="cascader-not-content" v-if="treeDataList.length <= 0">

            <a-empty :image="simpleImage" :description="noDataText"></a-empty>

          </div>

          <div class="cascader-content-wrap" v-else>

            <div class="cascader-content-container">

              <ul

                class="cascader-content-list"

                v-for="(itemList, levelIndex) in treeDataList"

                :key="levelIndex"

              >

                <li

                  class="cascader-content-item"

                  v-for="(subItem, subIndex) in itemList"

                  :key="subItem[selectOptionsConfig.key]"

                  :title="subItem[selectOptionsConfig.text]"

                  :class="{ 'cascader-content-item-active': subItem.$active }"

                  @click="

                    handleCascaderItemClick(subItem, subIndex, levelIndex)

                  "

                >

                  <a-checkbox

                    :indeterminate="!!subItem.$indeterminate"

                    :checked="!!subItem.$checked"

                    @click.self="

                      (e) => handleCheckClick(e, subItem, subIndex, levelIndex)

                    "

                  />

                  <span class="checkbox-text">

                    {{ subItem[selectOptionsConfig.text] }}</span

                  >

                  <a-icon

                    type="right"

                    style="font-size: 10px"

                    v-if="

                      subItem[selectOptionsConfig.children] &&

                      subItem[selectOptionsConfig.children].length > 0

                    "

                  />

                </li>

              </ul>

            </div>

          </div>

        </div>

      </template>

      <a-select-option

        v-for="item in treeToList"

        :key="item[selectOptionsConfig.key]"

        :value="item[selectOptionsConfig.value]"

        :text="item[selectOptionsConfig.text]"

      >

        {{ item[selectOptionsConfig.text] }}

      </a-select-option>

    </a-select>

  </div>

</template>

<script>

import { Empty } from "ant-design-vue";

import { cloneDeep } from "lodash";

const clickoutside = {

  // 初始化指令

  bind(el, binding) {

    function documentHandler(e) {

      if (el.contains(e.target)) {

        return false;

      }

      if (binding.expression) {

        binding.value(e);

      }

    }

    el.__vueClickOutside__ = documentHandler;

    document.addEventListener("click", documentHandler);

  },

  update() {},

  unbind(el) {

    document.removeEventListener("click", el.__vueClickOutside__);

    delete el.__vueClickOutside__;

  },

};

export default {

  name: "gbAntSelectMultipleCascader",

  components: {

    VNodes: {

      functional: true,

      render: (h, ctx) => {

        return ctx.props.vnodes;

      },

    },

  },

  directives: { clickoutside },

  props: {

    allowClear: {

      type: Boolean,

      default: true,

    },

    allText: {

      type: String,

      default: "全部",

    },

    noDataText: {

      type: String,

      default: "暂无数据",

    },

    treeData: {

      type: Array,

      default: () => {

        return [];

      },

    },

    dropdownClassName: {

      type: String,

    },

    selectOptionsConfig: {

      type: Object,

      default: () => {

        return {

          key: "id",

          value: "value",

          text: "title",

          children: "children",

        };

      },

    },

    maxTagCount: {

      type: Number,

    },

    maxTagTextLength: {

      type: Number,

    },

    placeholder: {

      type: String,

      default: "请搜索",

    },

    checkAll: {

      type: Boolean,

      default: false,

    },

    value: {

      type: Array,

    },

  },

  beforeCreate() {

    this.simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;

  },

  destroyed() {

    this.timer && clearInterval(this.timer);

  },

  data() {

    return {

      isOpen: false,

      isCheckAll: this.checkAll,

      isIndeterminateAll: false,

      isClickOutSide: true,

      selectedValueArr: this.value || undefined,

      treeDataList: cloneDeep(this.treeData),

      treeToList: [],

    };

  },

  watch: {

    checkAll: {

      handler(newVal) {

        if (newVal) {

          this.timer = setInterval(() => {

            if (this.treeDataList.length > 0) {

              clearInterval(this.timer);

              this.handleCascaderAllItemClick(true);

            }

          }, 30);

        }

      },

      immediate: true,

    },

    value(newVal) {

      // console.log(667,newVal,this.treeData)

      this.selectedValueArr = newVal;

      // this.treeDataList = this.treeData;

      this.initDefaultKeys(newVal, this.treeDataList);

      return newVal;

    },

    treeData(newVal) {

      this.treeListToArrList(newVal[0]);

      this.initDefaultKeys(this.selectedValueArr, newVal);

      this.treeDataList = newVal;

      return newVal;

    },

    //打开组件

    isOpen(newVal) {

      //打开为true 并且 没有选择

      if (newVal && !this.value.length) {

        //执行清空操作

        this.handleClearAll();

        this.isOpen = true;

      }

    },

  },

  methods: {

    handleClearAll() {

      this.treeDataList = this.treeData;

      this.isOpen = false;

      this.isCheckAll = false;

      this.isClickOutSide = true;

      this.isIndeterminateAll = false;

      this.updatePostData();

    },

    initDefaultKeys(selectedArr, treeDataList) {

      if (

        selectedArr &&

        selectedArr.length > 0 &&

        treeDataList &&

        treeDataList.length > 0

      ) {

        const treeDataListClone = cloneDeep(treeDataList);

        const treeToListClone = cloneDeep(this.treeToList);

        selectedArr.forEach((item) => {

          const curretnItemList = [];

          this.findKeysItem(treeDataListClone[0], item, curretnItemList);

          let currentItem = {};

          if (curretnItemList.length > 0) {

            currentItem = curretnItemList[0];

          }

          if (

            !treeToListClone.find(

              (listItem) =>

                listItem[this.selectOptionsConfig.value] ===

                currentItem[this.selectOptionsConfig.value]

            )

          ) {

            treeToListClone.push(currentItem);

          }

          currentItem.$checked = true;

          if (

            currentItem[this.selectOptionsConfig.children] &&

            currentItem[this.selectOptionsConfig.children].length > 0

          ) {

            this.setAllDataTreeChecked(

              currentItem[this.selectOptionsConfig.children],

              true

            );

          }

        });

        this.setCheckBoxIndeteriminate(treeDataListClone[0]);

        this.$nextTick(() => {

          this.treeToList = treeToListClone;

          this.treeDataList = treeDataListClone;

        });

      }

    },

    handleCascaderAllItemClick(checkAll) {

      const treeDataListClone = cloneDeep(this.treeDataList);

      if (checkAll) {

        this.setAllDataTreeChecked(treeDataListClone[0], checkAll);

      } else {

        this.setAllDataTreeChecked(treeDataListClone[0], !this.isCheckAll);

      }

      this.clearAllDataActive(treeDataListClone[0]);

      this.setCheckBoxIndeteriminate(treeDataListClone[0]);

      this.treeDataList = treeDataListClone;

      this.updatePostData();

    },

    handleDeselect(value) {

      const treeDataListClone = cloneDeep(this.treeDataList);

      const currentItemList = [];

      this.findKeysItem(treeDataListClone[0], value, currentItemList);

      let currentItem = {};

      if (currentItemList.length > 0) {

        currentItem = currentItemList[0];

      }

      currentItem.$checked = false;

      currentItem.$active = false;

      if (

        currentItem[this.selectOptionsConfig.children] &&

        currentItem[this.selectOptionsConfig.children].length > 0

      ) {

        this.setAllDataTreeChecked(

          currentItem[this.selectOptionsConfig.children],

          false

        );

      }

      this.setCheckBoxIndeteriminate(treeDataListClone[0]);

      this.treeDataList = treeDataListClone;

      this.updatePostData();

    },

    handleCheckClick(e, item, index, levelIndex) {

      const treeDataListClone = cloneDeep(this.treeDataList);

      const childrenTag = this.selectOptionsConfig.children;

      const valueTag = this.selectOptionsConfig.value;

      const currentItemList = [];

      this.findKeysItem(treeDataListClone[0], item[valueTag], currentItemList);

      let currentItem = {};

      if (currentItemList.length > 0) {

        currentItem = currentItemList[0];

      }

      e.stopPropagation();

      e.cancelBubble = true;

      const checked = e.target.checked;

      if (!currentItem.$active && levelIndex !== treeDataListClone.length - 1) {

        // 清空所有选中状态

        this.clearAllDataActive(treeDataListClone[0]);

      }

      if (currentItem[childrenTag] && currentItem[childrenTag].length > 0) {

        // 可展开

        if (!currentItem.$active) {

          const nextIndex = levelIndex + 1;

          if (treeDataListClone[nextIndex]) {

            treeDataListClone.splice(nextIndex);

          }

        }

      } else {

        // 不可展开

        const nextIndex = levelIndex + 1;

        if (treeDataListClone[nextIndex]) {

          treeDataListClone.splice(nextIndex);

        }

      }

      if (currentItem[childrenTag] && currentItem[childrenTag].length > 0) {

        this.setAllDataTreeChecked(currentItem[childrenTag], checked);

      } else {

        currentItem.$checked = checked;

      }

      this.setCheckBoxIndeteriminate(treeDataListClone[0]);

      this.treeDataList = treeDataListClone;

      this.updatePostData();

    },

    // 单个item点击事件

    handleCascaderItemClick(item, index, levelIndex) {

      const treeDataListClone = cloneDeep(this.treeDataList);

      const childrenTag = this.selectOptionsConfig.children;

      const valueTag = this.selectOptionsConfig.value;

      const currentItemList = [];

      this.findKeysItem(treeDataListClone[0], item[valueTag], currentItemList);

      let currentItem = {};

      if (currentItemList.length > 0) {

        currentItem = currentItemList[0];

      }

      const parentItemsList = [];

      this.findAllParentItems(

        currentItem[valueTag],

        treeDataListClone[0],

        treeDataListClone[0],

        parentItemsList

      );

      parentItemsList.push(currentItem);

      this.clearAllDataActive(treeDataListClone[0]);

      parentItemsList.forEach((activeItem) => {

        if (activeItem[childrenTag] && activeItem[childrenTag].length > 0) {

          activeItem.$active = true;

        }

      });

      if (currentItem[childrenTag] && currentItem[childrenTag].length > 0) {

        const nextIndex = levelIndex + 1;

        if (treeDataListClone[nextIndex]) {

          treeDataListClone.splice(nextIndex);

          treeDataListClone[nextIndex] = currentItem[childrenTag];

        } else {

          treeDataListClone.push(currentItem[childrenTag]);

        }

        this.addHideSelectedList(currentItem[childrenTag]);

      } else {

        const nextIndex = levelIndex + 1;

        if (treeDataListClone[nextIndex]) {

          treeDataListClone.splice(nextIndex);

        }

        currentItem.$checked = !currentItem.$checked;

      }

      this.setCheckBoxIndeteriminate(treeDataListClone[0]);

      this.treeDataList = treeDataListClone;

      this.updatePostData();

    },

    handleFocus() {

      this.isOpen = true;

      this.isClickOutSide = false;

    },

    updatePostData() {

      const that = this;

      const childrenTag = that.selectOptionsConfig.children;

      const valueTag = that.selectOptionsConfig.value;

      const selectedValueArr = [];

      _getAllItemChecked(that.treeDataList[0]);

      that.$emit("change", selectedValueArr);

      function _getAllItemChecked(treeDataList) {

        let parentItem;

        treeDataList.forEach((item) => {

          if (item[childrenTag] && item[childrenTag].length > 0) {

            parentItem = item;

            const currentCheckedAll = [];

            const currentCheckedAllItems = [];

            _getSubChecked(parentItem[childrenTag], currentCheckedAll);

            that.getSubCheckedItems(

              parentItem[childrenTag],

              currentCheckedAllItems,

              childrenTag

            );

            // _getSubCheckedItems(

            //  parentItem[childrenTag],

            //  currentCheckedAllItems

            // );

            if (currentCheckedAll.every((checkItem) => checkItem === true)) {

              if (parentItem[valueTag]) {

                selectedValueArr.push(parentItem[valueTag]);

              }

            } else if (

              currentCheckedAll.some((checkItem) => checkItem === true)

            ) {

              currentCheckedAllItems.forEach((selectedItem) => {

                if (selectedItem[valueTag]) {

                  selectedValueArr.push(selectedItem[valueTag]);

                }

              });

            }

          } else {

            if (item.$checked) {

              selectedValueArr.push(item.code);

            }

          }

        });

      }

      function _getSubChecked(itemList, arr) {

        itemList.forEach((item) => {

          arr.push(!!item.$checked);

          if (item[childrenTag] && item[childrenTag].length > 0) {

            _getSubChecked(item[childrenTag], arr);

          }

        });

      }

      // function _getSubCheckedItems(itemList, arr) {

      //  itemList.forEach((item) => {

      //    if (item.$checked) {

      //      arr.push(item);

      //    } else {

      //      if (item[childrenTag] && item[childrenTag].length > 0) {

      //        _getSubCheckedItems(item[childrenTag], arr);

      //      }

      //    }

      //  });

      // }

    },

    getSubCheckedItems(itemList, arr, childrenTag) {

      itemList.forEach((item) => {

        if (item.$checked) {

          arr.push(item);

        } else {

          if (item[childrenTag] && item[childrenTag].length > 0) {

            this.getSubCheckedItems(item[childrenTag], arr, childrenTag);

          }

        }

      });

    },

    // 点击组件外部区域

    handleDropDownOutSide() {

      this.isOpen = false;

      this.isClickOutSide = true;

    },

    // 设置当前的选中框的全选等状态

    setCheckBoxIndeteriminate(treeDataList) {

      const that = this;

      const childrenTag = that.selectOptionsConfig.children;

      _getAllItemChecked(treeDataList);

      const checkedAllArr = [];

      that.getAllItemCheckedAll(treeDataList, checkedAllArr, childrenTag);

      // _getAllItemCheckedAll(treeDataList, checkedAllArr);

      if (checkedAllArr.every((item) => item === true)) {

        that.isCheckAll = true;

        that.isIndeterminateAll = false;

      } else if (checkedAllArr.some((item) => item === true)) {

        that.isCheckAll = false;

        that.isIndeterminateAll = true;

      } else if (checkedAllArr.every((item) => item === false)) {

        that.isCheckAll = false;

        that.isIndeterminateAll = false;

      }

      // function _getAllItemCheckedAll(itemList, arr) {

      //  itemList.forEach((item) => {

      //    arr.push(!!item.$checked);

      //    if (item[childrenTag] && item[childrenTag].length > 0) {

      //      _getAllItemCheckedAll(item[childrenTag], arr);

      //    }

      //  });

      // }

      function _getAllItemChecked(treeDataList) {

        let parentItem;

        treeDataList.forEach((item) => {

          if (item[childrenTag] && item[childrenTag].length > 0) {

            parentItem = item;

            _getAllItemChecked(item[childrenTag]);

            const currentCheckedAll = [];

            that.getSubChecked(

              parentItem[childrenTag],

              currentCheckedAll,

              childrenTag

            );

            // _getSubChecked(parentItem[childrenTag], currentCheckedAll);

            if (currentCheckedAll.every((checkItem) => checkItem === true)) {

              parentItem.$checked = true;

              parentItem.$indeterminate = false;

            } else if (

              currentCheckedAll.some((checkItem) => checkItem === true)

            ) {

              parentItem.$checked = false;

              parentItem.$indeterminate = true;

            } else if (

              currentCheckedAll.every((checkItem) => checkItem === false)

            ) {

              parentItem.$checked = false;

              parentItem.$indeterminate = false;

            }

          }

        });

      }

      // function _getSubChecked(itemList, arr) {

      //  itemList.forEach((item) => {

      //    arr.push(!!item.$checked);

      //    if (item[childrenTag] && item[childrenTag].length > 0) {

      //      _getSubChecked(item[childrenTag], arr);

      //    }

      //  });

      // }

    },

    getAllItemCheckedAll(itemList, arr, childrenTag) {

      itemList.forEach((item) => {

        arr.push(!!item.$checked);

        if (item[childrenTag] && item[childrenTag].length > 0) {

          this.getAllItemCheckedAll(item[childrenTag], arr, childrenTag);

        }

      });

    },

    getSubChecked(itemList, arr, childrenTag) {

      itemList.forEach((item) => {

        arr.push(!!item.$checked);

        if (item[childrenTag] && item[childrenTag].length > 0) {

          this.getSubChecked(item[childrenTag], arr, childrenTag);

        }

      });

    },

    // 设置所有选中和非选中

    setAllDataTreeChecked(treeList, checked) {

      const childrenTag = this.selectOptionsConfig.children;

      treeList.forEach((item) => {

        item.$checked = checked;

        if (item[childrenTag] && item[childrenTag].length > 0) {

          this.setAllDataTreeChecked(item[childrenTag], checked);

        } else {

        }

      });

    },

    // 清空所有的active状态

    clearAllDataActive(treeList) {

      const childrenTag = this.selectOptionsConfig.children;

      treeList.forEach((item) => {

        item.$active = false;

        if (item[childrenTag] && item[childrenTag].length > 0) {

          this.clearAllDataActive(item[childrenTag]);

        }

      });

    },

    findKeysItem(treeDataList, currentKey, currentItem) {

      const childrenTag = this.selectOptionsConfig.children;

      treeDataList.forEach((item) => {

        if (item[this.selectOptionsConfig.value] === currentKey) {

          currentItem.push(item);

        } else {

          if (item[childrenTag] && item[childrenTag].length > 0) {

            this.findKeysItem(item[childrenTag], currentKey, currentItem);

          }

        }

      });

    },

    findAllParentItems(

      currentKey,

      treeDataList,

      originTreeDataList,

      parentItemsList,

      parentItem,

      parentItemsHasKey

    ) {

      if (parentItem && parentItemsHasKey) {

        parentItemsList.unshift(parentItem);

        this.findAllParentItems(

          parentItem[this.selectOptionsConfig.value],

          treeDataList,

          originTreeDataList,

          parentItemsList

        );

      } else {

        this.findKeysAndParentItem(

          currentKey,

          treeDataList,

          originTreeDataList,

          parentItemsList,

          parentItem,

          parentItemsHasKey

        );

      }

    },

    findKeysAndParentItem(

      currentKey,

      treeDataList,

      originTreeDataList,

      parentItemsList,

      parentItem

    ) {

      const childrenTag = this.selectOptionsConfig.children;

      treeDataList.forEach((item) => {

        if (item[this.selectOptionsConfig.value] === currentKey && parentItem) {

          this.findAllParentItems(

            parentItem[this.selectOptionsConfig.value],

            originTreeDataList,

            originTreeDataList,

            parentItemsList,

            parentItem,

            true

          );

        } else {

          if (item[childrenTag] && item[childrenTag].length > 0) {

            this.findKeysAndParentItem(

              currentKey,

              item[childrenTag],

              originTreeDataList,

              parentItemsList,

              item

            );

          }

        }

      });

    },

    // 将树形结构数据转换成平面结构

    treeListToArrList(treeList) {

      const arrList = [];

      if (treeList && treeList[0]) {

        treeList.forEach((item) => {

          arrList.push(item);

        });

        this.treeToList = arrList;

      }

    },

    addHideSelectedList(treeList) {

      const treeToListClone = Array.from(this.treeToList);

      treeList.forEach((item) => {

        if (

          !treeToListClone.find(

            (listItem) =>

              listItem[this.selectOptionsConfig.value] ===

              item[this.selectOptionsConfig.value]

          )

        ) {

          treeToListClone.push(item);

        }

      });

      this.treeToList = treeToListClone;

    },

  },

};

</script>

<style lang="less">

.gb-ant-select-multiple-cascader {

  .ant-select-dropdown-menu-item {

    display: none;

  }

  .cascader-content-item {

    .checkbox-text {

      padding-left: 8px;

      font-size: 12px;

      color: #4a4a4a;

      cursor: default;

      flex: 1;

      overflow: hidden;

      text-overflow: ellipsis;

      white-space: nowrap;

      text-align: left;

    }

    &.cascader-content-item-active {

      background-color: rgba(66, 70, 86, 0.05);

      .checkbox-text {

        color: #1d47aa;

      }

    }

    .ant-checkbox-wrapper {

      .ant-checkbox-indeterminate {

        .ant-checkbox-inner {

          &:after {

            background-color: #1d47aa;

            left: 48%;

          }

        }

      }

      .ant-checkbox-inner {

        width: 14px;

        height: 14px;

        background-color: #fff;

        border-color: #7d8292;

        &:after {

          border-color: #1d47aa;

          left: 20%;

        }

      }

    }

  }

  .ant-select-dropdown--multiple {

    min-width: auto !important;

  }

  &.multiple-cascader-outside {

    .ant-select-arrow {

      transform: rotate(180deg);

    }

  }

  .ant-select-arrow {

    margin-top: -8px;

    transition: transform 0.3s;

  }

  .ant-select-dropdown-menu-root {

    display: none;

  }

  .cascader-content-right {

    .right-wrap {

      .ant-checkbox {

        top: 0;

      }

    }

  }

}

</style>

<style lang="less" scoped>

.gb-ant-select-multiple-cascader {

  position: relative;

  .cascader-content-wrap {

    height: 100%;

    .cascader-content-container {

      display: flex;

      flex-direction: row;

      .cascader-content-list {

        list-style: none;

        // padding: 0;

        margin: 0;

        width: 153px;

        box-sizing: border-box;

        padding: 11px 0;

        max-height: 160px;

        overflow-y: auto;

        border-right: 1px solid rgba(222, 223, 226, 0.3);

        .cascader-content-item {

          padding: 5px 16px;

          margin-top: 5px;

          display: flex;

          flex-direction: row;

          align-items: center;

          line-height: 1;

          &:hover {

            background-color: rgba(66, 70, 86, 0.05);

          }

        }

      }

    }

  }

  .cascader-not-content {

    padding: 10px;

  }

}

</style>

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

推荐阅读更多精彩内容