Vite+TS+Vue3.0 笔记一

  • Vite工具和Vue都可以创建Vu3项目,Vite运行编译更快,几乎瞬间可以完成。
  • Vue3.0的.vue文件可以不用根标签包裹。

ref数据响应式和Ref对象

  • ref响应需要用到.value赋值,不可直接赋值
<script setup lang="ts">
    import { ref,Ref } from "vue";
    let msg: Ref<string> = ref('小松')
    const changeMsg = () => {
        msg.value = '小虎'
        console.log(msg);
        
    }
</script>

<template>
    <button @click="changeMsg">change</button>
    <div>{{ msg }}</div>
</template>

isRef用于判断是否为Ref对象

<script setup lang="ts">
    import { ref,Ref,isRef } from "vue";
    let msg: Ref<string> = ref('小松')
    let notRef: number = 1
    const changeMsg = () => {
        msg.value = '小虎'
        console.log(isRef(msg)); //true
        console.log(isRef(notRef)); //false
        
    }
</script>

<template>
    <button @click="changeMsg">change</button>
    <div>{{ msg }}</div>
</template>

shallowRef包装对象,节省性能,对应对象的属性

<script setup lang="ts">
    import { shallowRef } from "vue";
    let msg = shallowRef({
        name: '小松'
    })
    
    const changeMsg = () => {
        msg.value = {
            name: '大松'
        }
    }
</script>

<template>
    <button @click="changeMsg">change</button>
    <div>{{ msg }}</div>
</template>

triggerRef强制更新dom

<script setup lang="ts">
    import { shallowRef,triggerRef } from "vue";
    let msg = shallowRef({
        name: '小松'
    })
    
    const changeMsg = () => {
        // msg.value = {
        //     name: '大松'
        // }
        msg.value.name = '大送'
        triggerRef(msg)
    }
</script>

自定义customRef

<script setup lang="ts">
import { customRef } from "vue";
    function MyRef<T>(value:T) { //T是泛型
        return customRef((trank,trigger) => {
            return {
                get () {
                    trank()
                    return value
                },
                set(newVal: T) {
                    console.log('SET');
                    value = newVal
                    trigger()
                }
            }
        })
    }
    let msg = MyRef<string>('小曼')
    const changeMsg = () => {
        msg.value = '大满'
    }
</script>

<template>
    <button @click="changeMsg">change</button>
    <div>{{ msg }}</div>
</template>

shallowRef和triggerRef结合使用

<script setup lang="ts">
import { shallowRef,triggerRef } from "vue";
const msg = shallowRef({
    foo:'小送',
    bar:'小西'
})
const changeMsg = () => {
    msg.value.foo = 'xiaoman'
    console.log(msg);
    
}
</script>

<template>
    <button @click="changeMsg">change</button>
    <div>{{ msg }}</div>
</template>

想要让视图同步更新,需要用到triggerRef强制更新数据

<script setup lang="ts">
import { shallowRef,triggerRef } from "vue";
const msg = shallowRef({
    foo:'小送',
    bar:'小西'
})
const changeMsg = () => {
    msg.value.foo = 'xiaoman'
    triggerRef(msg)
    console.log(msg);
}
</script>

<template>
    <button @click="changeMsg">change</button>
    <div>{{ msg }}</div>
</template>

reactive响应式对象

  • 传基础数据类型会报错,字符串等,基础数据类型使用ref
  • 可传复杂数据类型,数组和对象等,复杂数据类型使用reactive
  • reactive响应对象时不需要用.value赋值,可直接赋值
<script setup lang="ts">
import { reactive } from "vue";

let msg = reactive([])
let obj = reactive({
    name: '小西'
})
obj.name = '大西'
</script>

<template>
{{msg}}
{{obj}}
</template>
  • 异步赋值数组(请求接口的时候)
<script setup lang="ts">
import { reactive } from "vue";

let msg = reactive<number[]>([])
setTimeout(() => {
    let arr = [1,2,3,4]
    // msg = arr 直接赋值不会响应
    msg.push(...arr) //解构会响应
},1000)

</script>

<template>
{{msg}}
</template>

另外一种数组赋值方式

<script setup lang="ts">
import { reactive } from "vue";

type O = {
    list:number[]
}
let msg = reactive<O>({
    list:[]
})
setTimeout(() => {
    msg.list = [1,2,3,4]
},1000)
</script>

<template>
{{msg}}
</template>

readonly会将proxy对象进行拷贝一份,设置只读模式,不可以操作数据

<script setup lang="ts">
import { reactive,readonly } from "vue";
let person = reactive({
    count:1
})
person.count++
let copy = readonly(person)
copy.count++
</script>

shallowReactive只对浅层数据发生响应,对于深层数据只会改变值,但不会更新视图

  • 浅层,数据可响应,视图同步更新
  • 深层,数据可响应,但视图不更新
<script setup lang="ts">
import { shallowReactive } from "vue";
let  msg = shallowReactive({
    test: '小满', //浅层,数据可响应,视图同步更新
    nav:{ //深层,数据可响应,但视图不更新
        bar:{
            name: '大满'
        }
    }
})
const change1 = () => {
    msg.test = '小西'
}
const change2 = () => {
    msg.nav.bar.name = '大西'
}
</script>

<template>
{{msg}}
<button @click="change1">change1</button>
<button @click="change2">change2</button>
</template>

toRef是引用,修改响应式数据会影响以前的数据,数据发生变化,界面就会自动更新.

  • ref、toRef、toRefs 都可以将某个对象中的属性变成响应式数据

  • ref的本质是拷贝,修改响应式数据,不会影响到原始数据,视图会更新

  • toRef、toRefs的本质是引用,修改响应式数据,会影响到原始数据,视图不会更新

  • toRef 一次仅能设置一个数据,接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性

  • toRefs接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行

<script setup lang="ts">
import { reactive, toRef } from "vue";
const obj = reactive({
    foo: 1,
    bar: 1
})
const state = toRef(obj,'bar')
const change = () => {
    state.value++
    console.log('原始对象>>>',obj);
    console.log('引用对象>>>',state);
}
</script>

<template>
<div>{{state}}</div>
<div><button @click="change">change</button></div>
</template>

toRefs接收一个对象,toRef 一次仅能设置一个数据

<script setup lang="ts">
import { reactive, toRefs } from "vue";
const obj = reactive({
    foo: 1,
    bar: 1
})
let { foo, bar } = toRefs(obj)
console.log(foo, bar);
const change = () => {
    foo.value++
    bar.value++
}
</script>

<template>
<div> >>>{{foo}}</div>
<div> >>>{{bar}}</div>
<div><button @click="change">change</button></div>
</template>

toRaw将响应式代理对象变为普通对象

<script setup lang="ts">
import { reactive, toRaw } from "vue";
const obj = reactive({
    foo: 1,
    bar: 1
})
const raw = toRaw(obj)
console.log('响应式对象',obj);
console.log('普通对象',raw);
</script>

计算属性 computed的使用

<script setup lang="ts">
import { computed, ref } from "vue";
let firstName = ref('')
let lastName = ref('')

</script>

<template>
    <div>
        <input v-model="firstName" type="text">
        <input v-model="lastName" type="text">
        <div>
            {{ firstName }} - {{ lastName }}
        </div>
    </div>
</template>

另外一种书写方式

<script setup lang="ts">
import { computed, ref } from "vue";
let firstName = ref('')
let lastName = ref('')
const name = computed(() => {
    return firstName.value + '----' + lastName.value
})
</script>

<template>
    <div>
        <input v-model="firstName" type="text">
        <input v-model="lastName" type="text">
        <div>
            {{ name }}
        </div>
    </div>
</template>

另外一种处理方式

<script setup lang="ts">
import { computed, ref } from "vue";
let firstName = ref('')
let lastName = ref('')
const name = computed({
    get (){
        return firstName.value + '----' + lastName.value
    },
    set(){
        firstName.value + '----' + lastName.value
    }
})
</script>

<template>
    <div>
        <input v-model="firstName" type="text">
        <input v-model="lastName" type="text">
        <div>
            {{ name }}
        </div>
    </div>
</template>

购物车案例

<script setup lang="ts">
import { reactive,ref } from "vue"

type Shop = {
    name: string,
    num: number,
    price: number
}
const data = reactive<Shop[]>([
    {
        name:'裤子',
        num:1,
        price:100
    },
    {
        name:'上衣',
        num:1,
        price:200
    },
    {
        name:'外套',
        num:1,
        price:300
    }
])
let $total = ref(0)
const addAndSub = (item: Shop,type: boolean):void =>{
    if(item.num > 1 && !type){
        item.num--
        total()
    }
    if(item.num < 99 && type){
        item.num++
        total()
    }
}
const del = (index: number) => {
    data.slice(index,1)
}
/*
reduce 计算总价,
*/
const total = () => {
    $total.value = data.reduce((prev, next) => {
        return prev + (next.num * next.price)
    },0)
}
total()
</script>

<template>
    <div>
        <table border width="800px">
            <thead>
                <tr>
                    <th>名称</th>
                    <th>数量</th>
                    <th>单价</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr :key="index" v-for="(item, index) in data">
                    <td align="center">{{ item.name }}</td>
                    <td align="center">
                        <button @click="addAndSub(item,false)"> - </button>
                            {{ item.num }}
                        <button @click="addAndSub(item,true)"> + </button>
                    </td>
                    <td align="center">{{ item.price }}</td>
                    <td align="center">
                        <button @click="del(index)">删除</button>
                    </td>
                </tr>
            </tbody>
            <tfoot>
                <td></td>
                <td></td>
                <td></td>
                <td align="center">总价: {{$total}}¥</td>
            </tfoot>
        </table>
    </div>
</template>

用computed计算属性


<script setup lang="ts">
import { computed, reactive,ref } from "vue"

type Shop = {
    name: string,
    num: number,
    price: number
}
const data = reactive<Shop[]>([
    {
        name:'裤子',
        num:1,
        price:100
    },
    {
        name:'上衣',
        num:1,
        price:200
    },
    {
        name:'外套',
        num:1,
        price:300
    }
])
let $total = ref(0)
const addAndSub = (item: Shop,type: boolean):void =>{
    if(item.num > 1 && !type){
        item.num--
    }
    if(item.num < 99 && type){
        item.num++
    }
}
const del = (index: number) => {
    data.slice(index,1)
}
/*
reduce 计算总价,
*/
$total = computed<number>(() => {
    return data.reduce((prev, next) => {
        return prev + (next.num * next.price)
    },0)
})

</script>

<template>
    <div>
        <table border width="800px">
            <thead>
                <tr>
                    <th>名称</th>
                    <th>数量</th>
                    <th>单价</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr :key="index" v-for="(item, index) in data">
                    <td align="center">{{ item.name }}</td>
                    <td align="center">
                        <button @click="addAndSub(item,false)"> - </button>
                            {{ item.num }}
                        <button @click="addAndSub(item,true)"> + </button>
                    </td>
                    <td align="center">{{ item.price }}</td>
                    <td align="center">
                        <button @click="del(index)">删除</button>
                    </td>
                </tr>
            </tbody>
            <tfoot>
                <td></td>
                <td></td>
                <td></td>
                <td align="center">总价: {{$total}}¥</td>
            </tfoot>
        </table>
    </div>
</template>

watch侦听器,可侦听数据变化,以及侦听多个数据源

<script setup lang="ts">
import { ref, watch } from 'vue'
let msg1 = ref<string>('')
let msg2 = ref<string>('')
/*
watch:侦听数据变化
    参数1:侦听数据源
    参数2:回调callback简称cb
cb回调:
    参数1:新值
    参数2:旧值
*/
watch([msg1,msg2],(newVal, oldVal) => {
    console.log('新值',newVal);
    console.log('旧值',oldVal);
})
</script>

<template>
<input type="text" v-model="msg1">
<input type="text" v-model="msg2">
</template>

如果需要监听深层对象,则需要开启第三个参数 deep:true

<script setup lang="ts">
import { ref, watch } from 'vue'
let msg = ref({
    nav:{
        bar:{
            name:"东南"
        }
    }
})
watch(msg,(newVal, oldVal) => {
    console.log('新值',newVal);
    console.log('旧值',oldVal);
},{deep:true})
</script>

<template>
<input type="text" v-model="msg.nav.bar.name">
</template>

bug:监听到的新值和旧值一样



页面刷新,侦听默认不会执行,只有当变化的时候才会去侦听



但我们可以让页面刷新的时候立马去监听,配置immediate:true属性,立即触发侦听器
<script setup lang="ts">
import { ref, watch } from 'vue'
let msg = ref({
    nav:{
        bar:{
            name:"东南"
        }
    }
})
watch(msg,(newVal, oldVal) => {
    console.log('新值',newVal);
    console.log('旧值',oldVal);
},{
    deep:true,
    immediate:true
})
</script>

  • 对于reacative对象使用侦听器,深层对象可以不用配置 deep:true, immediate:true
<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
let msg = reactive({
    nav:{
        bar:{
            name:"东南"
        }
    }
})
watch(msg,(newVal, oldVal) => {
    console.log('新值',newVal);
    console.log('旧值',oldVal);
})
</script>

<template>
<input type="text" v-model="msg.nav.bar.name">
</template>

监听reactive对象的多个属性

<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
let msg = reactive({
    name:"东南",
    name2:"南北"
})
watch(msg,(newVal, oldVal) => {
    console.log('新值',newVal);
    console.log('旧值',oldVal);
})
</script>

<template>
<input type="text" v-model="msg.name">
<input type="text" v-model="msg.name2">
</template>

单一监听reactive对象的某个属性,采用函数返回的形式

<script setup lang="ts">
import { reactive, ref, watch } from 'vue'
let msg = reactive({
    name:"东南",
    name2:"南北"
})
watch(() => msg.name,(newVal, oldVal) => {
    console.log('新值',newVal);
    console.log('旧值',oldVal);
})
</script>

<template>
<input type="text" v-model="msg.name">
<input type="text" v-model="msg.name2">
</template>

认识watchEffect高级监听器

watch是只有数据发生改变的时候才去监听,而且需要立即触发监听的话,需要额外配置immediate,watchEffect则不需要配置immediate则可实现立即监听的效果。

对于watch监听多个属性时,则需要作为参数传进去,watchEffect是高效的,不需要传参。

<script setup lang="ts">
import { watchEffect, ref } from 'vue'
let msg1 = ref<string>('桌子')
let msg2 = ref<string>('板凳')
watchEffect(() => {
    console.log('msg1=====>',msg1.value);
    console.log('msg2=====>',msg2.value);
    
})
</script>

<template>
<input type="text" v-model="msg1">
<input type="text" v-model="msg2">
</template>

  • watchEffect可接收一个callback作为回调,它可以在侦听之前操作一些东西(比如在侦听之前做一些防抖和节流的操作)
<script setup lang="ts">
import { watchEffect, ref } from 'vue'
let msg1 = ref<string>('桌子')
let msg2 = ref<string>('板凳')
watchEffect((oninvalidate) => {
    console.log('msg1=====>',msg1.value);
    console.log('msg2=====>',msg2.value);
    oninvalidate(() => {
        console.log('before');
        
    })
})
</script>

<template>
<input type="text" v-model="msg1">
<input type="text" v-model="msg2">
</template>
  • 停止监听,watchEffect可实现停止监听,当停止监听后,数据发生改变,将不会对其进行监听
<script setup lang="ts">
import { watchEffect, ref } from 'vue'
let msg1 = ref<string>('桌子')
let msg2 = ref<string>('板凳')
const stop = watchEffect((oninvalidate) => {
    console.log('msg1=====>',msg1.value);
    console.log('msg2=====>',msg2.value);
    oninvalidate(() => {
        console.log('before');
        
    })
})
const stopWatchEffect = () => stop()
</script>

<template>
<input type="text" v-model="msg1">
<input type="text" v-model="msg2">
<button @click="stopWatchEffect">停止监听</button>
</template>

组件使用

对比vue2组件的使用,在vue3中,组件的使用省略了在options中配置components该选项

<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
<HelloWorld></HelloWorld>
</template>

组件的生命周期

  • setup最新被执行
  • onBeforeMount 在该生命周期内,不能获取dom相关操作
  • onMounted 在该生命周期内,组件已经创建完成,可进行获取dom操作
  • onBeforeUpdate 和 onUpdated 数据更新前后使用
  • onBeforeUnmount 和 onUnmounted 是组件卸载前后调用
    Com.vue子组件
<script setup lang="ts">
import { ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } from 'vue';

const count = ref(0)

console.log('setup');
onBeforeMount(() => { //获取不到dom
    let div = document.querySelector('#msg')
    console.log('创建之前===> onBeforeMount',div);
})
onMounted(() => { //可进行dom获取
    let div = document.querySelector('#msg')
    console.log('创建完成===> onBeforeMount',div);
})
onBeforeUpdate(() => { //数据更新之前
    let div = document.querySelector('#msg')
    console.log('数据更新之前===> onBeforeUpdate');
})
onUpdated(() => {  //数据更新完成
    console.log('数据更新完成===> onUpdated');
})
onBeforeUnmount(() => {  //组件卸载之前
    console.log('组件卸载之前===> onBeforeUnmount');
})
onUnmounted(() => {  //数据更新完成
    console.log('组件卸载完成===> onUnmounted');
})
</script>

<template>
    <div id="msg">Hello!</div>
    <div>{{count}}</div>
    <button @click="count++">改变count</button>
</template>

app.vue根组件

<script setup lang="ts">
import { ref } from 'vue';
import Com from './components/Com.vue'
let flag = ref(true)
</script>

<template>
    <Com v-if="flag"></Com>
    <button @click="flag = !flag">改变组件的状态</button>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

scoped组件间的样式隔离

  • 实现Layout布局的拼装


  • 目录层次规范



App.vue

<script setup lang="ts">
import Layout from './views/Layout/index.vue'
</script>

<template>
    <Layout></Layout>
</template>

<style lang="less">
html,body,#app {
    height: 100%;
    overflow: hidden;
}
*{
    margin:0;
    padding: 0;
}
</style>

/views/Layout/index.vue

<script setup lang="ts">
import Menu from '../Layout/Menu/index.vue'
import Header from '../Layout/Header/index.vue'
import Content from '../Layout/Content/index.vue'
</script>

<template>
    <div id="layout">
        <Menu></Menu>
        <div id="layout-right">
            <Header></Header>
            <Content></Content>
        </div>
    </div>
</template>

<style lang="less" scoped>
#layout{
    display: flex;
    height: 100%;
    overflow: hidden;
    &-right{
        flex: 1;
        display: flex;
        flex-direction: column;
    }
}
</style>

/views/Layout/Content/index.vue

<script setup lang="ts">

</script>

<template>
    <div id="content">
        <div id="content-item" :key="item" v-for="item in 100">
            {{item}}
        </div>
    </div>
</template>

<style lang="less" scoped>
    #content{
        flex: 1;
        margin: 20px;
        border: 1px solid #ccc;
        overflow: auto;
        &-item{
            padding:20px;
            border:1px solid #ccc;
        }
    }
</style>

/views/Layout/Menu/index.vue

<script setup lang="ts">

</script>

<template>
    <div id="menu">菜单区域</div>
</template>

<style lang="less" scoped>
    #menu{
        width:200px;
        border-right: 1px solid #ccc;
    }
</style>
<script setup lang="ts">

</script>

<template>
    <div id="menu">菜单区域</div>
</template>

<style lang="less" scoped>
    #menu{
        width:200px;
        border-right: 1px solid #ccc;
    }
</style>

/views/Layout/Header/index.vue

<script setup lang="ts">

</script>

<template>  
    <div id="header">头部区域</div>
</template>

<style lang="less" scoped>
#header{
    height: 60px;
    border-bottom: 1px solid #ccc;
}
</style>

页面展示


父子组件传参

  • 子接用defineProps ,子发用defineEmits

  • 子组件直接使用defineProps()接收,不需引入,前提是搭配setup和TS语法糖使用

<script setup lang="ts">
</script>

父组件传字符串,非复杂数据类型不需要v-bind指令进行绑定



子组件接收



父组件传数组(复杂数据类型)

<script setup lang="ts">
import Menu from '../Layout/Menu/index.vue'
import Header from '../Layout/Header/index.vue'
import Content from '../Layout/Content/index.vue'
import { reactive } from 'vue';
const list = reactive<number[]>([1,2,3])
</script>

<template>
    <div id="layout">
        <Menu :data="list" title="春日宴"></Menu>
        <div id="layout-right">
            <Header></Header>
            <Content></Content>
        </div>
    </div>
</template>

子组件接收

<script setup lang="ts">
type Props = {
    title:string,
    data:number[]
}
defineProps<Props>();
</script>

<template>
    <div id="menu">
        菜单区域
        <div>{{title}}</div>
        <div>{{data}}</div>
    </div>
</template>

效果:



子组件给父组件传值:defineEmits

子组件派发

<script setup lang="ts">
import { reactive } from "vue";

type Props = {
    title:string,
    data:number[]
}
defineProps<Props>();

//子组件派发
const numList = reactive<number[]>([6,7,8])
const emit = defineEmits(['on-click'])
const Tap = () => {
    emit('on-click',numList)
}
</script>

<template>
    <div id="menu">
        菜单区域
        <div>{{title}}</div>
        <div>{{data}}</div>
        <div><button @click="Tap">发送</button></div>
    </div>
</template>

父组件

<script setup lang="ts">
import Menu from '../Layout/Menu/index.vue'
import Header from '../Layout/Header/index.vue'
import Content from '../Layout/Content/index.vue'
import { reactive } from 'vue';
const list = reactive<number[]>([1,2,3])

//父子接收
const getList = (numList:number[]) => {
    console.log(numList,'来自子组件的numList');
    
}
</script>

<template>
    <div id="layout">
        <Menu @on-click="getList" :data="list" title="春日宴"></Menu>
        <div id="layout-right">
            <Header></Header>
            <Content></Content>
        </div>
    </div>
</template>

子组件派发的时候可以携带多个值给父组件



父组件接收



子组件定义多个派发事件



父子组件获取实例,子组件需要defineExpose暴露给父组件

在vue3中父组件通过ref获取子组件的实例是无法获取的



子组件必须同通过defineExpose暴露给父组件


父子组件通讯,子组件设置默认值 withDefaults

父组件



子组件设置默认值

<script setup lang="ts">
type Props = {
    title?:string,
    data?:number[]
}
withDefaults(defineProps<Props>(),{
    title: '标题', //父组件传过来就用父组件的值,没有传过来就用默认值
    data:() => [1,2,3]
})

</script>

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

推荐阅读更多精彩内容