uniapp中使用echarts,renderjs模式实现echarts封装(兼容H5和APP)一篇就够了!

一、UniApp中使用renderjs

1 为什么要使用 renderjs

  • 某些h5端使用的插件涉及到大量的dom操作,无法跨端使用。

  • 受限于框架视图层与逻辑层的分离而导致的通信折损,而导致的页面动画不流畅。

2 renderjs解决了哪些问题

  • renderjs是一种可以直接运行在视图层(webview)中的js技术,可以在视图层操作dom。
  • 直接运行在视图层,解决了视图层与逻辑层频繁通信导致的性能折损,让动画更流畅。

3 兼容性

App H5
2.5.5+支持

4 使用方式

设置 script 节点的 lang 为 renderjs

<script module="test" lang="renderjs">
    export default {
        mounted() {
            // ...
        },
        methods: {
            // ...
        }
    }
</script>

5 注意事项

  • 目前仅支持内联使用。
  • 不要直接引用大型类库,推荐通过动态创建 script 方式引用。
  • 可以使用 vue 组件的生命周期不可以使用 App、Page 的生命周期
  • 视图层和逻辑层通讯方式与 WXS 一致,另外可以通过 this.$ownerInstance 获取当前组件的 ComponentDescriptor 实例。
  • 观测更新的数据在视图层可以直接访问到。
  • APP 端视图层的页面引用资源的路径相对于根目录计算,例如:./static/test.js。
  • APP 端可以使用 dom、bom API,不可直接访问逻辑层数据,不可以使用 uni 相关接口(如:uni.request)
  • H5 端逻辑层和视图层实际运行在同一个环境中,相当于使用 mixin 方式,可以直接访问逻辑层数据。

6 renderjs模块内的生命周期

<!--
    H5:所有 UNI 框架的生命周期都可使用
    APP:仅可使用 VUE 组件生命周期
    视图层与逻辑层可以重复定义生命周期,都会执行。
-->

<!-- 逻辑层 -->
<script>
    export default {
        onLoad() {
            console.log('逻辑层生命周期 - onLoad'); 
        },
        created() {
            console.log('逻辑层生命周期 - created');
        },
        mounted() {
            console.log('逻辑层生命周期 - mounted');
        }
    }
</script>

<!-- 视图层 -->
<script module="moduleName" lang="renderjs" type="module" >
    export default {
        onLoad() {
            console.log('视图层生命周期 - onLoad'); // 页面生命周期 APP 不会执行 H5 会执行
        },
        created() {
            console.log('视图层生命周期 - created'); // 组件生命周期 H5 APP 都会执行,重复定义也会执行,不会被覆盖。
        },
        mounted() {
            console.log('视图层生命周期 - mounted'); // 组件生命周期 H5 APP 都会执行,重复定义也会执行,不会被覆盖。
        }
    }
</script>

h5端生命周期.png
app端生命周期.png

7 renderjs模块内的this指向

<!-- 逻辑层 -->
<script>
    export default {
        data() {
            return {
                str:"逻辑层的数据模型"
            }
        },
        methods: {
            test() {
                return "调用逻辑层的方法"
            }
        }
    }
</script>

<!-- 视图层 -->
<script module="moduleName" lang="renderjs" type="module" >
    export default {
        mounted() {
            console.log("尝试获取逻辑层的数据模型",this.str) // H5端可正常打印 APP打印undefined
            console.log("尝试调用逻辑层的方法",this.test()) // H5端可正常调用 APP端报错
        }
    }
</script>
h5端this.png
app端this.png

8 视图层和逻辑层的通信方式

视图层可以通过this.$ownerInstance.callMethod('方法名', 传的值) 来和逻辑层进行通信

代码中 :变量名="变量值" :change:变量名=”renderjs模块上的方法“

change就是监听定义的变量发生改变---->触发视图层上的方法----->通过this.$ownerInstance.callMethod('方法名', 传的值)给页面传参---->页面接收值---->渲染页面

示例代码:

<template>
    <view>
        <!-- 监听变量 operation 的变化,operation 发生改变时,调用 test 模块的 loadOperation 方法 -->
        <view :operation="operation" :change:operation="test.loadOperation">
            <!-- 调用 test 模块的 clicked 变量 -->
            test模块:{{test.clicked}}
        </view>
        <br />
        <view>您总共点击了 {{total}} 次</view>
        <br />
        <button @click="onClick">点击</button>
    </view>

</template>

<script>
    export default {
        data() {
            return {
                operation: true,
                total:0,
            }
        },
        methods: {
            onClick(e){
                this.operation = !this.operation
            },
            /**
             * 接收 renderjs 传过来的数据
             * @param {Object} data
             */
            reciveMessage(data) {
                this.total = data;
            }
        }
    }
</script>
<script module="test" lang="renderjs">
    export default {
        data() {
            return {
                clicked: false,
                count: 0
            }
        },
        methods: {
            loadOperation(newValue, oldValue, ownerInstance, instance) {
                // 数据变更
                console.log(newValue,oldValue,ownerInstance,instance)
                this.clicked = newValue;
                // 向uni-app页面组件发送信息
                this.sendMsg();
            },
            sendMsg() {
                // 向页面传参
                this.$ownerInstance.callMethod('reciveMessage', ++this.count)
            },
        }
    }
</script>
<style>

</style>

二、Uniapp中结合renderJS使用echarts

1.echarts引入方式(通过动态创建script方式引用)

html使用echarts的方式:

1.为 ECharts 准备一个具备高宽的 DOM 容器。

<body>
    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
    <div id="main" style="width: 600px;height:400px;"></div>
</body>

2.通过 echarts.init 方法初始化一个 echarts 实例

 // 基于准备好的dom,初始化echarts实例
 var myChart = echarts.init(document.getElementById('main'));

3.通过 setOption 方法生成一个简单的柱状图,

// 指定图表的配置项和数据
        var option = {
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data:['销量']
            },
            xAxis: {
                data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };
// 使用指定的配置项和数据显示图表。
 myChart.setOption(option);

renderjs使用echarts的方式:(同html的使用方式大致相同)

1.为 ECharts 准备一个具备高宽的 DOM 容器。

<view class="content">
        <view id="echarts" style="width:100%;height:300rpx"></view>
</view>

2.引入renderjs, 动态引入echarts。原生操作dom 。将echarts引入

3.script标签上的onload事件加载完成后初始化echarts 实例

4.通过 setoption方法生成

<script module="echarts" lang="renderjs">
    let myChart
    export default {
        mounted() {
            if (typeof window.echarts === 'function') {
                myChart = echarts.init(document.getElementById('echarts'))
                // 观测更新的数据在 view 层可以直接访问到
                myChart.setOption(this.option)
            } else {
                // 动态引入较大类库避免影响页面展示
                const script = document.createElement('script')
                // view 层的页面运行在 www 根目录,其相对路径相对于 www 计算
                script.src = 'static/echarts.js'
                //script标签的onload事件都是在外部js文件被加载完成并执行完成后才被触发的
                script.onload = ()=>{
                    myChart = echarts.init(document.getElementById('echarts'),)
                    myChart.setOption(this.option)
                }
                document.head.appendChild(script)
            }
        },
        methods: {
            
        }
    }
</script>

三、echarts的主题配置与封装

1.主题配置

主题配置是全局控制echarts的样式

在echarts官网可以可视化定制配置,然后导出json或者js文件。

配置的具体方法:

JS版本

下载或复制以下的主题保存至 *.js 文件;
将该文件在 HTML 中引用;
使用 echarts.init(dom, 'customed') 创建图表,第二个参数即为 *.js 文件中注册的主题名字。

json版本

下载或复制以下的主题保存至 *.json 文件;
读取该 JSON 文件,并使用 obj = JSON.parse(data) 将其转换成对象;
调用 echarts.registerTheme('customed', obj) 注册主题;
使用 echarts.init(dom, 'customed') 创建图表,第二个参数即为刚才注册的主题名字。

在uniapp中可以直接建一个js文件,modules.exports一个对象。然后页面引入使用

// 通用配置项
module.exports = {
    "color": [
        "#5470c6",
        "#91cc75",
        "#fac858",
        "#ee6666",
        "#73c0de",
        "#3ba272",
        "#fc8452",
        "#9a60b4",
        "#ea7ccc"
    ],
    "backgroundColor": "rgba(0, 0, 0, 0)",
    "textStyle": {},
    "title": {
        "textStyle": {
            "color": "#464646"
        },
        "subtextStyle": {
            "color": "#6E7079"
        }
    },
    ....
    ....
    ....
 }

2.使用renderJS封装echarts,实现主题配置

实现效果:一个组件,可以实现不同的图表功能,样式可以全局配置,避免option样式过多

实现思路:

1.在同个页面使用多个图表,id名必须不一致

2.option配置项需改成传参形式

3.主题配置文件

主要代码如下:

<template>
    <view class="content">
        <!-- #ifdef APP-PLUS || H5 -->
        <view @click="echarts.onClick" :prop="optionData" :style="{width:moduleParam.width,height:moduleParam.height}" :change:prop="echarts.updateEcharts"  :moduleParam="moduleParam" :change:moduleParam="echarts.upmoduleParam" :id="moduleParam.id" class="echarts" ></view>
        <!-- <button @click="changeOption">更新数据</button> -->
        <!-- #endif -->
        <!-- #ifndef APP-PLUS || H5 -->
        <view>非 APP、H5 环境不支持</view>
        <!-- #endif -->
    </view>
</template>
<script>
    
    export default {
        data() {
            return {
                
            }
        },
        props:{
            moduleParam:{
                type:Object,
                default:()=>{
                    id: "myCharts";
                    width: "100%";
                    height: "300rpx"
                }
            },
            optionData:{
                type:Object,
                default:()=>{}
            }
        },
        onLoad() {

        },
        methods: {
            changeOption() {
                // 父组件刷新数据
                this.$emit("changeOption")
            },
            onViewClick(options) {
                this.$emit("getClickData",options)
            }
        }
    }
</script>

<script module="echarts" lang="renderjs">
    import echartsConfig from '@/common/echarts-config.js'
    let myChart
    export default {
        data(){
            return{
                clickData:null
            }
        },
        mounted() {
            if (typeof window.echarts === 'function') {
                this.initEcharts()
            } else {
                // 动态引入较大类库避免影响页面展示
                const script = document.createElement('script')
                // view 层的页面运行在 www 根目录,其相对路径相对于 www 计算
                script.src = 'static/echarts.min.js'
                script.onload = this.initEcharts.bind(this)
                document.head.appendChild(script)
            }
        },
        methods: {
            initEcharts(){
                echarts.registerTheme('echartsConfig',echartsConfig )  //注册主题
                myChart = echarts.init(document.getElementById(this.moduleParam.id),"echartsConfig")
                // 观测更新的数据在 view 层可以直接访问到
                myChart.setOption(this.optionData)
                // 点击传参
                myChart.on('click', params => {
                    // console.log(params)
                    this.clickData = params
                })
            },
            updateEcharts(newValue, oldValue, ownerInstance, instance) {
                // 监听 service 层数据变更
                console.log(newValue)
                myChart = echarts.init(document.getElementById(this.moduleParam.id),"echartsConfig")
                myChart.setOption(newValue)
            },
            upmoduleParam(newvalue,oldvalue){},
            onClick(event, ownerInstance) {
                // console.log(this.clickData)
                if(!this.clickData){
                    return
                }
                ownerInstance.callMethod('onViewClick',{
                    value:this.clickData.value,
                    name:this.clickData.name,
                    dataIndex:this.clickData.dataIndex,
                    seriesName:this.clickData.seriesName
                })
                // 上次点击数据置空
                this.clickData = null
            }
        }
    }
</script>

<style>
    .content {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }

    .echarts {
        width: 100%;
        height: 600rpx;
    }
</style>



主题配置文件

// 通用配置项
module.exports = {
    "color": [
        "#5470c6",
        "#91cc75",
        "#fac858",
        "#ee6666",
        "#73c0de",
        "#3ba272",
        "#fc8452",
        "#9a60b4",
        "#ea7ccc"
    ],
    "backgroundColor": "rgba(0, 0, 0, 0)",
    "textStyle": {},
    "title": {
        "textStyle": {
            "color": "#464646"
        },
        "subtextStyle": {
            "color": "#6E7079"
        }
    },
    "line": {
        "itemStyle": {
            "borderWidth": 1
        },
        "lineStyle": {
            "width": 2
        },
        "symbolSize": 4,
        "symbol": "emptyCircle",
        "smooth": false
    },
    "radar": {
        "itemStyle": {
            "borderWidth": 1
        },
        "lineStyle": {
            "width": 2
        },
        "symbolSize": 4,
        "symbol": "emptyCircle",
        "smooth": false
    },
    "bar": {
        "itemStyle": {
            "barBorderWidth": 0,
            "barBorderColor": "#ccc"
        }
    },
    "pie": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "scatter": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "boxplot": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "parallel": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "sankey": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "funnel": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "gauge": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        }
    },
    "candlestick": {
        "itemStyle": {
            "color": "#eb5454",
            "color0": "#47b262",
            "borderColor": "#eb5454",
            "borderColor0": "#47b262",
            "borderWidth": 1
        }
    },
    "graph": {
        "itemStyle": {
            "borderWidth": 0,
            "borderColor": "#ccc"
        },
        "lineStyle": {
            "width": 1,
            "color": "#aaa"
        },
        "symbolSize": 4,
        "symbol": "emptyCircle",
        "smooth": false,
        "color": [
            "#5470c6",
            "#91cc75",
            "#fac858",
            "#ee6666",
            "#73c0de",
            "#3ba272",
            "#fc8452",
            "#9a60b4",
            "#ea7ccc"
        ],
        "label": {
            "color": "#eee"
        }
    },
    "map": {
        "itemStyle": {
            "normal": {
                "areaColor": "#eee",
                "borderColor": "#444",
                "borderWidth": 0.5
            },
            "emphasis": {
                "areaColor": "rgba(255,215,0,0.8)",
                "borderColor": "#444",
                "borderWidth": 1
            }
        },
        "label": {
            "normal": {
                "textStyle": {
                    "color": "#000"
                }
            },
            "emphasis": {
                "textStyle": {
                    "color": "rgb(100,0,0)"
                }
            }
        }
    },
    "geo": {
        "itemStyle": {
            "normal": {
                "areaColor": "#eee",
                "borderColor": "#444",
                "borderWidth": 0.5
            },
            "emphasis": {
                "areaColor": "rgba(255,215,0,0.8)",
                "borderColor": "#444",
                "borderWidth": 1
            }
        },
        "label": {
            "normal": {
                "textStyle": {
                    "color": "#000"
                }
            },
            "emphasis": {
                "textStyle": {
                    "color": "rgb(100,0,0)"
                }
            }
        }
    },
    "categoryAxis": {
        "axisLine": {
            "show": true,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisTick": {
            "show": true,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisLabel": {
            "show": true,
            "textStyle": {
                "color": "#6E7079"
            }
        },
        "splitLine": {
            "show": false,
            "lineStyle": {
                "color": [
                    "#E0E6F1"
                ]
            }
        },
        "splitArea": {
            "show": false,
            "areaStyle": {
                "color": [
                    "rgba(250,250,250,0.2)",
                    "rgba(210,219,238,0.2)"
                ]
            }
        }
    },
    "valueAxis": {
        "axisLine": {
            "show": false,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisTick": {
            "show": false,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisLabel": {
            "show": true,
            "textStyle": {
                "color": "#6E7079"
            }
        },
        "splitLine": {
            "show": true,
            "lineStyle": {
                "color": [
                    "#E0E6F1"
                ]
            }
        },
        "splitArea": {
            "show": false,
            "areaStyle": {
                "color": [
                    "rgba(250,250,250,0.2)",
                    "rgba(210,219,238,0.2)"
                ]
            }
        }
    },
    "logAxis": {
        "axisLine": {
            "show": false,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisTick": {
            "show": false,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisLabel": {
            "show": true,
            "textStyle": {
                "color": "#6E7079"
            }
        },
        "splitLine": {
            "show": true,
            "lineStyle": {
                "color": [
                    "#E0E6F1"
                ]
            }
        },
        "splitArea": {
            "show": false,
            "areaStyle": {
                "color": [
                    "rgba(250,250,250,0.2)",
                    "rgba(210,219,238,0.2)"
                ]
            }
        }
    },
    "timeAxis": {
        "axisLine": {
            "show": true,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisTick": {
            "show": true,
            "lineStyle": {
                "color": "#6E7079"
            }
        },
        "axisLabel": {
            "show": true,
            "textStyle": {
                "color": "#6E7079"
            }
        },
        "splitLine": {
            "show": false,
            "lineStyle": {
                "color": [
                    "#E0E6F1"
                ]
            }
        },
        "splitArea": {
            "show": false,
            "areaStyle": {
                "color": [
                    "rgba(250,250,250,0.2)",
                    "rgba(210,219,238,0.2)"
                ]
            }
        }
    },
    "toolbox": {
        "iconStyle": {
            "normal": {
                "borderColor": "#999"
            },
            "emphasis": {
                "borderColor": "#666"
            }
        }
    },
    "legend": {
        "textStyle": {
            "color": "#333"
        }
    },
    "tooltip": {
        "axisPointer": {
            "lineStyle": {
                "color": "#ccc",
                "width": 1
            },
            "crossStyle": {
                "color": "#ccc",
                "width": 1
            }
        }
    },
    "timeline": {
        "lineStyle": {
            "color": "#DAE1F5",
            "width": 2
        },
        "itemStyle": {
            "normal": {
                "color": "#A4B1D7",
                "borderWidth": 1
            },
            "emphasis": {
                "color": "#FFF"
            }
        },
        "controlStyle": {
            "normal": {
                "color": "#A4B1D7",
                "borderColor": "#A4B1D7",
                "borderWidth": 1
            },
            "emphasis": {
                "color": "#A4B1D7",
                "borderColor": "#A4B1D7",
                "borderWidth": 1
            }
        },
        "checkpointStyle": {
            "color": "#316bf3",
            "borderColor": "fff"
        },
        "label": {
            "normal": {
                "textStyle": {
                    "color": "#A4B1D7"
                }
            },
            "emphasis": {
                "textStyle": {
                    "color": "#A4B1D7"
                }
            }
        }
    },
    "visualMap": {
        "color": [
            "#bf444c",
            "#d88273",
            "#f6efa6"
        ]
    },
    "dataZoom": {
        "handleSize": "undefined%",
        "textStyle": {}
    },
    "markPoint": {
        "label": {
            "color": "#eee"
        },
        "emphasis": {
            "label": {
                "color": "#eee"
            }
        }
    }
}


页面引用:

<template>
    <view class="content">
        <dom-echart :moduleParam="moduleParam1" :optionData="option"  @changeOption="changeOption()"></dom-echart>
        <dom-echart :moduleParam="moduleParam2" :optionData="option1" @changeOption="changeOption1()"></dom-echart>
        <dom-echart :moduleParam="moduleParam3" :optionData="option2" @changeOption="changeOption2()"></dom-echart>
    </view>
</template>

<script>
    import domEchart from './index/index.vue'
    export default {
        components:{
            domEchart
        },
        data() {
            return {
                moduleParam1:{
                    id:"moId1",
                },
                moduleParam2:{
                    id:"moId2",
                },
                moduleParam3:{
                    id:"moId3",
                },
                option: {
                    title: {
                        text: 'ECharts1'
                    },
                    xAxis: {
                        data: ["衬衫1", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
                    },
                    yAxis: {},
                    series: [{
                        name: '销量',
                        type: 'bar',
                        data: [5, 20, 36, 10, 10, 20]
                    }]
                },
                option1: {
                    title: {
                        text: 'ECharts2'
                    },
                    series: [{
                        name: '销量',
                        type: 'pie',
                        data: [53, 20, 28, 12, 10, 20]
                    }]
                },
                option2: {
                    title: {
                        text: 'ECharts3'
                    },
                    xAxis: {
                        data: ["衬衫1", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
                    },
                    yAxis: {},
                    series: [{
                        name: '销量',
                        type: 'line',
                        data: [53, 20, 28, 12, 10, 20]
                    }]
                }
                }
        },
        onLoad() {

        },
        methods: {
            changeOption(){
                const data = this.option.series[0].data
                // 随机更新示例数据
                data.forEach((item, index) => {
                    data.splice(index, 1, Math.random() * 40)
                })
            },
        
            changeOption1(){
                const data = this.option1.series[0].data
                // 随机更新示例数据
                data.forEach((item, index) => {
                    data.splice(index, 1, Math.random() * 40)
                })
            },
            changeOption2(){
                const data = this.option2.series[0].data
                // 随机更新示例数据
                data.forEach((item, index) => {
                    data.splice(index, 1, Math.random() * 40)
                })
            }
        }
    }
</script>

<style>
</style>

实现效果

image-20210510102605090.png
image-20210510102624945.png
dome源码请移步gitee:https://gitee.com/shen-miaoxin/uniapp-renderjs-echarts

点个小星星~

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

推荐阅读更多精彩内容