第十一节 JavaScript DOM 操作

之前学习的属于JS的核心语法,ECMA的语法,接下来开始我们就要学习JS控制页面上的元素了。

1. DOM认知

DOM(Document Object Model,文档对象模型)描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。这使得JavaScript操作HTML,不是在操作字符串,而是在操作节点,极大地降低了编程难度。

DOM对很多东西做了抽象,提供了丰富的API:取得元素、css样式、事件、运动、元素尺寸位置、节点操作。每个知识体系都非常庞大,千丝万缕。

DOM的结构呈树状,所以也把DOM叫做DOM树,DOM树是由很多DOM节点组成的

2. 认识DOM节点

2.1 DOM树
ddd.jpg
2.2 DOM 常用节点

元素节点 1
属性节点 2
文本节点 3
注释节点 8
document 文档节点 9
DocumentFragment 文档片段节点 11

2.3 DOM节点属性

nodeName 元素节点的标签名,以大写字母的形式表示,只读不能修改
nodeValue 文本节点和注释节点的内容,可读可写
nodeType 节点的类型(最有用的),帮助我们区分节点,只读
attributes 元素节点的属性集合(只能修改属性值), name 属性名,value 属性值

3. 获取DOM元素

内定的DOM元素获取,直接就可以用的

document 获取document文档(这是一个文档对象)
document.documentElement 获取html标签 (html元素对象)
document.head 获取head标签(head元素对象)
document.title 获取title标签 (title元素对象)
document.body 获取body标签 (body元素对象)

console.log(document.head.nodeType);
console.log(document.body.nodeType);
console.log(document.body.nodeName);
console.log(document.body.nodeValue);
console.dir(document.nodeType);
通过get系列动态获取元素

document.getElementById() 通过id获取元素(IE7以下不区分大小写,会获取name属性)

element.getElementsByTagName() 通过标签名获取元素

document.getElementsByName() 通过name属性获取

var aIpt = document.getElementsByName("aa");
console.log(aIpt);

注意通过name属性获取元素,只用部分标签可用(表单,表单元素,img,iframe);

document.getElementsByClassName() 通过class类名获取

var acl = document.getElementsByClassName("cl")
console.log(acl);

class获取元素(ie8及以下ie版本中没有,可以多个class一起写 document.getElementsByClassName("c1 c2")

通过query系列静态获取元素

element.querySelector() 选到指定选择器下的第一个元素(ie7及以下没有)
element.querySelectorAll() 选到指定选择器的所有元素(ie7及以下没有)

var ospan = document.querySelector("div span")
console.log(ospan);
var aspan = document.querySelectorAll("div span")
console.log(aspan);

现在ie7以下用的很少了 ,可以放心用,但是query系列获取的不是实时的,是静态的,选择的是快照,副本.

<div id='box'></div>
<div></div>
<div></div>
<script>
var div = document.getElementsByTagName("div")
var oBox = document.getElementById('box');
oBox.remove();
console.log(div);
</script>
动态获取与静态获取 都是在一定范围内查询节点

query 拥有更好的获取方式 因为参数是 css选择器

get系列是动态获取 每次使用时会重新获取 ,如果删除了oBox.remove(),控制台、元素中就都看不到了

query系列是静态获取,如果删除了oBox.remove();,控制台还显示,是之前的快照,元素中就看不到了

<div id='box'></div>
<div></div>
<div></div>
<script>
var div = document.getElementsByTagName("div")
var oBox = document.getElementById('box');
// var oqBox = document.querySelector("#box");
// var aqBox = document.querySelectorAll("div");
oBox.remove();
console.log(div);
console.log(oBox);
// console.log(aqBox);
// console.log(oqBox);
</script>

getElementById getElementsByName 这两个方法只能通过document来调用

var oWrap = document.getElementById('wrap')
var aInput = document.getElementsByName('cc')

可以通过普通元素调用方法 getElementsByTagName() getElementsByClassName()

<div id='box'>
<p class="haha">hahap</p>
<div class ="haha">haha1</div>
<div class ="haha">haha2</div>
<span>span1</span>
<span>span2</span>
<span>span3</span>
</div>
<div class ="haha">haha1</div>
<div class ="haha">haha2</div>
<span>外span外</span>
<span>外span外</span>
<script>
var oBox =document.getElementById("box")
console.log(oBox);
var ahaha = oBox.getElementsByClassName('haha'); //普通元素Element调用的方法  get
console.log(ahaha);
var aSpan = oBox.getElementsByTagName('span') //普通元素Element调用的方法   get
console.log(aSpan);
var aaSpan = document.getElementsByTagName('span') //document对象调用所有   get
console.log(aaSpan);
var oqhaha =oBox.querySelector("span");//普通元素Element调用的方法  query
console.log(oqhaha);
var aqhaha =oBox.querySelectorAll("span");//普通元素Element调用的方法  query
console.log(aqhaha);
var aaqhaha =document.querySelectorAll("span");//document对象调用所有span  query
console.log(aaqhaha);
</script>
3.1 获取元素节点

HTML负责页面的布局、结构。JS要操作HTML标签,第一件事儿就是得到这个元素(标签)。

说白了,就是把HTML标签拿到JS里面来。

JavaScript通过document对象表示文档,它表示整个页面。它有很多属性和方法,包含了绝大多数多页面的特征和操作。学习DOM,说白了就是学习document对象。

全线浏览器兼容的,得到元素的方法,就这两个:

document.getElementById()               //通过id得到元素
document.getElementsByTagName();    通过标签名得到元素们
3.2 getElementById()

getElementById()方法,通过id获取元素

这个单词实际上是由几个小单词组成的:get得到 Element元素 By通过 Id id属性

var oBox = document.getElementById("box");
console.log(typeof oBox);       //object

需要注意的是,getElementById里面就写id就行了,不要多写#

如果说页面上没有匹配的id的HTML元素,将返回null,

 var oBox1 =document.getElementById("box1")
  console.log(oBox1);         //unll
  console.log(typeof oBox1)     //返回object对象类型

id大小写要严格区分,但是在IE7及以下中,大小写是不区分的。

IE7及较低版本还有一个怪癖,表单元素name特性也会被当做id。
为了避免这个问题,所以页面上的name最好也不要和任何id的名字相同。
<input type="text" name="haha" />

<script type="text/javascript">
    var oInput = document.getElementById("haha");
</script>

3.3 getElementsByTagName

getElementsByTagName

就是通过标签名得到元素,得到的是页面上所有该种标签元素,得到的是类数组,数组可以有下标,开始是0,最后一项是.length-1

var ops = document.getElementsByTagName("p");
3.4 连续打点调用get

先获取一个HTML标签,然后选择这个HTML标签中的所有p标签:

var ps = document.getElementById("box2").getElementsByTagName("p");

不要多写一个document,下面的写法是错误的

var ps = document.getElementById("box2").document.getElementsByTagName("p");

连续get可以很疯狂,但是如果是数组,一定要加上下标,才能变成对象:

document.getElementsByTagName("div")[1].getElementsByTagName("p")[2].getElementsByTagName("span")[1].style.color = "red";

get 、query是通过方法(范围)来查询节点,接下来通过属性查询节点之间的对应关系来获取节点

4. 节点的操作

11.jpg
4.1 基于节点树的操作(兼容所有浏览器),不区分节点类型

parentNode 父节点(最顶端的parentNode为#document)
childNodes 子节点们
firstChild 第一个子节点
lastChild 最后一个子节点
nextsibling 下一个兄弟节点
previousSibling 上一个兄弟节点

节点分元素(标签)节点、文本节点 、注释节点

以通过.parentNode 属性获取一个元素的父节点, 这个父节点一定是元素节点(因为只有元素(标签)才会嵌套下级,最顶层的父节点就是document document 的父节点是null

var parentNode = box.parentNode;
console.log('parentNode', parentNode.parentNode.parentNode.parentNode)
<div id="box">
  <!-- 注释节点 -->
  <div class="wrap">wrap</div>
  <p>this is p</p>
  <span>this is span</span>
</div>

  <h1 id="hh">这是H1</h1>
  <script>
childNodes 获取元素的所有子节点
var childNodes = box.childNodes;

firstChild 获取第一个子节点(不限定节点类型)
var firstChild = box.firstChild;

lastChild 获取最后一个子节点(不限定节点类型)
var lastChild = box.lastChild;

获取p元素
var oP = box.getElementsByTagName('p')[0]

previousSibiling 上一个兄弟节点
var previousSibling = oP.previousSibling

nextSibling 下一个兄弟节点
var nextSibling = oP.nextSibling
  </script>
4.2 基于元素节点树的操作(除了children,其他都不兼容IE9及以下)

parentElement 父元素节点
children 子元素节点们
firstElementChild 第一个子元素节点
lastElementChild 最后一个子元素节点
nextElementSibling 下一个兄弟元素节点
previousElementChild 上一个兄弟元素节点

parentElemtn父元素节点和 parentNode父节点

html元素的父元素节点是null 因为document不是元素节点。元素节点类型是1 document节点的类型是9
所有元素的最顶层的父元素节点是html元素
parentElemtn父元素节点和 parentNode父节点处理顶层节点(document---null)不一样, 其余使用都是一样的
var parentElement = box.parentElement;
console.log('parentElement', parentElement.parentElement.parentElement)

封装一个方法获取元素的所有子元素节点组成的数组,不允许用children

function retElementChild(node){
    var arr = [],
        child = node.childNodes,
        len = child.length;
    for(var i = 0; i < len; i++){
        if(child[i].nodeType == 1){
            arr.push(child[i])
        }
    }
    return arr;
}
<div>1
    <img src="" alt="">
  </div>
  <span>2</span>
  <p>3</p>
  <script>
    function ElementChild(node) {
      var child = node.childNodes;
      var len = child.length;
      var arr = [];
      for (var i = len - 1; i >= 0; i--) {
        if (child[i].nodeType == 1) {
          arr.push(child[i])
        }
      }
      return arr;
    }
    console.log(ElementChild(document.body));
  </script>
4.3 增:创建DOM节点

document.createElement() 创建元素节点
document.createTextNode() 创建文本节点
document.createComment() 创建注释节点
document.createDocumentFragment 创建文档片段节点

<div>我是div</div>
  <P>zhe shi ppp1</P>
  <P>zhe shi pppaa</P>
  <div><h1 id='hh'>我是标题一</h1></div>
  <script>
    var oEle = document.createElement('div')
    console.log('oEle', oEle)
    var oText = document.createTextNode('this is text')
    console.log('oText', oText)
    var oComment = document.createComment('this is 注释')
    console.log('oComment', oComment)
    // 1. 将一个不存在在DOM树上的节点插入DOM树
    document.body.appendChild(oEle)
    // document.body.appendChild(oText)
    document.body.appendChild(oComment)
    var aP =document.getElementsByTagName('p')[1];
    document.body.insertBefore(oText,aP);    //在aP节点前添加oText
    document.body.insertBefore(hh,aP)//将DOM树上已经存在的节点插入到某个位置,是剪切操作
 </script>
4.4 插:添加(剪切操作)

parentNode.appendChild(A) 在parentNode的最后面添加节点A
parentNode.insertBefore(A,B) 把节点A添加在节点B前面

利用节点插入方法让dom倒序

box的子元素节点是类数组对象,通过box的子元素节点进行排序

 <div id="box">
    <p>1.this is p</p>
    <div>2.this is div</div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <script>

    方法一向前插入insertBefore
    console.log(box.children);
    for (var i = 0; i < box.children.length; i++) {
      box.insertBefore(box.children[i], box.children[0])
    }
    console.log(box.children);
    方法二向后插入appendChild
    console.log(box.children);
    for (var i = box.children.length - 1; i >= 0; i--) {
      box.appendChild(box.children[i])
    }
    console.log(box.children);
  </script>
4.5 删:删除节点

parentNode.removeChild(A) 删除节点A

child.remove()

4.6 替换(剪切操作)

parentNode.replaceChild(A,B) 用节点A代替节点B

4.7 判断一个元素节点有没有子节点方法

element.hasChildNodes() 如果有则返回true。没有则返回false

 <div id="box">
    <p>1.this is p</p>
    <div>2.this is div</div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <div id="wrap"> </div>
  <script>
// 获取节点的方式
// var oH = box.getElementsByTagName('h1')[0];//通过方法获取
// var oH = box.children[3]//节点关系获取
var oH =box.lastElementChild;//节点关系获取
// 删除一个节点,删除的是DOM树上的节点
var list = document.createElement('ul');  //这时节点存在变量里,不在DOM树上,不存在删除节点问题
console.log(list); //list 是个对象,想要删除就list=null 或 list =""  或 list =undefined
//页面是根据DOM树渲染的,删除都是在已知的DOM节点树上进行的
// oH.remove()//自己删除自己,没有返回值,不能后悔
// box.removeChild(oH)//父节点删除子节点,返回被删除的节点,可以将该节点重新插入到页面上
var oH2 = document.createElement("h2");
oH2.innerText="我是创建的节点H2";// 给节点加内容
box.appendChild(oH2) 
box.replaceChild(oH2,oH);//用节点树上不存在的节点替换存在的节点
box.replaceChild(box.children[1],box.children[0])//用DOM树上已经存在的节点替换DOM树上的节点,对于替换节点等同改变了位置
console.log(box.hasChildNodes());
console.log(wrap.hasChildNodes());//存在元素子节点
剔除一个节点中的空标签
      <div id="box">
        <p>1.this is p</p>
        <span></span>
        <div>2.this is div</div>
        <h3></h3>
        <span>3.this is span</span>
        <h1>4.this is h1</h1>
        <p></p>
      </div>
    <script>
    // 方法从前往后循环
    var arrNodes = box.children;
    console.log(arrNodes);
    for(var i=0;i<arrNodes.length;i++){
      if(!arrNodes[i].hasChildNodes()){
        arrNodes[i].remove();
        i--;//i-- 类数组的长度就不能写死,虽然影响性能,要用arrNodes.length,undefined不能调用hasChildNodes()方法
      }
    }
    console.log(arrNodes);

5. 节点的一些属性和方法

5.1 元素节点常用的属性
  1. innerHTML 获取元素节点的内容,可读可写
    如果内容中有符合html格式的,会被解析成标签
  2. innerText 获取元素节点的内容,可读可写
    如果内容中有符合html格式的,不会被解析成标签
  <div id="box">
    <p>1.this is p
      <span>spanspan</span>
    </p>
    <div>2.this is div
      <div>wo shi nei bu</div>
    </div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <div id="wrap"></div>
  <script>
    // 获取节点的内容
    console.log(box.innerHTML);//获取包含标签的字符串   //识别标签
    console.log(box.innerText)//获取不包含标签的字符串   //不识别标签
    // 给节点添加内容
    wrap.innerHTML = "<h2>这里是h2标签</h2>"  //识别标签
    wrap.innerText = "<h2>这里是h2标签</h2>"  //不识别标签
  </script>

innerText在赋值的时候要注意,会将标签覆盖掉
注意: 老版本的火狐不兼容innerText.火狐有自己的属性textContent,但是textContent老版本IE(8及以下)不兼容

5.2 方法操作标签属性

element.setAttribute(“class”,“on”) 设置元素节点的class属性
element.getAttribute(“class”) 获取元素节点的class属性
element.removeAttribute(“class”) 删除元素节点的class属性

<style>
    .on{
        color:#fff;
        font-size:20px;
        background-color:orange;
    }
</style>
<div id="box">wuwei</div>
<script>
    var oBox = document.getElementById('box');
    oBox.setAttribute('class','on');
</script>

6. 更改HTML的属性

JS可以更改HTML的任何属性,方法是两种:点语法 和 setAttribute()、getAttribute()。

6.1 getAttribute(),setAttribute()

getAttribute(); //获取属性
setAttribute(); //设置属性

oImg.setAttribute("src","images/2.jpg");
等价于
oImg.src = “images/2.jpg”;

 <div id="box" class="aa" name="mydiv" title="" style="color:blue;background-color: pink;">
    <p>1.this is p
      <span>spanspan</span>
    </p>
    <div>2.this is div
      <div>wo shi nei bu</div>
    </div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <div id="wrap"></div>
  <script>
    console.log(box.attributes);//获取标签的属性名类数组
    console.log(box.attributes[4].name);//类数组获取标签的属性名
    console.log(box.attributes[4].value);//类数组获取标签的属性值
    //getAttribute,setAttribute既可以操作合法标签属性,又可以操作自定义的标签属性
    console.log(box.getAttribute("class"));//获取属性值
    box.setAttribute("class", "newclass");//设置已存在的属性class属性值为newclass
    box.setAttribute("cccc", "newcccc");//设置不存在的属性cccc,值为newcccc
    box.xxxx = 123 //.box dom元素(本质上在js中就是一个对象(节点对象))对象xxxx 是对象的属性       box.removeAttribute("class");//删除属性  
  </script>
6.2 点语法,Js属性操作标签属性(点语法只能操作合法的标签属性,自定义的标签属性无法操作)

得到一个元素之后,直接打点调用它的属性名,就能对HTML相应的属性进行更改。可以获取,也可以设置

 <div id="box" class="aa" name="" title="" style="color:blue;">
    <p>1.this is p
      <span>spanspan</span>
    </p>
    <div>2.this is div
      <div>wo shi nei bu</div>
    </div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <div id="wrap"></div>
  <script>
  box.className = box.className += " bb";//属性值前加空格
  console.log(box.style="font-weight:600");//合法所以控制台元素会显示
  console.log(box.dd="newdd");//不合法
  console.log(box.name="myname");//不合法所以控制台元素找不到

class这个属性,要换成className,因为class是JS的保留字

oDiv.className = "da";

如果想要换一个HTML元素的class属性,那么就要打点调用.className属性。

6.3 点语法与getAttribute(),setAttribute()的区别

第一,所有自定义的属性,都不能通过点语法获取和设置

设置自定义属性

box.wu='name';  //此时点操作符不能设置自定义属性
box.setAttribute("wu","name"));  

获取自定义属性

alert(box.wu);  //undefined,自定义的属性,不是w3c的属性,都不能用点语法
alert(box.getAttribute("wu")); //haha

第二,所有的行内样式,点语法.style得到的是一个样式对象。我们可以通过.style.border继续得到小样式。

但是getAttribute()得到的是字符串

var oBox = document.getElementById("box");
console.log(typeof oBox.style);   //object
console.log(typeof oBox.getAttribute("style"));   //string

第三,getAttribute()不需要避讳,直接

oDiv.getAttribute(“class”); //就行了

点语法操作标签属性与方法操作标签属性的不同

<div id="box" class="aa" name="" title="" style="color:blue;background-color: skyblue;border: 1px solid pink;">
    <p>1.this is p
      <span>spanspan</span>
    </p>
    <div>2.this is div
      <div>wo shi nei bu</div>
    </div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <div id="wrap"></div>
  <script>

    // 1、点语法要求标签属性必须合法,不能是自定义的。方法可以操作所有的标签属性。
    // 2、点语法操作style属性获取的是计算属性对象,方法获取的是字符串
    console.log(box.getAttribute('style'));//获取的是字符串,想要得到其中的值,还需要字符串切割
    // console.log(box.style);//计算样式对象,计算样式中有很多默认的样式
    console.log(box.style.color)
    //3、getAttribute()不需要避讳,直接
    console.log(box.getAttribute('class'));//方法可以直接用class
    console.log(box.className);  //点操作要className
    </script>

点语法的效率远高于getAttribute()、setAttribute()。

所以,如果操作自定义的属性,偶尔用一次setAttribute,getAttribute,除此之外,都用点语法。

6.4 关于H5新增的元素节点的classList属性

classList 属性是一个类数组,其身上有几个常用的方法

  1. add(value) 将给定的参数字符串添加到元素的class属性中,如果存在就不添加了
  2. remove(value) 将给定的参数字符串从class属性中删除
  3. contains(value) 返回布尔值,表示class属性中是否包含参数字符串
  4. toggle(value) 检测class属性中是否有参数字符串 有则删除 返回false,没有则添加,返回true

class类名为aa bb cc,点语法操作起来就不是很方便,H5新增方便操作class的方法

<div id="box" class="aa">
    <p>1.this is p</p>
    <div>2.this is div</div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <script>
    console.log(box.classList);
    box.classList.add("bb");  //加
    box.classList.add("cc"); //加
    box.classList.remove("aa") //删除
    console.log(box.classList);
    box.classList.toggle("ee");//存在就删除,没有就添加
    console.log(box.classList);
    console.log(box.classList.contains("jjing"));//判断是否存在,返回布尔值
  </script>

这个属性IE9及其一下不能用

6.5 H5新增了自定义属性,但是需要以data-开头

元素节点有一个dataset属性用来获取和设置自定义属性

<div id="box" class="aa" data-img="http:/www.baidu.com" data-aa="http://www.hengshui.com">
    <p>1.this is p</p>
    <div>2.this is div</div>
    <span>3.this is span</span>
    <h1>4.this is h1</h1>
  </div>
  <script>
    console.log(box.getAttribute('data-img'));
    // 用getAttribute操作data开头的自定义属性,每次只能操作一个,H5会将以data开头的属性转成对象
    console.log(box.dataset);//获取
    console.log(box.dataset.img);//获取
    box.dataset.haha = "this is haha";//添加设置一个新data属性
    box.dataset.img="tu pian"
   </script>

IE10及以下不兼容

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

推荐阅读更多精彩内容