Vue-music 小知识点

  • Object.assign()

方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

语法
Object.assign(target, ...sources)

具体请参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

  • 数组的空位

数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。

Array(3) // [, , ,]

上面代码中,Array(3)返回一个具有3个空位的数组。

注意,空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点。

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false

上面代码说明,第一个数组的0号位置是有值的,第二个数组的0号位置没有值。
参考:http://es6.ruanyifeng.com/#docs/array

  • fastclickbetter-scroll 点击冲突,只需要给被点击的元素添加一个类: class="needsclick", 最新版本的better-scroll已经解决了这个问题,不用再加class="needsclick"

如:给img标签添加class="needsclick"

<slider>
    <div v-for="item in recommends">
      <a :href="item.linkUrl">
        <I mg class="needsclick" @load="loadImage" :src="item.picUrl">
      </a>
    </div>
</slider>
  • 数组根据标题首字母排序
ret.sort((a, b) => {
   return a.title.charCodeAt(0) - b.title.charCodeAt(0)
})

参考:http://www.w3school.com.cn/jsref/jsref_charCodeAt.asp
以及:music 歌手页面

  • 通过map获取一个新的集合数组
computed: {
      shortcutList() {
      //group:获取到的每一个对象
        return this.data.map((group) => {
          //从0开始,截取一个字符
          return group.title.substr(0, 1)
        })
      }
},
  • 数组过滤 filter()
computed: {
      /* 计算出推荐的数组 */
      positives() {
        return this.ratings.filter((rating) => {
          return rating.rateType === POSITIVE;
        });
      },
      /* 计算出吐槽的数组 */
      negatives() {
        return this.ratings.filter((rating) => {
          return rating.rateType === NEGATIVE;
        });
      }
    },
  • @touch 触碰事件
<div class="list-shortcut" @touchstart.stop.prevent="onShortcutTouchStart" @touchmove.stop.prevent="onShortcutTouchMove"
         @touchend.stop>
      <ul>
        <li v-for="(item, index) in shortcutList" :data-index="index" class="item"
            :class="{'current':currentIndex===index}">{{item}}
        </li>
      </ul>
</div>
  • event.target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素、文档或窗口。

下面的例子可获得触发事件的元素:

<html>
<head>

<script type="text/javascript">
function getEventTrigger(event)
  { 
  x=event.target; 
  alert("The id of the triggered element: "
  + x.id);
  }
</script>

</head>
<body >

<p id="p1" onmousedown="getEventTrigger(event)">
Click on this paragraph. An alert box will
show which element triggered the event.</p>

</body>
</html>
  • Vue.js 定义一个变量,若不想被系统添加set和get方法,可以定义在created()钩子里面

这样,系统就不会去观测该变量值的改变,从而影响双向绑定

created() {
   this.touch = {}
    ......
}
  • better-scroll scrollToElement(), 第一个参数指的是节点,第二个参数:动画时间

下面的例子中,0指的是动画时间为0
这个默认把你所在的那一行滚动到顶部位置!!!

this.$refs.listview.scrollToElement(this.$refs.listGroup[index], 0)
  • methods 方法书写规范

公共方法放在上面,
私有的方法放在下面.
如下图:

    methods: {
      refresh() {
          ......
      },
      scroll(pos) {
          ......
      },
      _calculateHeight() {
          ......
      },
      _scrollTo(index) {
          ......
      }
    },
  • 数据的变化,到dom的变化,大概耗时17ms

所以,一般倒计时20ms后执行需要操作的函数。

watch: {
  data() {
    setTimeout(() => {
          this._calculateHeight()
     }, 20)
  }
}
  • better-scroll的probeType属性默认是1,如果想要在scroll快速滚动的时候,正确的监听scroll,需把该属性设置为3。
  • 设置background-image:url( ),最好写在行内样式里面,不要写在css里.
<div class="bg-image" :style="bgStyle" ref="bgImage">

计算属性:

computed: {
      bgStyle() {
        return `background-image:url(${this.bgImage})`
      }
    },
  • this.$refs.list.$el.style.top = ${this.imageHeight}px

vm.$el : Vue 实例使用的根 DOM 元素, 类型:HTMLElement

this.$refs.list.$el.style.top
  • Math.max(x...) 返回两个指定的数中带有较大的值的那个数。

    Math.PI * 2r : 获取圆的周长


    Math 对象方法
  • js修改样式时,则需要把webkit-xxx也写上,也可以单独封装来实现autoprefix效果,如: vue-music

    注意: width,height 除外

this.$refs.filter.style['backdrop-filter'] = `blur(${blur}px)`
this.$refs.filter.style['webkitBackdrop-filter'] = `blur(${blur}px)`

封装, 创建一个js文件


let elementStyle = document.createElement('div').style

let vendor = (() => {
  let transformNames = {
    webkit: 'webkitTransform',
    Moz: 'MozTransform', // 火狐
    O: 'OTransform', // 欧朋
    ms: 'msTransform', // IE
    standard: 'transform'
  }

  for (let key in transformNames) {
    if (elementStyle[transformNames[key]] !== undefined) {
      return key
    }
  }

  return false
})()

// 在外边调用该方法
export function prefixStyle(style) {
  if (vendor === false) {
    return false
  }

  if (vendor === 'standard') {
    return style
  }

  // vendor 浏览器厂家
  // style.charAt(0).toUpperCase() + style.substr(1) 首字母大写
  return vendor + style.charAt(0).toUpperCase() + style.substr(1)
}

在外边直接调用prefixStyle()函数

  • vue-router 按钮返回上一个界面
this.$router.back()
  • push到子路由
this.$router.push({
   path: `/singer/${singer.id}` // ${singer.id} 为传递的参数
})
  • Vuex 在传递参数时的使用
    • 先在父界面,引入mapMutations 语法糖
      import {mapMutations} from 'vuex'
      
    • 在该界面methods中代理该...mapMutations语法糖
      methods: {
          ...mapMutations({
              setSinger: 'SET_SINGER'
          })
      }
      
    • push界面时,调用上面的setSinger
      this.setSinger(singer)
      
    • 在使用该参数的界面,先引入mapGetters语法糖
      import {mapGetters} from 'vuex'
      
    • 在计算属性中实现...mapGetters()语法糖
      computed: {
        ...mapGetters([
          'singer'
        ])
      }
      
    • 最后就可以愉快的使用了
      this.singer.id 或者 singer.id 看情况决定是否使用this调用
      
  • 创建model 和 class的区别
    • 创建model
      export const playMode = {
           sequence: 0,
           loop: 1,
           random: 2
      }
      
      在外部使用先引入
      import {playMode} from 'common/js/config'
      
      再调用
      mode: playMode.sequence
      
    • 创建class
       export default class Singer {
         constructor({id, name}) {
            this.id = id
            this.name = name
            this.avatar =   `https://y.gtimg.cn/music/photo_new/T001R300x300M000${id}.jpg?max_age=2592000`
         }
      }
      
      class在外部调用时,需要new一个对象
      map.hot.items.push(new Singer({
                name: item.Fsinger_name,
                id: item.Fsinger_mid
      }))
      
  • 事件派发
this.$emit('select', item, index)
  • index : index ,前后一致,可以简写为index,如下面的方法
selectItem(item, index) {
     this.selectPlay({
        list: this.songs,
        index
     })
},
  • 获取屏幕的宽度/高度 window.innerWidth/window.innerHeight
window.innerWidth / window.innerHeight
  • ES6的写法
const {x, y, scale} = this._getPosAndScale()

_getPosAndScale()函数为

_getPosAndScale() {
        const targetWidth = 40
        const paddingLeft = 40
        const paddingBottom = 30
        const paddingTop = 80
        const width = window.innerWidth * 0.8
        const scale = targetWidth / width
        const x = -(window.innerWidth / 2 - paddingLeft)
        const y = window.innerHeight - paddingTop - width / 2 - paddingBottom
        return {
          x,
          y,
          scale
        }
      }
  • Vue 过渡动画transition,可以利用钩子实现一些特殊动画.

动画和过渡的区别 ?
动画:可以不需要触发就可以执行
过渡:需要人为触发

可以学习vue-music音乐内核动画
https://cn.vuejs.org/v2/api/#transition

  • create-keyframe-animation 获取dom的fame,用于实现移动动画,利用Vue.js 之 transition的钩子,可以实现各种复杂的动画.
  • x | 0 代表向下取整
const interval = interval | 0   //代表向下取整
  • 获取拖动等手势 touchstart, touchmove ,touchend
<div class="progress-btn-wrapper" ref="progressBtn"
           @touchstart.prevent="progressTouchStart"
           @touchmove.prevent="progressTouchMove"
           @touchend="progressTouchEnd"
>

实现方法

    created() {
      this.touch = {}
    },
    methods: {
      progressTouchStart(e) {
        this.touch.initiated = true
      //  e.touches[0] 表示第 0 个手指的位置 
        this.touch.startX = e.touches[0].pageX
        this.touch.left = this.$refs.progress.clientWidth
      },
      progressTouchMove(e) {
        if (!this.touch.initiated) {
          return
        }
        const deltaX = e.touches[0].pageX - this.touch.startX
        const offsetWidth = Math.min(this.$refs.progressBar.clientWidth - progressBtnWidth, Math.max(0, this.touch.left + deltaX))
        this._offset(offsetWidth)
      },
      progressTouchEnd() {
        this.touch.initiated = false
        this._triggerPercent()
      },
      _triggerPercent() {
        const barWidth = this.$refs.progressBar.clientWidth - progressBtnWidth
        const percent = this.$refs.progress.clientWidth / barWidth
        this.$emit('percentChange', percent)
      },
  • 通过点击事件,获取位置
<div class="progress-bar" ref="progressBar" @click="progressClick">

实现方法 e.pageX 获取x位置
getBoundingClientRect()用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性。 参考:http://www.cnblogs.com/Songyc/p/4458570.html

progressClick(e) {
        const rect = this.$refs.progressBar.getBoundingClientRect()
        const offsetWidth = e.pageX - rect.left
        this._offset(offsetWidth)
        // 这里当我们点击 progressBtn 的时候,e.offsetX 获取不对
        // this._offset(e.offsetX)
        this._triggerPercent()
},
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

// 洗牌函数
export function shuffle(arr) {
  let _arr = arr.slice()   // 类似于拷贝一个副本,如不这样做,会改变原来(arr)数组的顺序,发生bug
  for (let i = 0; i < _arr.length; i++) {
    let j = getRandomInt(0, i)
    let t = _arr[i]
    _arr[i] = _arr[j]
    _arr[j] = t
  }
  return _arr
}
  • (ES6) array.findIndex(),用于筛选满足某个条件的item所对应的索引;
let index = list.findIndex((item) => {
  // 筛选出当前歌曲id为this.currentSong.id 的item的索引
   return item.id === this.currentSong.id
})
  • 单曲循环播放原理:当这首歌播放完毕的时候,把他的开始时间重设为0即可
      end() {
        if (this.mode === playMode.loop) {
          //单曲循环播放
          this.loop()
        } else {
          this.next()
        }
      },
      loop() {
        this.$refs.audio.currentTime = 0
        this.$refs.audio.play()
        if (this.currentLyric) {
          this.currentLyric.seek(0)
        }
      },
      next() {
        if (!this.songReady) {
          return
        }
        if (this.playlist.length === 1) {
          this.loop()
        } else {
          let index = this.currentIndex + 1
          if (index === this.playlist.length) {
            index = 0
          }
          this.setCurrentIndex(index)
          if (!this.playing) {
            this.togglePlaying()
          }
        }
        this.songReady = false
      },
  • $el的作用:Vue 实例上的 $el 属性才是 DOM
this.$refs.list.$el.style.top = `${this.imageHeight}px` 
和
this.$refs.layer.style[transform] = `translate3d(0,${translateY}px,0)` 
的区别

我们先看一下标签内容

第一个是一个自定义组件,也就是一个Vue实例.
<scroll  ref="list">
 ......
</scroll>

第二个是直接是一个标签
<div class="bg-layer" ref="layer"></div>

也就是说:

一个直接是 DOM,一个是 Vue 的实例,Vue 实例上的 $el 属性才是 DOM。

  • 获取当前的时间戳
+new Date()
  • res.json() : 转换其他的值到json

下面的例子中:res.json(response.data) 把获取到的数据response.data 转化为json赋值给res,是该函数可以在外边调用,获取到json的数据.

apiRoutes.get('/getDiscList', function (req, res) {
  var url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg'
  axios.get(url, {
    headers: {
      referer: 'https://c.y.qq.com/',
      host: 'c.y.qq.com'
    },
    params: req.query
  }).then((response) => {
    res.json(response.data)
  }).catch((e) => {
    console.log(e)
  })
})
  • 如果更改了后端的代码.node 必须重启服务,才能正常显示

下面webpack里面的内容更改,也需要重启服务器.


修改了配置的东西,必须重启服务
  • scroll 中下面两个方法参数的传递

详见vue-music-chapter6scroll.vue组件中的注释

scrollTo() {
        // 滚动到某个位置  时间ms  如:({0, 0}, 1000) 滚动到顶部 1000ms
        this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
},
scrollToElement() {
        // 要滚动到的元素  时间ms
        this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
}
  • mixin.js 用于写一些方法,合并到调用他的组件的方法中,类似于git提交代码>>合并代码

mixin.js文件中实现下面方法

import {mapGetters} from 'vuex'

export const playlistMixin = {
  computed: {
    ...mapGetters([
      'playlist'
    ])
  },
  mounted() {
    this.handlePlaylist(this.playlist)
  },
  // 导航条切换会触发此事件
  activated() {
    this.handlePlaylist(this.playlist)
  },
  watch: {
    playlist(newVal) {
      this.handlePlaylist(newVal)
    }
  },
  methods: {
    handlePlaylist() {
      throw new Error('component must implement handlePlaylist method')
    }
  }
}

在music-list.vue文件中调用

<script type="text/ecmascript-6">
    ......
  import {playlistMixin} from 'common/js/mixin'

  export default {
    // mixins是一个数组
    mixins: [playlistMixin],
      ......
  },
  //在methods中显现该方法:handlePlaylist
  methods: {
    handlePlaylist(playlist) {
        const bottom = playlist.length > 0 ? '60px' : ''
        this.$refs.list.$el.style.bottom = bottom
        this.$refs.list.refresh()
      }
  }
</script>

详细使用请参考vue-music

  • 在子路由界面按F5刷新数据,由于有一些参数是上一级界面传过来的,会导致刷新获取不到数据,此时可以判断从上一个界面的参数存不存在,不存在就返回到上一级界面
methods: {
      _getSongList() {
        if (!this.disc.dissid) {
          this.$router.push('/recommend')
          return
        }
      }
}
  • loading组件,最好用div再包裹一层,如下面:
<div class="loading-container" v-show="!topList.length">
   <loading></loading>
</div>
  • 绝对定位设置居中,如垂直居中设置top: 50% , transform: translateY(-50%),水平居中同理可证;
.list-shortcut
   position: absolute
   z-index: 30
   right: 0
   top: 50%
   transform: translateY(-50%)
  • 设置垂直水平居中,设置top: 50%,left: 50%,transform: translate(-50%, -50%)
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
z-index: 999
  • this.$watch() 和watch钩子的区别:

created() {
      this.$watch('query', debounce((newQuery) => {
        this.$emit('query', newQuery)
      }, 200))
}
  • 数组的截取 slice()

array.slice(0, 10) // 截取数组的前十个;

  • 父组件如何调用子组件的方法?
    • 子组件search-box.vue组件中,有一个方法setQuery(),想在父组件中调用.
      methods: {
         ......
         setQuery(query) {
           this.query = query
         },
         ......
      }
      
    • 父组件先添加ref属性ref="searchBox",在methods钩子中的addQuery()函数使用this.$refs.searchBox.setQuery()调用; 具体使用如下:
      <template>
        <div class="search">
          <div class="search-box-wrapper">
            <search-box ref="searchBox" @query="onQueryChange"></search-box>
          </div>
        </div>
      </template>
      
      methods: {
        addQuery(query) {
          this.$refs.searchBox.setQuery(query)
        }
      }
      
  • 对象的扩展运算符 (...)

扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

这等同于使用Object.assign方法。

let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);

上面的例子只是拷贝了对象实例的属性
... 还有更多功能,请参考:http://es6.ruanyifeng.com/?search=%25E5%25B1%2595%25E5%25BC%2580%25E8%25BF%2590%25E7%25AE%2597%25E7%25AC%25A6&x=0&y=0#docs/object#%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6

  • javascript 中 push和concat的区别
    在javascript中,我们一般都只用push向数组的尾部插入新元素的,但是其实在javascript中还有另外一个方法和push一样,也是向数组尾部插入新元素的,但是他们之间却存在着一定的区别,当我们看下面的代码的时候就明显的知道了:
  1. 通过使用push操作数组:


    push
  2. 通过使用concat操作数组:
    concat

    从上面的两个操作就很明显的看出来push和concat的区别了
    ①. push 遇到数组参数时,把整个数组参数作为一个元素;而 concat 则是拆开数组参数,一个元素一个元素地加进去。
    ②.push 直接改变当前数组;concat 不改变当前数组。

请参考:http://www.cnblogs.com/delin/archive/2010/06/17/1759695.html

  • 搜索页面:输入框快速输入(删除)内容 会导致频繁请求数据, 故做截留处理 debounce():自己封装的函数

请参考:search-box.vue 组件

  • 让输入框失去焦点blur()
<input ref="query" v-model="query" class="box" :placeholder="placeholder"/>

js调用,让键盘下去,让输入框失去焦点

可以在scroll滚动,或者点击方法中调用
this.$refs.query.blur()  // 让移动端输入框失去焦点
  • localStorage 和 sessionStorage 的区别
    • localStorage - 没有时间限制的数据存储。
    • sessionStorage - 针对一个 session 的数据存储(关闭窗口,存储的数据清空) 。
      将数据存到 session中,管你前进后退还是刷新,数据依然在,关闭窗口后再进页面才会清空数据。
  • array.findIndex()

语法: array.findIndex(function())
function() 一般是比较条件

var ages = [3, 10, 18, 20];
 
function checkAdult(age) {
    return age >= 18;
}
 
function myFunction() {
    document.getElementById("demo").innerHTML = ages.findIndex(checkAdult);
}

或者

let index = list.findIndex((item) => {
   return item.id === this.currentSong.id
})
  • better-scroll 使用注意:

下面的写法,scroll的高度获取只能是第一个div的高度,这样是不对的!!!

<scroll>
   <div></div>
   <div></div>
</scroll>
正确的写法:需要用容器包括下
<scroll>
  <div class="scroll-wrapper">
     <div></div>
     <div></div>
  </div>
</scroll>

div1和div2里面放的不同的数据数组,如果想让内容撑开scroll,在计算属性中, 把连个div的数据数组concat在一起,然后给scroll的:data属性赋值即可!
为什么要用计算属性呢? 因为在计算属性中,如果两个div的数据数组有一个发生改变,那么计算属性就会重新计算.故保证了数据的正确性!

  • 阻止事件冒泡

下面的代码,当我们点击wrapper里面的任意一个div时,div的事件都会冒泡到最外面的wrapper上面,从而触发wrapper的点击事件儿.

<div class="wrapper" @click="点击事件儿">
    <div></div>
    <div></div>
</div>

此时要想阻止里面的div事件冒泡到最外层的wrapper上,可以给div添加@click.stop阻止事件冒泡即可!

<div class="wrapper" @click="点击事件儿">
    <div @click.stop></div>
    <div @click.stop></div>
</div>
  • <transition> 和 <transition-group> 的区别?
<transition> 元素作为单个元素/组件的过渡效果。
<transition> 只会把过渡效果应用到其包裹的内容上,而不会额外渲染 DOM 元素,也不会出现在检测过的组件层级中。

<transition-group> 元素作为多个元素/组件的过渡效果。
<transition-group> 渲染一个真实的 DOM 元素。默认渲染 <span>,可以通过 tag 属性配置哪个元素应该被渲染。

transition-group的使用注意事项:

①.需指定tag,如:tag="ul";
②.子元素需设置 :key, 如:<li :key="item.id"></li>

<scroll ref="listContent" :data="sequenceList" class="list-content" >
   <transition-group ref="list" name="list" tag="ul">
      <li :key="item.id" class="item" v-for="(item,index) in sequenceList"
                @click="selectItem(item,index)">
              ......
      </li>
   </transition-group>
</scroll>

详见官方文档

  • scroll里面有动画时,scroll的refresh()应延时,比如transition-group的动画时间是0.1s,那么scroll的refresh()最少延时120ms,才能正确计算高度

:refreshDelay="120" 延时120ms,为什么呢?
因为:transition-group动画时长是100ms, 当从添加歌曲到队列中时,一般情况下,20ms就会执行scroll.refresh()操作,此时动画还没有执行完,会导致scroll的高度计算不对,故 应在动画结束之后再执行refresh()操作,所以延时120ms执行refresh()。

<scroll ref="listContent" :data="sequenceList" class="list-content" :refreshDelay="refreshDelay">
    <transition-group ref="list" name="list" tag="ul">
        <li :key="item.id" class="item" v-for="(item,index) in sequenceList"
              ......
        </li>
   </transition-group>
</scroll>
  • js如何查询某个对象是否在这个数组中?
isFavorite(song) {
      const index = this.favoriteList.findIndex((item) => {
        return item.id === song.id
      })
      return index > -1  // 如果大于-1, 说明存在
}
  • 打出的包比较大,可以使用路由懒加载优化下 : 这样首屏加载的资源就会很少,提交加载速度!!!!

https://router.vuejs.org/zh-cn/advanced/lazy-loading.html

  • 在对Vue.js进行版本升级时,vuevue-template-compiler的版本号必须一致,否则编译报错!!!
"dependencies": {
    "vuex": "^2.3.1",  // 必须一致
     ......
  },
"devDependencies": {
    "vue-template-compiler": "^2.3.3", // 必须一致
}
  • vConsole 一个轻量、可拓展、针对手机网页的前端开发者调试面板。

main.js中调用 ,然后console.log的内容在手机上就可以查看了.

在上线的时候,把import vConsole from 'vconsole'注释掉就可以了

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

推荐阅读更多精彩内容

  • UI组件element ★11612 - 饿了么出品的Vue2的web UI工具套件 Vux ★7503 - 基于...
    董董董董董董董董董大笨蛋阅读 8,503评论 6 123
  • 转载 :OpenDiggawesome-github-vue 是由OpenDigg整理并维护的Vue相关开源项目库...
    果汁密码阅读 23,092评论 8 124
  • 今天来一次文艺范。 今天画了一个绑着枯树冠的女孩。 上了树冠和头发的颜色以及肤色 树冠上的星月和衣服的黑夜。后悔没...
    54b4972e410d阅读 230评论 0 3
  • 【日精进打卡第30天】 姓名:赵福缘 公司:青柠养车 【知~学习】 《大学》一遍 【行~实践】 一、修身: 二、努...
    夜勿忧阅读 110评论 0 0
  • 1)每次在夜空中,看到这颗星球孤独旋转,我心中都会有一种难以名状的依恋和亲切。 Every time I see ...
    紫茎阅读 180评论 1 0