vue2.5开发仿去哪儿开发重点记录

本文主要写了第一次使用

Vue Vue-router Vuex Vue-cli

开发一个仿去哪儿移动端网页的项目记录。

项目所用到的插件:

vue-awesome-swiper 图片轮转

better-scroll 页面滚动

fastClick 解决移动端点击延迟300毫秒问题

axios 基于promise的ajax

项目中所用的css预处理器

stylus CSS预处理器为CSS提供了更多的更加灵活的可编程性

安装 stylus

yarn add stylus --save

yarn add stylus-loader --save

项目中所使用的自适应移动端开发配置与布局工具

在vue-cli目录中的index.html首页中配置

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,er-scalable=no">

使网页能够适配屏幕大小以及放大缩小影响体验。


import 'styles/ reset.css ' /解决移动端不同样式问题/

import 'styles/ border.css '/解决移动端像素边框的问题/

解决不同机型的样式,像素边框


项目结构:

去哪儿首页知识点 :

HomeSwiper 组件

使用 vue-awesome-swiper 轮播插件 2.6.7 版本(新版本有些Bug,为了开发的稳定性选择用老版本)

npm install vue-awesome-swiper@2.6.7 --save

轮播图当中的CSS样式有需要关注的一个地方

该样式主要是防止网速过慢时有部分模块未加载而导致页面结构发生抖动的情况,

所以把

wrapper宽度100%,高度由宽度的27%自动撑开成一个独立的div,使之在加载时就替代着轮转图的位置

解决了抖动问题

 .wrapper
  { 
 overflow: hidden;
 width:100%;height:0;
 padding-bottom:27%; 
  }
  或者写成
  .wrapper
 { 
 width:100%;height:27vw;
  }

显示轮播下标点以及页面循环切换应配置swiperOption类的paginationloop属性

image

HomeIcons 组件

小技巧:利用padding-bottom配置等距div布局(需要记得height配置为0)

image

制作iconList的图标分页功能(重点)

使用vue中的计算功能,根据图标数目自动更换页数以实现切换分页功能

computed: {

    pages() {

      const pages = [];

      this.iconList.forEach((item, index) => {

        const page = Math.floor(index / 8);

        if (!pages[page]) {

          pages[page] = [];

        }

        pages[page].push(item);

      });

      return pages;

    }

 }

};

小功能:创建一个mixins.styl定义css样式

能够在字符数超出边框长度时隐藏并添加省略号

ellipsis() 

    overflow: hidden;

    white-space: nowrap;

    text-overflow: ellipsis;

Recommend.vue以及Weekends.vue组件中css`样式配置思想值得学习

Ajax(Axios)获取首页数据

npm install axios --save

yarn add axios --save

使用方法:

 methods: {
 
     getHomeInfo(){
 
       axios.get('/api/index.json') //接收到接口数据
 
       .then(this.getHomeInfoSucc)
 
     },
     //回调函数
     getHomeInfoSucc(res){
 
       console.log(res)
 
       res=res.data
 
       if(res.ret && res.data){
 
         this.city = res.data.city
 
         this.swiperList = res.data.swiperList
 
         this.swiperList = res.data.swiperList
 
         this.iconList = res.data.iconList
 
         this.recommendList = res.data.recommendList
 
         this.weekendList = res.data.weekendList
 
       }
 
     }
 
   }

传入虚拟json数据到staticmock文件夹中,并设置代理路径

进入`config`中的`index.js`设置`api`所指定的代理路径

 proxyTable: {
 
       '/api':{
 
         target:'http://localhost:8080',
 
         pathRewrite:{
 
           '^/api':'/static/mock'
 
         }
 
       }
 
     }

这样做webpack-dev-server会将此配置自动替换

配置主文件夹中.gitignore

添加 staitc/mock,防止被推送到仓库


城市选择页面

router-link组件:

<router-link :to="">    //to 后面跟需要跳转的 path 。

使用路由跳转需要配置对应的vue-router


import Vue from 'vue'

import Router from 'vue-router'
 
import Homefrom '@/pages/home/Home'
 
import City from '@/pages/city/City'

Vue.use(Router)
 
export default newRouter
({
   routes: [{ 
                     path: '/', 
 
                     name: 'Home', 
 
                     component: Home },  
 
                  {
 
                    path: '/city',
 
                   name: 'City',
 
                   component: City
 
                   }] 
 
 })

由于引入了border.css

所以可以在元素classs属性中添加border所带的移动端像素边框

若想修改像素边框的元素

可以采用,例:

.border-topbottom
 
&:before
 
border-color:#ccc
 
&:after
 
border-color:#ccc

better-scroll插件的使用:

yarn add better-scroll --save  //首先用yarn安装插件

然后在要使用的vue中script引入

import BScroll from "better-scroll";

mounted()
 
{
 
 this.scroll = new BScroll(this.$refs.wrapper); 
 
 }

注意:使用时应该有个外层DOM结构,可以在要采用滚动部分最外层div处用ref添加一个DOM引用

<div class="list" ref="wrapper">

city-components(实现点击右侧字母表定位首字母城市)

这里需要采用兄弟联动,但不用bus方法(教程)

采用 Alphabet.vue(子组件) $emit传递给 City.vue(父组件) ,然后再通过 City.vue(父组件) 传递给 List.vue(子组件)的方式

Alphabet.vue:

<template>

<ulclass="list">

<li

class="item"

v-for="item of letters"

:key="item"

:ref="item"

@click="handleLetterClick" //绑定一个click

>{{item}}</li>

</ul>

</template>
methods: {
  handleLetterClick (e) {
    this.$emit('change', e.target.innerText)
  }
}

City.vue:

<city-alphabet :cities="cities" @change="handleLetterClick"></city-alphabet>
//@change里的函数传入了e.target.innerText这个值
methods: {
  handleLetterClick (letter) {
    this.letter = letter
  }
}

然后再创建一个data用于存储传递的数据:

data () {
  return {
    cities: {},
    hotCities: [],
    letter: ''  // Alphabet 通过 change 事件传递过来的数据
  }
}

再将letter的数据进行绑定,传给list.vue

<city-list :cities="cities" :hot="hotCities" :letter="letter"></city-list>

并在list.vue中进行接收

props: {
  hot: Array,
  cities: Object,
  letter: String  //  拿到传过来的letter
}

利用监听器来读取数据是否发生变化
并使用Better-scroll的方法
scrollToElement来实现跳转

watch: {
  letter () {
    if (this.letter) {
      const element = this.$refs[this.letter][0]
      this.scroll.scrollToElement(element)
    }
  }
}

在使用$refs前应该先用ref属性引用DOM

<div class="area" v-for="(item, key) of cities" :key="key" :ref="key">
  <div class="title border-topbottom">{{key}}</div>
  <div class="item-list">
    <div class="item border-bottom" v-for="innerItem of item" :key="innerItem.id">{{innerItem.name}}</div>
  </div>
</div>

alphabet 滑动跳转功能

实现的逻辑:
1.先获取A字母距离顶部边框高度
2.进行右侧字母表滑动时,取当前位置距离顶部边框高度
3.通过computed计算出,当前手指位置与A 字母高度的差值
4.最后再通过Math.floor向下取整每个字母高度得出下标,取得当前字母,并触发change事件实现跳转

<template>
  <ul class="list">
    <li class="item"
        v-for="item of letters"
        :key="item"
        :ref="item"
        @touchstart="handleTouchStart" //触摸开始
        @touchmove="handleTouchMove" //开始滑动
        @touchend="handleTouchEnd" //触摸结束
        @click="handleLetterClick"
    >
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  // 计算属性中定义 letters 是一个数组,从 cities 数据中遍历ABC等城市开头的数据
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return letters
    }
  },
  data () {
    return {
      touchStatus: false  // 用来判断触摸行为
    }
  },
  methods: {
    handleLetterClick (e) {
      this.$emit('change', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) { //e是事件对象
      if (this.touchStatus) {
        const startY = this.$refs['A'][0].offsetTop       // A 距离头部header区域下沿的高度
        const touchY = e.touches[0].clientY - 80      // 手指距离 header区域下沿的高度 80是header上沿到下沿的高度大小
        const index = Math.floor((touchY - startY) / 20)  // 当前移动的字母下标,得到index后可取出对应的字母
        if (index >= 0 && index < this.letters.length) {
          this.$emit('change', this.letters[index])       // 通过 $emit 发送事件给City.vue
        }
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

最后需要在handleTouchMove里进行节流函数操作
浅析函数防抖与函数节流
在data中再创建一个timer:null

handleTouchMove (e) {
  if (this.touchStatus) {
    // 函数节流主要是降低操作频率,提高性能
    if (this.timer) {
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(() => {
      const startY = this.startY  
      const touchY = e.touches[0].clientY - 79  
      const index = Math.floor((touchY - startY) / 20)
      if (index >= 0 && index < this.letters.length) {
        this.$emit('change', this.letters[index])     
      }
    }, 12)//每隔12毫秒再读取一次
  }
}

search模糊查询功能

<template>
  <div>
    <div class="search">
      <input v-model="keyword" class="search-input" type="text" placeholder="输入城市名或拼音"> //用v-model进行双向绑定
    </div>
    <div class="search-content">
      <ul>
        <li v-for="item of list">{{item.name}}</li>
      </ul>
    </div>
  </div>
</template>

使用监听器监听keyword的变化

<script>
export default {
  name: 'CitySearch',
  props: {
    cities: Object
  },
  data () {
    return {
      keyword: '',
      list: [],
      timer: null
    }
  },
  watch: {
    keyword () {
      if (this.timer) {
        clearTimeout(this.timer)
      }
      this.timer = setTimeout(() => {
        const result = []
        for (let i in this.cities) { //循环city对象
          this.cities[i].forEach((value) => { //取出每个节点的城市的值
            if (value.spell.indexOf(this.keyword) > -1 ||
                value.name.indexOf(this.keyword) > -1) { /*当双向绑定的KeyWord值发生改变时,
                                                                                     将带有首字符的value值传入*/
                  result.push(value)
            }
          })
        }
        this.list = result //将带有数据的result数组存储到list中
      }, 100)
    }
  }
}
</script>

最后实现一下input无输入的情况下,
数据冗余bug的解决方式:

if (!this.keyword) {
  this.list = []
  return
}

由于搜索层是覆盖在原本页面上的,
以及当模糊查询没找到相匹配的城市时没有提示
影响体验,所以进行优化
使用v-show组件:

<li class="search-item border-bottom" v-show="!list.length">没有找到匹配</li>

search-content的显示隐藏
v-show判断当keyword值为0则为false,不显示搜索内容框

<div class="search-content"  v-show="keyword">
  <ul>
    <li class="search-item border-bottom" v-for="item of list">{{item.name}}</li>
    <li class="search-item border-bottom" v-show="!list.length">没有找到匹配</li>
  </ul>
</div>

使用vuex

实现数据共享
用于实现点击城市更改index首页中数据的更改

重点:下图需熟记

vuex操作图

1.先对vuex进行安装与配置

yarn add vuex --save

2.在src中创建一个store文件夹
在store中创建index.js用于放置vuex的功能数据

3.进行vuex操作

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    city: '珠海'
  },
  mutations: {
    changeCity (state/*这个参数用于放置全局数据*/, city/*这是传入的值*/) 
{
      state.city = city
    }
  }
})

main.js中引入store,使得store可以全局使用

import store from './store'  //引入 store

new Vue({
  el: '#app',
  router,
  store,  //传递 store 实例到根组件
  components: { App },
  template: '<App/>'
})

在想使用的组件中定义一个@click点击事件
并传入相应的值
如 :

@click="handleCityClick(item.name)" //item.name为传入值

然后根据vuex操作图进行操作

methods: {
  handleCityClick (city) {
    this.$store.commit('changeCity', city)
    this.$router.push('/')  //这里是编程式函数跳转到首页
  }
}

注意:这样做还不够,因为点击跳转时并未保存到内置存储当中,刷新页面时又会恢复到初始状态

使用内置存储localStorage:

export default new Vuex.Store({
  state: {
    city: localStorage.city || '珠海'
  },
  mutations: {
    changeCity (state, city) {
      state.city = city
      localStorage.city = city
    }
  }
})

再次注意:建议try catch异常处理优化一下,因为可能某些情况下用户禁用了localStorage的功能

关于vuex中组件的使用(详细请看官方文档)

///这里引入vuex的一个组件
用于映射store中state的数据
<script>
import { mapState } from "vuex";
export default {
  name: "HomeHeader",
  computed:{
    ...mapState(['city']) //此处采用扩展运算符
  }
};
</script>

keep-alive组件对于网页性能的优化

未进行优化的网页在每次切换页面时,
ajax都会重新请求数据影响到网页的性能
这个时候就应该使用keep-alive了
他会将访问过的页面储存到内存中以便重新访问时加载
大大加强了性能,减少了数据上的冗余
App.vue:

<template>
  <div id="app">
    <keep-alive> //只需要包裹一层keep-alive
      <router-view/>
    </keep-alive>
  </div>
</template>

包裹了keep-alive的标签,
将得到keep-alive特有的生命周期钩子
Home.vue:

<script>
import HomeHeader from "./components/Header";
import HomeSwiper from "./components/Swiper";
import HomeIcons from "./components/Icons";
import HomeRecommend from "./components/Recommend";
import HomeWeekend from "./components/Weekend";
import axios from "axios";
import { mapState } from "vuex";
export default {
  name: "Home",
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  data() {
    return {
      lastCity:'',
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: []
    };
  },
  computed:{
    ...mapState(['city'])
  },
  methods: {
    getHomeInfo() {
      axios.get(`/api/index.json?city=${this.city}`).then(this.getHomeInfoSucc);
    },
    getHomeInfoSucc(res) {
      console.log(res);
      res = res.data;
      if (res.ret && res.data) {
        this.swiperList = res.data.swiperList;
        this.swiperList = res.data.swiperList;
        this.iconList = res.data.iconList;
        this.recommendList = res.data.recommendList;
        this.weekendList = res.data.weekendList;
      }
    }
  },
  mounted() {
    this.lastCity = this.city
    this.getHomeInfo();
  },
  activated(){  //此处使用生命周期钩子函数在发现不同城市时自行修改页面显示信息
                      //activated会在跳转页面时进行判断
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    }
  }
};
</script>

补充:在 keep-alive 添加一个exclude="Detail"属性,

能将Detail排除于keep-alive的功能之外

详情页面

关于tag属性route-link补充

<router-link
        tag="li"  //这个标签相当于router-link成为了一个有路由功能的li标签
        v-for="item of list"
        :key="item.id"
        class="item border-bottom"
        :to="'/detail/' + item.id"
      >

实现图片下方黑色渐变效果


下方黑色渐变.png

background-image中linear-gradient的运用

.banner-info {
  background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, .8))
}

全局画廊组件(Gallary.vue)

配置滑动插件

      <swiper :options="swiperOption">
        <!-- slides -->
        <swiper-slide v-for="(item, index) of imgs" :key="index">
          <img class="gallary-img" :src="item">
        </swiper-slide>
        <!-- Optional controls -->
        <div class="swiper-pagination" slot="pagination"></div> //图片页下标
      </swiper>

对图片页下标样式的修改

图片页

具体参照SwiperAPI文档

<script>
export default {
  name: "CommonGallary",
  props: {
    imgs: {
      type: Array,
      default() {
        return [];
      }
    }
  },
  data() {
    return {
      swiperOption: {
        pagination: ".swiper-pagination",
        paginationType: "fraction",
        observeParents: true, ////swiper 插件监听到自身或父级元素DOM变化时,自动自我刷新。解决 swiper 刷新宽度计算 bug 的问题
        observer: true,
        loop:true
      }
    };
  },
  methods: {
    handleGallaryClick() {
      this.$emit("close");
    }
  }
};
</script>

解决分页不显示Bug

.container >>> .swiper-container {
  overflow: inherit;  //轮播插件自带overflow:hidden,需要通过>>>向外修改
}

实现header渐隐渐显的效果

<div>
    <router-link to="/" tag="div" class="header-abs" v-show="showAbs">
      <div class="iconfont header-abs-back">&#xe633;</div>
    </router-link> //返回首页
    <div class="header-fixed" v-show="!showAbs" :style="opacityStyle">
      <router-link to="/">//下拉显示header头部
        <div class="iconfont header-fixed-back">&#xe633;</div>
      </router-link>景点详情
    </div>
  </div>
<script>
export default {
  name: "DetailHeader",
  data() {
    return {
      showAbs: true, //用于判断头部的显示
      opacityStyle: {
        opacity: 0
      }
    };
  },
  methods: {
    handleScroll() {
      const top = document.documentElement.scrollTop; 拿到滚动头部开始到滑动的距离
      if (top > 60) {
        let opacity = top / 140; //这里实现opacity值的动态变化
        opacity = opacity > 1 ? 1 : opacity; //三元判断若opacity>1了,则值不再变化(1则为完全显示)
        this.opacityStyle = { opacity };
        this.showAbs = false;
      } else {
        this.showAbs = true;
      }
      console.log(document.documentElement.scrollTop);
    }
  },
  activated() {//跳转页面到页面关闭期间时则运行
    window.addEventListener("scroll", this.handleScroll); //添加滚动监听事件scroll
  }
};
</script>

为避免影响其他组件进行全局解绑(修复windows全局组件绑定监听器而导致切换页面还会继续加载的bug)

  deactivated() {//关闭此页面时执行
    window.removeEventListener("scroll", this.handleScroll);
  }

用递归实现详情页
每次在组件中配置name属性的重要原因,
以便于在组件自身调用自身的递归方式的时候调用。
效果:

递归调用列表

实现:

 <div>
    <div class="item" v-for="(item, index) of list" :key="index">
      <div class="item-title border-bottom">
        <span class="item-title-icon"></span>
        {{item.title}}
      </div>
      <div v-if="item.children" class="item-children">//在 div 标签中做一个 v-if 判断,如果存在 item.children,则为true
        <detail-list :list="item.children"></detail-list>// 把item.children作为list传给自身进行递归
      </div>
    </div>
  </div>

关于Detail中ajax读取不同页面数据
路由器routerindex.js的配置与其他页面有所不同
需要在配置跳转path属性中,
加上:id用于axios提取不同页面数据

同步加载写法(增加一个异步加载知识点)

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'
import City from '@/pages/city/City'
import Detail from '@/pages/detail/Detail'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }, {
      path: '/city',
      name: 'City',
      component: City
    }, {
      path: '/detail/:id', //此处多加了:id
      name: 'Detail',
      component: Detail
    }
  ],
  scrollBehavior (to, from, savePosition) {
    return { x: 0, y: 0 }
  }
})

异步加载写法

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: ()=>{@/pages/home/Home}
    }, {
      path: '/city',
      name: 'City',
      component: ()=>{@/pages/city/City}
    }, {
      path: '/detail/:id', //此处多加了:id
      name: 'Detail',
      component: ()=>{@/pages/detail/Detail}
    }
  ]

关于同步异步介绍
通过$route.params.id取得点击页面时的id

methods: {
    getDetailInfo() {
      axios.get(`/api/detail.json?id=${this.$route.params.id}`)//取得不同Id到后台请求不同的页面数据
      .then(res => {
        res = res.data;
        if (res.ret && res.data) {
          const data = res.data;
          console.log(data);
          this.sightName = data.sightName;
          this.bannerImg = data.bannerImg;
          this.gallaryImgs = data.gallaryImgs;
          this.list = data.categoryList;
        }
      });
    }
  },
  mounted() {
    this.getDetailInfo();
  }
};

通过id在获取新页面后,
载入页面会停留在原来的下拉角度
所以应在routerindex.js添加

  scrollBehavior (to, from, savePosition) {
    return { x: 0, y: 0 }
  }

gallary的动画效果


transition.png
<template>
  <transition>
    <slot></slot> //slot这个插槽是用于中间插入gallary组件
  </transition>
</template>

<script>
export default {
  name: "FadeAnimation"
};
</script>

<style lang="stylus" scoped>
.v-enter, .v-leave-to {
  opacity: 0;
}

.v-enter-active, .v-leave-active {
  transition: opacity 0.5s;
}
</style>

然后在Banner.vue中引入,
这时slot插槽属性就相当于common-gallary

<fade-animation>
    <common-gallary 
    :imgs="bannerImgs" 
    v-show="showGallary" 
    @close="handleGallaryClick"
    ></common-gallary>
    </fade-animation>

进行项目的上线

当项目完成之后,准备上线,必须先运行

npm run build

完成打包之后在进入dist目录

dist目录里的文件

把里面的文件放到后端文件夹中,项目完成上线


附上githttps://gitee.com/yggtzsj/FangQuNaEr

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