普歌-码上鸿鹄团队复习总结:JavaScript进阶重点(DOM、BOM)

定义

  1. Dom
  • <font color="#000">文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理HTML/XML的标准API接口.</font >
  • <font color="#000">提供对文档的结构化描述,定义方式对结构进行访问并进行修改结构,样式和内容</font>
  • <font color="#000">顶级对象时是document</font>
  1. Bom
  • <font color="#000">浏览器对象模型(Browser Object Model,简称BOM)</font>
  • <font color="#000">提供了独立于内容而与浏览器窗口交互的对象</font>
  • <font color="#000">顶级对象是window</font>
  1. DOM和BOM的区别(对比图)
==DOM== ==BOM==
文档对象模型 浏览器对象模型
DOM把[<font color="red">文档</font>]当做一个[<font color="red">对象</font>]来看待 BOM把[<font color="red">浏览器</font>]当做一个[<font color="red">对象</font>来看待
DOM的顶级对象是<font color="red">document</font> BOM的顶级对象是<font color="red">window</font>
DOM主要学习的是操作页面元素 BOM学习的是浏览器窗口交互的一些对象
DOM是W3C标准规范 BOM是浏览器厂商在各自浏览器上定义的,兼容性差
  1. dom和bom的关系结构图
    DOM和BOM关系结构图:

一、DOM

1. dom树

dom树:

<ul>
<li>文档: 一个页面就是一个文档,DOM中使用document表示</li>
<li>元素: 页面中的所有标签都是元素,DOM中使用element表示</li>
<li>节点: 网页中的所有内容都是节点(标签,属性,文本,注释等),DOM中使用node表示</li>
</ul>

2. document对象

<font size=4 color='#42b983'>提示:</font>


\color{#000}{ document对象对应整个文档,整个文档相关的操作和编程的api都是通过document对象进行实现}

2.1 常用属性

  • URL: 获取当前文档的URL地址,只读
document.URL
  • title: 获取当前文档Head中的title的文字内容,可写入修改
document.title

2.2 获取文档元素

 // 根据id,返回Element
getElementById('元素id')
//根据标签名获取(如果是*,返回所有),返回HTMLCollection集合
getElementsByTagName('标签名')
// 根据name属性,返回NodeList集合
getElementsByName(name) 
//根据元素类名返回元素对象集合
getElementByClassName('元素类名') 
// 根据css选择器返回第一个元素对象
querySelector('选择器') 
// 根据css选择器返回所有指定元素,多个选择器以逗号分隔querySelectorAll( 'p,a')
querySelectorAll('选择器') 

2.3 获取特殊元素(body,html)

// 获取body元素
const bodyElem = document.body;  //返回body元素对象
// 获取Html元素
const htmlElem = document.documentElement;  //返回html元素对象

3. 元素对象

3.1 Element

// Element对象是所有标签元素的基础对象,封装了所有标签元素的公共方法与属性
// 常用属性
Element.attributes              // 获得所有属性key-value集合
Element.className               // 获得类名(可读写)=>idea:elem.className = 'pink',然后再css定义
                                // 注意:此方法会覆盖原有类名
============================^_^============================
Element.classList               // 返回一个元素的类属性的实时 DOMTokenList 集合(只读),通过其内部方法修改
                                // ie10+,
============================^_^============================                             
Element.id                      // 获取元素id
Element.innerHTML               // 获取元素内部包裹的html标签字符串(可读写)
Element.innerText               // 获取元素内部文本,标签不识别会直接进行显示(可读写)
Element.tagName                 // (只读)获取元素的标签名字符串
Element.style                   // 获取/修改style样式,如Element.style.backgroundColor


// 常用方法
Element.getAttribute(attrName)      // 返回属性的字符串值,适合获取自定义属性data-
Element.removeAttribute(attrName)   // 从指定的元素中删除一个属性
Element.setAttribute(attrName,value)// 设置属性
Element.hasAttribute(attrName)      // 检测属性是否存在
Element.getElementsByClassName()    // 获取后代元素根据className
Element.getElementsByTagName()      // 获取后代元素根据tagName
...

Element.dataset.index | Element.dataset['index']  // 用于获取data-自定义属性(h5新增),支持驼峰命名获取(ie11+)

3.2 HTMLCollection

// HTMLCollection对象,是伪数组。元素的动态集合,提供了用来从该集合选择元素的方法和属性,当其所包含的文档结构发生改变时,会自动更新.
// 常用属性
HTMLCollection.length       // 返回集合中子元素的数组

============================^_^============================     

// 常用方法
HTMLCollection.item()       // 根据给定的索引(从0开始),返回具体的节点
HTMLCollection.namedItem()  // 根据 Id 返回指定节点,或者作为备用,根据字符串所表示的 name 属性来匹配

4. 节点操作

<font size=4 color='#e7c000'>WARNING:</font>


\color{#000}{ 一般的,节点至少拥有nodeType(节点类型),nodeName(节点名称),nodeValue(节点值)}

  • 元素节点 nodeType为1
  • 属性节点 nodeType为2
  • 文本节点 nodeType为3(文本几点包含文字,空格,换行等)

4.1 节点层级

  • 父级节点
    //parentNode属性可返回某节点的父节点,注意是最近的一个父节点(亲爸爸)
    node.parentNode // 找不到返回null
  • 子节点
parentNode.childNodes           // 注意: 会返回3种子节点=>如果指向某种节点,可通过nodeType判断
parentNode.firstChild           // 返回第一个子节点(会包括3种节点)
parentNode.lastChild            // 获取最后一个子节点(会包括3种节点)

parentNode.children             // 只获取子元素节点
parentNode.firstElementChild    // 获取第一个子元素节点(ie9+)
parentNode.lastElementChild     // 获取最后一个子元素节点(ie9+)

<font color="red">*注意:
parentNode.childNodes 返回值里包含了所有子节点,包括元素节点,文本节点等
</font>

  • 兄弟节点
node.nextSibling                // 当前元素的下一个兄弟节点(会包含3种节点)
node.previousSibling            // 当前元素的上一个兄弟节点(会包含3种节点)

node.nextElementSibling         // 当前元素的下一个兄弟元素节点(IE9+)
node.previousElementSibling     // 当前元素的上一个兄弟元素节点(IE9+)
  • 节点创建与添加
// 创建节点
let li = document.createElement('li');
// 在已有子节点后面追加节点(不会覆盖原有节点)
parentNode.appendChild(li);
// 在指定子节点前面追加节点(不会覆盖原有节点)
parentNode.insertBefore(child,指定子元素)
  • 节点移除
parentNode.removeChild(child节点)     // 删除父元素的某个子节点
  • 节点复制
node.cloneNode()    // 拷贝node节点=>浅拷贝,只拷贝标签,不拷贝里面内容
node.cloneNode(true)// 拷贝node节点=>深度拷贝,拷贝标签以及里面内容
  • 三种动态创建元素的区别
document.write('<div>123</div>')        // 注意:当页面文档流加载完毕,会进行重绘
element.innerHTML = '<div>123</div>'    // 不要重复拼接字符串,内存消耗过大
document.createElement()                

5.DOM事件

5.1 鼠标事件

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发
oncontextmenu 阻止鼠标右键菜单(阻止默认行为)
onselectstart 禁止鼠标选取内容(阻止默认行为)
onselect 禁止复制(阻止默认行为)
  • mouseenter和mouseover区别

mouseover经过自身会触发,经过子级也会再次触发(支持事件冒泡).mouseenter只有经过自身盒子才触发(不支持事件冒泡)

备注:mouseover搭配mouseout;mouseenter搭配mouseleave

5.2 键盘事件

<font color="red" face="宋体" size=5>三个事件的执行顺序: keydown > keypress > keyup</font>

键盘事件 触发条件
keyup 某个键盘按键松开触发
keydown 某个键盘按键按下时触发,只要不松开会一直触发
keypress 某个键盘按键按下时触发,不识别功能键(ctrl,上下箭头等),只要不松开会一直触发
键盘事件的示例:

5.3 注册事件

注:注册事件有两种方式:传统方式和监听方式

  • 传统方式: 使用on前缀 => 事件注册<font color="#ca0c16">具有唯一性,后者会覆盖前者</font>
<p onclick="alert(123)">
  点击  
</p>
//最后只能弹出来"点击段落"的弹框,后者覆盖了前者
const elem = document.querySelector('p')
elem.onclick = function() {
    alert('点击段落');
}

// 解绑事件
elem.onclick = null
  • 监听方式
// true:事件句柄在捕获阶段执行 false(默认):事件句柄在冒泡阶段执行
// 注意:解除绑定与绑定的事件内存地址需要相同
let div = document.getElementById('div')
function listener(event) {
    
}
div.addEventListener('click',listener,true)
div.removeEventListener('click',listener,true)

// ie9以前使用attachEvent,处理兼容性再用吧
div.attachEvent('onclick',method) // 绑定
div.detachEvent('onclick',method) // 移除
监听方式处理兼容:

5.4 触屏事件对象(touchEvent)

touchEvent是一类描述手指在触摸平面(触摸屏等)的状态变化的事件对象,这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少等

touchEvent对象 说明
event.touches 正在触摸屏幕的所有手指的一个列表(==可判断双指还是单指触屏==)
event.targetTouches 正在触摸当前dom元素上的手指的一个列表
event.changedTouches 手指状态发生了改变的列表,从无到有,从有到无变化

5.5 事件流

事件分为捕获阶段与冒泡阶段.捕获阶段就是事件信息从顶层向下层传递的过程,冒泡时事件反应处理从底层向上层反馈的过程。

事件流

js可以通过addEventListener来实现捕获阶段或者冒泡阶段的事件响应方法注册

5.6 事件对象

  • 什么是事件对象
    事件对象的解释

<font size=3>事件对象鼠标事件(MouseEvent),则记录鼠标相关信息,如坐标等;键盘事件(KeyboardEvent),则记录键盘相关信息,如点击的哪个按键</font>

elem.onclick = function(event) { // 此处的event就是事件对象
    event.target                 // 返回触发事件的元素,不同于this返回的是绑定事件的元素
    event.srcElement             // 同event.target,ie兼容处理使用(ie6,7,8),非标准
    event.relatedTarget          // 返回绑定事件的元素,类似于this
    event.type                   // 获取事件触发类型,如click、mouseover,不带on
    event.pageX | event.pageY    // 获取光标相对于页面的x坐标和y坐标 ie9+
    event.clientX | event.clientY// 获取光标相对可视区域的x坐标与y坐标(不受滚动条影响)
    event.screenX | event.screenY// 获取光标相对电脑屏幕的x坐标与y坐标
    event.which                  // 代表获取到的鼠标或键盘的输出的值,鼠标分别为0,1,2
    event.key                    // 获取按下的按键值
    event.keyCode                // 获取按下按键的ascii码值
}

5.7 默认行为与冒泡阻止

  • 常见html默认行为
~ Submit按钮: 在form表单中的,提交form表单中的数据到服务器
~ Button: 在手机浏览器中, 若是在form中,则是submit
~ a标签: 默认将当前页面跳转为a标签中href的地址
  • 阻止事件默认行为
<!-- 方式4 -->
<a onclick="javascript:;">点击</a>
<script>
    const a = document.querySelector('a');
    a.onclick = function(event) {
        // 方式1
        event.preventDefault()
        // 方式2,低版本ie使用
        event.returnValue()
        // 方式3,addEventListener注册方式无效
        return false 
    }
</script>
  • 阻止冒泡
<div class="parent">
    <div class="child"></div>
</div>
<script>
    const pElem = document.querySelector('.parent')
    const cElem = document.querySelector('.child')
    cElem.onclick = function(event) {
        // 标准: 阻止冒泡
        event.stopPropagation()
        // 非标准: 阻止冒泡(ie678)
        event.cancalBabel = true
    }
</script>

兼容性写法:


阻止冒泡的兼容写法

5.8 事件委托

事件委托又叫事件代理,jquery里面称为事件委派

  • 原理: 不再每个子节点单独设置事件监听器(提高了性能),而是将事件监听器设置再父级元素上,然后利用冒泡原理影响每个子节点


    事件委托原理
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>

<script>
    const ul = document.querySelector('ul');
    ul.addEventListener('click', event => {
        // 不用单独每个li绑定事件
        //event.target可以得到我们点击的对象
        console.log(event.target);
    });
</script>

二、BOM

<font size=3 color="#000">BOM没有标准组织,ECMA有ECMA组织,DOM有W3C组织制定,而BOM还是在延用网景的标准,兼容较差</font>

  • 它是js访问浏览器窗口的一个接口
  • 它是一个全局对象,定义在全局作用域的变量,函数都会变成window对象的属性和方法 => this指向问题产生

1. Window对象

1.1 属性

window.innerWidth   // 获取当前屏幕宽度,tip 可用来做响应式布局,还是推荐媒体查询,flex做响应式布局
window.innerHeight  // 获取当前屏幕高度

1.2 方法

window.scroll(x,y)  // 滚动窗口至文档中的特定位置 => such: window.scroll(0,0) 滚动到页面顶部

1.3 事件

  • 窗口加载事件
window.onload = function() {}
// 或
window.addEventListener('load',function() {})

// window.onload是窗口加载事件,当文档内容完全加载会触发该事件(包括图像,脚本文件,css文件等)
// window.onload传统注册事件只能写一次,如果多次会以最后一个为准,addEventListener没有此问题

window.addEventListener('DOMContentLoaded',function(){}) // 只要dom文档加载完就会触发监听事件
  • 窗口大小调整事件
// 窗口大小发生变化,就会触发
window.onresize = function() {}
window.addEventListener('resize',function() {})

2. location对象

2.1 属性

location对象属性 返回值
location.href 获取或设置整个URL
location.host 返回主机域名
location.port 返回端口号
location.pathname 返回路径
location.search 返回参数
location.hash 返回锚点

2.2 方法

location.assign()       // 跟href相同,实现跳转页面
location.replace()      // 替换当前页面,因为不记录历史,所以不能后退页面
location.reload()       // 重新加载页面,参数为true会强制刷新

2.3 URL(同一资源定位符)

url的一般语法格式为:
protocol://host[:port]/path/[?jquery]#fragment
https://www.baidu.com/index.html?name=andy&age=18#link

URL

组成 说明
protocol 通信协议,如http,https,ftp,maito
host 主机(域名)
port 端口(默认80)
path 资源路径;由零或多个"/"隔开的字符串
query 参数,以键值对形式,通过&符来隔开
fragment 锚点;#后面内容

3. navigator对象

navigator对象包含了很多设备相关属性例如操作系统,版本号等信息


navigator对象信息
// case: 使用userAgent识别手机pc
if(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
    window.location.href = ''; //手机
} else {
    window.location.href = ''; //电脑
}

4. history对象

window对象为我们提供了一个history对象,与浏览器历史记录进行交互,该对象包含用户(在浏览器窗口中)访问过的URL

history对象方法 作用
back() 实现后退
forward() 实现前进
go(参数) 前进后退功能,参数是1: 前进一个页面,-1:后退一个页面

5. 定时器

  • setInterval(重复执行,每次调用有时间延迟)
let inervalId = setInterval(code, milliseconds);
let inervalId = setInterval(function, milliseconds, param1, param2, ...)
  • setTimeOut(只执行一次,延迟delay毫秒后执行)
let interValId = setTimeOut(fn,delay)
  • 清除延迟
clearInterVal(inervalId)     // 对应setInterval
clearTimeOut(inervalId)      // 对应setTimeOut
  • 标题跑马灯效果实现
// 数组方式实现跑马灯效果
setInterval(() => {
    let title = [...document.title];
    title.unshift(title.pop());
    document.title = title.join('');
}, 500);

// 字符串方式实现跑马灯
setInterval(() => {
    let oldTitle = document.title;
    let newTitle = oldTitle.slice(-1).concat(oldTitle.slice(0, -1));
    document.title = newTitle;
}, 500);

6. JS执行机制

6.1 JS是单线程

javascript就是为了处理页面中用户的交互以及操作DOM而产生,js是单线程 => 这就意味着所有任务都需要排队,前一个任务执行结束才能执行下一个任务。导致某个js流程执行时间过长,页面渲染就不连贯,造成页面阻塞

6.2 同步和异步

为了解决js的单线程阻塞问题,利用多核CPU的计算能力,HTML5提出Web Worker标准,允许Javascript脚本创建多个线程。

  • 同步: 前一个任务执行完毕才进行下一任务

    注意: 同步任务都在主线程上执行,形成一个执行栈
    
  • 异步: 前一任务执行过程种,同时执行另一任务

    JS的异步任务都是通过回调函数来处理,如监听事件,点击事件等
    

6.3 执行机制

  • 先执行执行栈的同步任务
  • 异步任务(回调函数)放到任务队列中
  • 一旦执行栈中的同步任务执行完毕,系统就会依次执行任务队列中的异步任务


    执行机制

三、网页特效

1. 元素偏移量offset

使用offset相关属性,可以动态获取该元素的位置(偏移),大小等.

  • 注意: 返回值是不带单位的
  • 获得元素距离带有定位父元素的位置
  • 获取元素自身大小(宽度和高度)
offset系列属性 作用
element.offsetParent 返回该元素带有定位的父级元素,如何父级都没有定位返回body
element.offsetTop 返回元素相对带有定位父元素上方的偏移
element.offsetLeft 返回元素相对带有定位父元素左边框的偏移
element.offsetWidth 返回自身包括内边距,边框,内容区的宽度 => border+padding+width
element.offsetHeight 返回自身包括内边距,边框,内容区的高度=> border+padding+width
  • offset与style区别(宽度)
offset style
offset可以得到任意样式表中的样式值 只能得到行内样式表的样式值,css中的获取不到
获得的数值没有单位 获得的是有单位的字符串
offsetWidth包含padding+border+width style.width不包含padding和border
offsetWidth只读 style.width可读写
适合获取元素大小位置 适合修改元素值

2. 元素可视区client

通过client的相关属性可以动态获取该元素的边框大小,元素大小等

  • 注意: 返回值是不带单位的
client 作用
element.clientTop 返回元素上边框的大小
element.clientLeft 返回元素左边框的大小
element.clientWidth 返回自身包括padding,内容区宽度,不包含边框
element.clientHeight 返回自身包括padding,内容区高度,不包含边框

3. 元素滚动scroll

通过scroll可以动态获取该元素的大小,滚动距离等

  • 注意: 返回值是不带单位的
scroll 作用
element.scrollTop 返回被卷去的上侧距离
element.scrollLeft 返回被卷去的左侧距离
element.scrollWidth 返回自身实际的宽度,不含边框,包含padding
element.scrollHeight 返回自身实际的高度,不含边框,包含padding

<font color="red">注意: 页面的滚动距离通过window.pageXOffset获取</font>

四、动画

1.封装动画函数

 (function () {
        function animate(obj, target, comeback) {
          //让我们只有一个定时器执行
          //先清除以前的定时器,只保留当前的一个定时器执行
          clearInterval(obj.timer);
          obj.timer = setInterval(function () {
            //步长值写到定时器里
            //var step=Math.ceil((target-obj.offsetLeft)/10);
            varstep = (target - obj.offsetLeft) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (obj.offsetLeft == target) {
              //停止动画本质是停止定时器
              clearInterval(obj.timer);
              //回调函数写到定时器结束里面
              //if(comeback){
              //comeback();
              //}
              comeback && comeback();
            }
            //这个步长值改为一个慢慢变小的值步长公式:(目标值-现在的位置)/10
            obj.style.left = obj.offsetLeft + step + "px";
          }, 15);
        }
      });

2. 缓动动画

缓动动画原理

五、本地存储

本地存储特性:

  • 数据存储在用户浏览器中
  • 设置,读取方便,甚至页面刷新不丢失数据
  • 容量较大,sessionStorage约5M,localStorage约20M
  • 只能存储字符串,对象转json后再存储

1. window.sessionStroage

  • 生命周期为关闭浏览器窗口
  • 在同一窗口(页面)下数据可以共享
  • 以键值对的形式存储使用
const user = { name: '隔壁老高', age: 18 }

// sessionStorage
// 存储数据
sessionStorage.setItem('user', JSON.stringify(user, null, 2))
// 修改数据 => 重新存储即可
// 读取数据
sessionStorage.getItem('user')
// 删除数据
sessionStorage.removeItem('user')
// 清空数据
sessionStorage.clear()

2. window.localStorage

  • 生命周期永久生效,除非手动删除否则关闭页面也会存在
  • 可以多窗口(页面)共享(同一浏览器可以共享数据)
  • 以键值对的形式存储使用
const user = { name: '隔壁老高', age: 18 }

// localStorage
// 存储数据
localStorage.setItem('user', JSON.stringify(user, null, 2))
// 修改数据 => 重新存储即可
// 读取数据
localStorage.getItem('user')
// 删除数据
localStorage.removeItem('user')
// 清空数据
localStorage.clear()

~有问题可以评论区留言,喜欢的小伙伴可以点赞、关注、收藏哦 \color{red}{♥♥♥}


<font size=4>相关推荐:wantLG的《普歌-码上鸿鹄团队复习总结:js 高级 ECMAScript 6(es6新特性)(上)》</font>


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