学习笔记

二、js

(一)字符串

1.字符串的切割:String.prototype.split()

split方法按照给定规则分割字符串,返回一个由分割出来的子字符串组成的数组。
'a|b|c'.split('|') // ["a", "b", "c"]

  • 如果分割规则为空字符串,则返回数组的成员是原字符串的每一个字符。
    'a|b|c'.split('') // ["a", "|", "b", "|", "c"]
  • 如果省略参数,则返回数组的唯一成员就是原字符串。
    'a|b|c'.split() // ["a|b|c"]
  • 如果满足分割规则的两个部分紧邻着(即两个分割符中间没有其他字符),则返回数组之中会有一个空字符串。
    'a||c'.split('|') // ['a', '', 'c']
  • 如果满足分割规则的部分处于字符串的开头或结尾(即它的前面或后面没有其他字符),则返回数组的第一个或最后一个成员是一个空字符串。
'|b|c'.split('|') // ["", "b", "c"]
'a|b|'.split('|') // ["a", "b", ""]
  • split方法还可以接受第二个参数,限定返回数组的最大成员数。
'a|b|c'.split('|', 0) // []
'a|b|c'.split('|', 1) // ["a"]
'a|b|c'.split('|', 2) // ["a", "b"]
'a|b|c'.split('|', 3) // ["a", "b", "c"]
'a|b|c'.split('|', 4) // ["a", "b", "c"]

上面代码中,split方法的第二个参数,决定了返回数组的成员数。

2.字符串的拼接:String.prototype.concat()

  • concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
var s1 = 'abc';
var s2 = 'def';
s1.concat(s2) // "abcdef"
s1 // "abc"
  • 该方法可以接受多个参数。
    'a'.concat('b', 'c') // "abc"
  • 如果参数不是字符串,concat方法会将其先转为字符串,然后再连接。
var one = 1;
var two = 2;
var three = '3';

''.concat(one, two, three) // "123"
one + two + three // "33"

上面代码中,concat方法将参数先转成字符串再连接,所以返回的是一个三个字符的字符串。作为对比,加号运算符在两个运算数都是数值时,不会转换类型,所以返回的是一个两个字符的字符串。

3.字符串的提取:

(1)String.prototype.slice()

slice方法用于从原字符串取出子字符串并返回,不改变原字符串。它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
'JavaScript'.slice(0, 4) // "Java"

  • 如果省略第二个参数,则表示子字符串一直到原字符串结束。
    'JavaScript'.slice(4) // "Script"
  • 如果参数是负值,表示从结尾开始倒数计算的位置,即该负值加上字符串长度。
'JavaScript'.slice(-6) // "Script"
'JavaScript'.slice(0, -6) // "Java"
'JavaScript'.slice(-2, -1) // "p"
  • 如果第一个参数大于第二个参数,slice方法返回一个空字符串。
    'JavaScript'.slice(2, 1) // ""
(2)String.prototype.substr()

substr方法用于从原字符串取出子字符串并返回,不改变原字符串,跟slice和substring方法的作用相同。

  • substr方法的第一个参数是子字符串的开始位置(从0开始计算),第二个参数是子字符串的长度。
    'JavaScript'.substr(4, 6) // "Script"
  • 如果省略第二个参数,则表示子字符串一直到原字符串的结束。
    'JavaScript'.substr(4) // "Script"
  • 如果第一个参数是负数,表示倒数计算的字符位置。如果第二个参数是负数,将被自动转为0,因此会返回空字符串。
'JavaScript'.substr(-6) // "Script"
'JavaScript'.substr(4, -1) // ""

上面代码中,第二个例子的参数-1自动转为0,表示子字符串长度为0,所以返回空字符串。

(二)数组

1.添加元素:push(),unshift()

  • push方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var arr = [];

arr.push(1) // 1
arr.push('a') // 2
arr.push(true, {}) // 4
arr // [1, 'a', true, {}]

上面代码使用push方法,往数组中添加了四个成员。

  • unshift()方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];

a.unshift('x'); // 4
a // ['x', 'a', 'b', 'c']

unshift()方法可以接受多个参数,这些参数都会添加到目标数组头部。

var arr = [ 'c', 'd' ];
arr.unshift('a', 'b') // 4
arr // [ 'a', 'b', 'c', 'd' ]

2.删除元素:pop(),shift()

  • pop方法用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。
var arr = ['a', 'b', 'c'];

arr.pop() // 'c'
arr // ['a', 'b']

对空数组使用pop方法,不会报错,而是返回undefined。
[].pop() // undefined
push和pop结合使用,就构成了“后进先出”的栈结构(stack)。

var arr = [];
arr.push(1, 2);
arr.push(3);
arr.pop();
arr // [1, 2]

上面代码中,3是最后进入数组的,但是最早离开数组。

  • shift()方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];

a.shift() // 'a'
a // ['b', 'c']

上面代码中,使用shift()方法以后,原数组就变了。

shift()方法可以遍历并清空一个数组。

var list = [1, 2, 3, 4];
var item;

while (item = list.shift()) {
  console.log(item);
}

list // [

上面代码通过list.shift()方法每次取出一个元素,从而遍历数组。它的前提是数组元素不能是0或任何布尔值等于false的元素,因此这样的遍历不是很可靠。
push()和shift()结合使用,就构成了“先进先出”的队列结构(queue)。

4.splice()

splice方法用于删除原数组的一部分成员,并可以在删除的位置添加新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。
arr.splice(start, count, addElement1, addElement2, ...);
splice的第一个参数是删除的起始位置(从0开始),第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。

var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2) // ["e", "f"]
a // ["a", "b", "c", "d"]

上面代码从原数组4号位置,删除了两个数组成员。

var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2, 1, 2) // ["e", "f"]
a // ["a", "b", "c", "d", 1, 2]

上面代码除了删除成员,还插入了两个新成员。

  • 起始位置如果是负数,就表示从倒数位置开始删除。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(-4, 2) // ["c", "d"]

上面代码表示,从倒数第四个位置c开始删除两个成员。

  • 如果只是单纯地插入元素,splice方法的第二个参数可以设为0。
var a = [1, 1, 1];

a.splice(1, 0, 2) // []
a // [1, 2, 1, 1]
  • 如果只提供第一个参数,等同于将原数组在指定位置拆分成两个数组。
var a = [1, 2, 3, 4];
a.splice(2) // [3, 4]
a // [1, 2]

4.合并数组:concat()

concat方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。

['hello'].concat(['world'])
// ["hello", "world"]

['hello'].concat(['world'], ['!'])
// ["hello", "world", "!"]

[].concat({a: 1}, {b: 2})
// [{ a: 1 }, { b: 2 }]

[2].concat({a: 1})
// [2, {a: 1}]

除了数组作为参数,concat也接受其他类型的值作为参数,添加到目标数组尾部。

[1, 2, 3].concat(4, 5, 6)
// [1, 2, 3, 4, 5, 6]

如果数组成员包括对象,concat方法返回当前数组的一个浅拷贝。所谓“浅拷贝”,指的是新数组拷贝的是对象的引用。

var obj = { a: 1 };
var oldArray = [obj];

var newArray = oldArray.concat();

obj.a = 2;
newArray[0].a // 2

上面代码中,原数组包含一个对象,concat方法生成的新数组包含这个对象的引用。所以,改变原对象以后,新数组跟着改变。

5.提取数组:slice()

slice方法用于提取目标数组的一部分,返回一个新数组,原数组不变。
arr.slice(start, end);
它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。

var a = ['a', 'b', 'c'];

a.slice(0) // ["a", "b", "c"]
a.slice(1) // ["b", "c"]
a.slice(1, 2) // ["b"]
a.slice(2, 6) // ["c"]
a.slice() // ["a", "b", "c"]

上面代码中,最后一个例子slice没有参数,实际上等于返回一个原数组的拷贝。

  • 如果slice方法的参数是负数,则表示倒数计算的位置。
var a = ['a', 'b', 'c'];
a.slice(-2) // ["b", "c"]
a.slice(-2, -1) // ["b"]

上面代码中,-2表示倒数计算的第二个位置,-1表示倒数计算的第一个位置。

  • 如果第一个参数大于等于数组长度,或者第二个参数小于第一个参数,则返回空数组。
var a = ['a', 'b', 'c'];
a.slice(4) // []
a.slice(2, 1) // []
  • slice方法的一个重要应用,是将类似数组的对象转为真正的数组。
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })
// ['a', 'b']

Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);

上面代码的参数都不是数组,但是通过call方法,在它们上面调用slice方法,就可以把它们转为真正的数组。

6.数组转字符串:

join()方法以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。

var a = [1, 2, 3, 4];

a.join(' ') // '1 2 3 4'
a.join(' | ') // "1 | 2 | 3 | 4"
a.join() // "1,2,3,4"
  • 如果数组成员是undefined或null或空位,会被转成空字符串。
[undefined, null].join('#')
// '#'

['a',, 'b'].join('-')
// 'a--b'
  • 通过call方法,这个方法也可以用于字符串或类似数组的对象。
Array.prototype.join.call('hello', '-')
// "h-e-l-l-o"

var obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-')
// 'a-b'

(二)性能优化

1.优化的思路

加载的优化
体验的优化

  • 加载的优化
    网络越快越好:
    使用CDN
    东西体积越少越好:
    前端所有资源压缩(特别是图片),
    东西数量越少越好:
    icon,css,js等资源打包合并
    服务器处理的越快越好
    能重复利用的最好重复利用
  • 体验的优化
    只给用户暂时需要的东西
    别让用户感觉卡顿
    动画不要卡:
    优先使用css3的动画,

2.页面优化

  • 内容方面:
    减少 HTTP 请求 (Make Fewer HTTP Requests)
    减少 DOM 元素数量 (Reduce the Number of DOM Elements)
    使得 Ajax 可缓存 (Make Ajax Cacheable)
  • 针对CSS:
    把 CSS 放到代码页上端 (Put Stylesheets at the Top)
    从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External)
    精简 JavaScript 与 CSS (Minify JavaScript and CSS)
    避免 CSS 表达式 (Avoid CSS Expressions)
  • 针对JavaScript :
    脚本放到 HTML 代码页底部 (Put Scripts at the Bottom)
    从页面中剥离 JavaScript 与 CSS (Make JavaScript and CSS External)
    精简 JavaScript 与 CSS (Minify JavaScript and CSS)
    移除重复脚本 (Remove Duplicate Scripts)
  • 面向图片(Image):
    优化图片
    不要在 HTML 中使用缩放图片
    使用恰当的图片格式
    使用 CSS Sprites 技巧对图片优化

3.页面卡的原因

4.浏览器本地存储

  1. js中包含sessionStorage和localStorage以及cookie三种浏览器端的数据存储方式。
    sessionStorage 、localStorage 和 cookie 之间的共同点:都是保存在浏览器端,且同源的。
    sessionStorage 、localStorage 和 cookie 之间的区别:
  2. cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有网址路径(path)的概念,可以限制cookie只属于某个网址路径下。
  3. 存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
  4. 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
  5. 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。

2.使用方法

  • sessionstorage
    sessionStorage.setItem("name","luanpeng"); //添加存储key-value
    sessionStorage.age = 12; //设置数据
    for(var key in sessionStorage) //遍历数据
    console.log(sessionStorage.getItem(key)); //getItem读取属性值
    delete sessionStorage.name; //删除数据
    sessionStorage.removeItem("age"); //删除数据

  • localstorage

  • localstorage同一个对象访问必须域名相同。数据保留至用户删除或清除缓存
    localStorage.setItem("name","luanpeng"); //添加设置属性
    localStorage.age = 12; //添加设置
    console.log(localStorage.getItem("age")); //读取
    console.log(localStorage.name); //读取
    cookie
    export const cookie = {

    //根据key值获取对应的cookie
    get: (key) => {

      //获取cookie
      const data = document.cookie;
      //获取key第一次出现的位置    pwd=
      let startIndex = data.indexOf(key+'=');
      //  name=123;pwd=abc
      //如果开始索引值大于0表示有cookie
      if(startIndex>-1) {
    
          //key的起始位置等于出现的位置加key的长度+1
          startIndex = startIndex+key.length+1;
    
          //结束位置等于从key开始的位置之后第一次;号所出现的位置
    
          let endIndex = data.indexOf(';',startIndex);
    
          //如果未找到结尾位置则结尾位置等于cookie长度,之后的内容全部获取
          endIndex = endIndex<0 ? data.length:endIndex;
    
          return decodeURIComponent(data.substring(startIndex,endIndex));
    
    
      }else {
    
          return '';
      }
    

    },

    set:(key,value,time) => {
    //默认保存时间
    var time = time;
    //获取当前时间
    let cur = new Date();
    //设置指定时间
    cur.setTime(cur.getTime()+time243600*1000);

      //创建cookie  并且设置生存周期为GMT时间
      document.cookie = key+'='+encodeURIComponent(value)+';expires='+(time===undefined?'':cur.toGMTString());
    

    },

    del:function(key){

      //获取cookie
      const data = this.get(key);
    
      //如果获取到cookie则重新设置cookie的生存周期为过去时间
      if(data!==false){
    
          this.set(key,data,-1);
    
      }
    

    }

};

3.注意点
localStorage和sessionStorage只能存储字符串类型的对象;
localStorage是永久存储的,除非用户显示的删除;
sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页关闭了sessionStorage将清空;
不同浏览器不能共享sessionStorage和localStorage中的信息;
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。

4.web缓存

  1. 前端缓存概述
    前端缓存主要是分为HTTP缓存和浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。下面会分别具体描述。
  2. 前端缓存分类
    2.1 HTTP缓存
    整体流程:HTTP缓存都是从第二次请求开始的。
    第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,击中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否击中协商缓存,击中则返回304,否则服务器会返回新的资源。

cookie 和 session
cookie
cookie是存储在浏览器上的一小段数据,用来记录某些当页面关闭或者刷新后仍然需要记录的信息。在控制台用 「document.cookie」查看你当前正在浏览的网站的cookie。

cookie可以使用 js 在浏览器直接设置(用于记录不敏感信息,如用户名), 也可以在服务端通使用 HTTP 协议规定的 set-cookie 来让浏览器种下cookie,这是最常见的做法。(打开一个网站,清除全部cookie,然后刷新页面,在network的Response headers试试找一找set-cookie吧)

每次网络请求 Request headers 中都会带上cookie。所以如果 cookie 太多太大对传输效率会有影响。
一般浏览器存储cookie 最大容量为4k,所以大量数据不要存到cookie。
设置cookie时的参数:

path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
expires 和 maxAge:告诉浏览器 cookie 时候过期,maxAge 是 cookie 多久后过期的相对时间。不设置这两个选项时会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效
httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss 攻击拿到cookie。
测试: 很多网站的静态资源使用CDN地址而是使用当前网站域名,从cookie的角度说说这对性能有何影响?

session
当一个用户打开淘宝登录后,刷新浏览器仍然展示登录状态。服务器如何分辨这次发起请求的用户是刚才登录过的用户呢?这里就使用了session保存状态。用户在输入用户名密码提交给服务端,服务端验证通过后会创建一个session用于记录用户的相关信息的对象,这个 session 可保存在服务器内存中(容易产生内存泄露),生产环境一般是保存在数据库中。

创建session后,会把关联的session_id 通过setCookie 添加到http响应头部中。
浏览器在加载页面时发现响应头部有 set-cookie字段,就把这个cookie 种到浏览器指定域名下。
当下次刷新页面时,发送的请求会带上这条cookie, 服务端在接收到后根据这个session_id来识别用户。
cookie 是存储在浏览器里的一小段「数据」,而session是一种让服务器能识别某个用户的「机制」,当然也可以特指服务器存储的 session 数据。session 在实现的过程中需要使用cookie。

页面要显示英文或者中文怎么显示相应的文字?
多语言的切换界面大概就分三步走:
1.前端页面多语言
2.数据库多语言
3.用户访问语言统一
第一步:页面多语言
需要考虑的问题是:
A.用户登陆时候,自动识别字符,调用不同的语言包?
B.用户切换不同语言时候,调用不同的语言包?
C.增加多语言后的目录结构?
页面多语言也就是外观的多语言化,这里可以采用静态的语言包的方式。
设计时候就应该包括language的目录,针对不同语言有独立的子目录。
如英文language/en ,简体中文language/gb,繁体中文language/b5 (可以扩展其他语言)
每个目录下就包含了对每个页面的语言版本。选择语言版本时候就可以调用相应版本的语言包。
2.数据库多语言
这个考虑的问题:
A.后台录入数据的多语言化?
B.用户在不同版本下,提交的内容,如何保存?
C.提供三种语言包,还是提供英文和简体,简体通过转化提供繁体?

数据库多语言就是达到多语言在数据库里面的统一。就需要采用utf-8统一编码。
无论什么语言的文字,都统一使用utf-8来存放到数据库里面。采用表字段来表识
属于什么语言版本的文字。
3.简体转化的繁体。
利用php的iconv.此过程对于linux/unix有效,对于windows无效。
iconv("GB2312","BIG5",$text);
4.因为,charset = "utf-8",数据就都是以utf-8编码方式存在,
添加数据时候,要分别用en/gb/big5来标识语言版本.
INSERT INTO zz_importer VALUES (,'', '', 'en');
INSERT INTO zz_importer VALUES (,'', '', 'gb');
INSERT INTO zz_importer VALUES (,'', '', 'big5');
vue.js的优点
Vue.js的特点:MVVM框架、数据驱动、组件化、轻量、简洁、高效、快速、模块友好

其实Vue.js不是一个框架,因为它只聚焦视图层,是一个构建数据驱动的Web界面的库。

 Vue.js通过简单的API(应用程序编程接口)提供高效的数据绑定和灵活的组件系统。

 Vue.js的特性如下:

1.轻量级的框架

2.双向数据绑定

3.指令

4.插件化

优点: 1. 简单:官方文档很清晰,比 Angular 简单易学。

2. 快速:异步批处理方式更新 DOM。

3. 组合:用解耦的、可复用的组件组合你的应用程序。

4. 紧凑:~18kb min+gzip,且无依赖。

5. 强大:表达式 & 无需声明依赖的可推导属性 (computed properties)。

6. 对模块友好:可以通过 NPM、Bower 或 Duo 安装,不强迫你所有的代码都遵循 Angular 的各种规定,使用场景更加灵活。

缺点: 1. 新生儿:Vue.js是一个新的项目,没有angular那么成熟。

2. 影响度不是很大:google了一下,有关于Vue.js多样性或者说丰富性少于其他一些有名的库。

3. 不支持IE8:

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

推荐阅读更多精彩内容