《Head First HTML5 javascript》第8章 DOM

DOM(document object model)

文档对象模型 (DOM) 是 HTML 和 XML 文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以结构化的方式进行访问,从而改变文档的内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。

一个 web 页面是一个文档。这个文档可以在浏览器窗口或作为 HTML 源码显示出来。但上述两个情况中都是同一份文档。文档对象模型(DOM)提供了对同一份文档的另一种表现,存储和操作的方式。DOM 是 web 页面的完全的面向对象表述,它能够使用如 JavaScript 等脚本语言进行修改。

DOM重要的数据类型

下面的表格简单则描述了这些数据类型。

document当一个成员返回 document 对象(例如,元素的 ownerDocument 属性返回它所属于 document ) ,这个对象就是 root document 对象本身。 DOM document Reference 一章对 document 对象进行了描述。
elementelement 是指由 DOM API 中成员返回的类型为 element 的一个元素或节点。例如, document.createElement() 方法会返回一个 node 的对象引用,也就是说这个方法返回了在 DOM 中创建的 element。 element 对象实现了 DOM Element 接口以及更基本的 Node 接口,参考文档将两者都包含在内。
textelement的文本内容,一定存储在element的子节点里
nodeListnodeList 是一个元素的数组,如从 document.getElementsByTagName() 方法返回的就是这种类型。 nodeList 中的条目由通过下标有两种方式进行访问:
• list.item(1)
• list[1]两种方式是等价的,第一种方式中 item() 是 nodeList 对象中的单独方法。 后面的方式则使用了经典的数组语法来获取列表中的第二个条目。
attribute当 attribute 通过成员函数 (例如,通过 createAttribute()方法) 返回时,它是一个为属性暴露出专门接口的对象引用。DOM 中的属性也是节点,就像元素一样,只不过可能会很少使用它。
namedNodeMapnamedNodeMap 和数组类似,但是条目是由 name 或 index 访问的,虽然后一种方式仅仅是为了枚举方便,因为在 list 中本来就没有特定的顺序。出于这个目的, namedNodeMap 有一个 item() 方法,也可以从 namedNodeMap 添加或移除。

DOM 中核心接口

在 DOM 编程时,通常使用的最多的就是 Document 和 window 对象。简单的说, window 对象表示浏览器中的内容,而 document 对象是文档本身的根节点。Element 继承了通用的 Node 接口,将这两个接口结合后就提供了许多方法和属性可以供单个元素使用。在处理这些元素所对应的不同类型的数据时,这些元素可能会有专用的接口。

下面是在 web 和 XML 页面脚本中使用 DOM 时,一些常用的 API 简要列表。

  • document.getElementById(id)document.getElementById

    value性质取值:JS允许我们通过 getElementById()函数以id访问网页元素,但这个函数不会直接取值,需要以JS对象的形式提供HTML域内容,我们通过域的value性质访问数据

    document.getElementById("cakedonuts").value
    
  • document.getElementsByTagName(name)

    document.getElementsByTagName返回一个包括所有给定标签名称的元素的 HTML 集合HTMLCollection。整个文件结构都会被搜索,包括根节点。返回的 HTML 集合 是动态的,意味着它可以自动更新自己来保持和 DOM 树的同步而不用再次调用 document.getElementsByTagName()

    document.getElementsByTagName(”img”)[3];//第4个<img>标签
    
  • createElement用于创建一个由标签名称 tagName指定的 HTML 元素。如果用户代理无法识别 tagName,则会生成一个未知 HTML 元素

    document.body.onload = addElement;
    
    function addElement () {
      // 创建一个新的 div 元素
      let newDiv = document.createElement("div");
      // 给它一些内容
      let newContent = document.createTextNode("Hi there and greetings!");
      // 添加文本节点 到这个新的 div 元素
      newDiv.appendChild(newContent);
    
      // 将这个新的元素和它的文本添加到 DOM 中
      let currentDiv = document.getElementById("div1");
      document.body.insertBefore(newDiv, currentDiv);
    }
    
  • Document.createTextNode()创建一个文本节点。

    var text = document.createTextNode(data);//data 是一个字符串,包含了要放入文本节点的内容。
    

Node

**Node**是一个接口,各种类型的 DOM API 对象会从这个接口继承。它允许我们使用相似的方式对待这些不同类型的对象;比如,继承同一组方法,或者用同样的方式测试。

Node属性

  1. [Node.nodeValue]返回或设置当前节点的值,只限文本与属性节点使用(不含元素)。

    document.getElementById("scenetext").nodeValue;
    
  2. [Node.nodeType]节点类型,返回与该节点类型对应的无符号短整型的值,可能的值:

    NameValue
    ELEMENT_NODE1
    ATTRIBUTE_NODE 已弃用2
    TEXT_NODE3
    CDATA_SECTION_NODE4
    ENTITY_REFERENCE_NODE 已弃用5
    ENTITY_NODE 已弃用6
    PROCESSING_INSTRUCTION_NODE7
    COMMENT_NODE8
    DOCUMENT_NODE9
    DOCUMENT_TYPE_NODE10
    DOCUMENT_FRAGMENT_NODE11
    NOTATION_NODE 已弃用12
  3. Node.childNodes 包含节点下所有的子节点的数组,以出现在HTML代码中的顺序而排列,返回包含指定节点的子节点的集合,该集合为即时更新的集合(live collection)。

  4. [Node.firstChild]返回该节点第一个子节点[Node],如果该节点没有子节点则返回null

  5. [Node.lastChild](返回该节点最后一个子节点[Node],如果该节点没有子节点返回null

Node方法

  1. [Node.removeChild()]移除当前节点的一个子节点。这个子节点必须存在于当前节点中。

    // 移除一个元素节点的所有子节点
    var element = document.getElementById("top");
    while (element.firstChild) {
      element.removeChild(element.firstChild);
    }
    
  2. [Node.appendChild()]将指定的 childNode 参数作为最后一个子节点添加到当前节点。 如果参数引用了 DOM 树上的现有节点,则节点将从当前位置分离,并附加到新位置。

    // 创建一个新的段落元素 <p>,然后添加到 <body> 的最尾部
    var p = document.createElement("p");
    document.body.appendChild(p);
    

innerHTML

通过innerHTML 可以取得HTML内容类元素(div、span、p…)内存储的所有内容,包括HTML标签,如下面的案例所示,可以获取文字内容+strong标签及其内容,这与DOM方法不同。

<p id="story">
	you are standing <strong>alone</strong> in the woods.
</p>

设置 innerHTML 的值可以让你轻松地将当前元素的内容替换为新的内容。举个例子来说,你可以通过文档 [body]属性删除 body 的全部内容。

document.body.innerHTML = "";

只要把文字字符串指派给元素的innerHTML特性,元素内容即可设为HTML文本字符串。新内容将取代任何原本属于元素的内容。它本身没有附加功能,如果要实现附加的效果可以采用串联的方法将新内容加到旧内容上:

elem.innerHTML += "new content";

关键字this

this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化,但是有一个总的原则,那就是this指的是调用函数的那个对象。

总结:谁调用了这个函数,this指向谁(对象)

this 在  中的表现与在函数中类似,因为类本质上也是函数,但也有一些区别和注意事项。

在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中:

class Example {
  constructor() {
    const proto = Object.getPrototypeOf(this);
    console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}

new Example(); // ['constructor', 'first', 'second']

函数上下文中的 this

// 对象可以作为 bind 或 apply 的第一个参数传递,并且该参数将绑定到该对象。
var obj = {a: 'Custom'};

// 声明一个变量,并将该变量作为全局对象 window 的属性。
var a = 'Global';

function whatsThis() {
  return this.a;  // this 的值取决于函数被调用的方式
}

whatsThis();          // 'Global' 因为在这个函数中 this 没有被设定,所以它默认为 全局/ window 对象
whatsThis.call(obj);  // 'Custom' 因为函数中的 this 被设置为 obj
whatsThis.apply(obj); // 'Custom' 因为函数中的 this 被设置为 obj

this 和对象转换

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一个参数是用作“this”的对象
// 其余参数用作函数的参数
add.call(o, 5, 7); // 16

// 第一个参数是用作“this”的对象
// 第二个参数是一个数组,数组中的两个成员用作函数参数
add.apply(o, [10, 20]); // 34

原型链中的 this

对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法就在这个对象上一样。

var o = {
  f: function() {
    return this.a + this.b;
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

这个例子中,对象 p 没有属于它自己的 f 属性,它的 f 属性继承自它的原型。虽然最终是在 o 中找到 f 属性的,这并没有关系;查找过程首先从 p.f 的引用开始,所以函数中的 this 指向p。也就是说,因为f是作为p的方法调用的,所以它的this指向了p。这是 JavaScript 的原型继承中的一个有趣的特性。

getter 与 setter 中的 this

再次,相同的概念也适用于当函数在一个 getter 或者 setter 中被调用。用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。

function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, 'sum', {
    get: sum, enumerable: true, configurable: true});

console.log(o.average, o.sum); // logs 2, 6

作为构造函数

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

虽然构造函数返回的默认值是 this所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回 this对象)。

/*
 * 构造函数这样工作:
 *
 * function MyConstructor(){
 *   // 函数实体写在这里
 *   // 根据需要在 this 上创建属性,然后赋值给它们,比如:
 *   this.fum = "nom";
 *   // 等等...
 *
 *   // 如果函数具有返回对象的 return 语句,
 *   // 则该对象将是 new 表达式的结果。
 *   // 否则,表达式的结果是当前绑定到 this 的对象。
 *   //(即通常看到的常见情况)。
 * }
 */

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37

function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

在刚刚的例子中(C2),因为在调用构造函数的过程中,手动的设置了返回对象,与this绑定的默认对象被丢弃了。(这基本上使得语句“this.a = 37;”成了“僵尸”代码,实际上并不是真正的“僵尸”,这条语句执行了,但是对于外部没有任何影响,因此完全可以忽略它)。

作为一个 DOM 事件处理函数

当函数被用作事件处理函数时,它的 this 指向触发事件的元素(一些浏览器在使用非 addEventListener 的函数动态地添加监听函数时不遵守这个约定)。

// 被调用时,将关联的元素变成蓝色
function bluify(e){
  console.log(this === e.currentTarget); // 总是 true

  // 当 currentTarget 和 target 是同一个对象时为 true
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

// 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*');

// 将 bluify 作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

作为一个内联事件处理函数

当代码被内联 on-event 处理函数 (en-US) 调用时,它的this指向监听器所在的 DOM 元素:

<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

上面的 alert 会显示 button。注意只有外层代码中的 this 是这样设置的:

<button onclick="alert((function(){return this})());">
  Show inner this
</button>

在这种情况下,没有设置内部函数的 this,所以它指向 global/window 对象(即非严格模式下调用的函数未设置 this 时指向的默认对象)。

类中的 this

和其他普通函数一样,方法中的 this 值取决于它们如何被调用。有时,改写这个行为,让类中的 this 值总是指向这个类实例会很有用。为了做到这一点,可在构造函数中绑定类方法:

class Car {
  constructor() {
    // Bind sayBye but not sayHi to show the difference
    this.sayBye = this.sayBye.bind(this);
  }
  sayHi() {
    console.log(`Hello from ${this.name}`);
  }
  sayBye() {
    console.log(`Bye from ${this.name}`);
  }
  get name() {
    return 'Ferrari';
  }
}

class Bird {
  get name() {
    return 'Tweety';
  }
}

const car = new Car();
const bird = new Bird();

// The value of 'this' in methods depends on their caller
car.sayHi(); // Hello from Ferrari
bird.sayHi = car.sayHi;
bird.sayHi(); // Hello from Tweety

// For bound methods, 'this' doesn't depend on the caller
bird.sayBye = car.sayBye;
bird.sayBye();  // Bye from Ferrari

涉及css样式要点

  1. <style>包含文档的样式信息或者文档的部分内容。默认情况下,该标签的样式信息通常是CSS的格式。

    type:该属性以 MIME 类型(不应该指定字符集)定义样式语言。如果该属性未指定,则默认为 text/css

  2. 字重 font-weightCSS属性指定了字体的粗细程度。一些字体只提供 normal  和 bold两种值。

    /* Keyword values */
    font-weight: normal;
    font-weight: bold;
    
    /* Keyword values relative to the parent */
    font-weight: lighter;
    font-weight: bolder;
    
    /* Numeric keyword values */
    font-weight: 1
    font-weight: 100;
    
    /* Global values */
    font-weight: inherit;
    font-weight: initial;
    font-weight: unset;
    
  3. 边框 borderCSS的 **border**属性是一个用于设置各种单独的边界属性的简写属性border可以用于设置一个或多个以下属性的值:border-width[border-style](<https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-style>)[border-color](<https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-color>)

    /* style */
    border: solid;
    
    /* width | style */
    border: 2px dotted;
    
    /* style | color */
    border: outset #f33;
    
    /* width | style | color */
    border: medium dashed green;
    
    /* Global values */
    border: inherit;
    border: initial;
    border: unset;
    
  4. 间距

    1. 内间距 paddingCSS 简写属性控制元素所有四条边的内边距区域

      /* 应用于所有边 */
      padding: 1em;
      
      /* 上边下边 | 左边右边 */
      padding: 5% 10%;
      
      /* 上边 | 左边右边 | 下边 */
      padding: 1em 2em 2em;
      
      /* 上边 | 右边 | 下边 | 左边 */
      padding: 5px 1em 0 2em;
      
      /* 全局值 */
      padding: inherit;
      padding: initial;
      padding: unset;
      
    2. 外间距 margin为给定元素设置所有四个(上下左右)方向的外边距属性

      /* 应用于所有边 */
      margin: 1em;
      margin: -3px;
      
      /* 上边下边 | 左边右边 */
      margin: 5% auto;
      
      /* 上边 | 左边右边 | 下边 */
      margin: 1em auto 2em;
      
      /* 上边 | 右边 | 下边 | 左边 */
      margin: 2px 1em 0 auto;
      
      /* 全局值 */
      margin: inherit;
      margin: initial;
      margin: unset;
      
      margin: 5%;                 /* 所有边:5% 的外边距 */
      
      margin: 10px;               /* 所有边:10px 的外边距 */
      
      margin: 1.6em 20px;         /* 上边和下边:1.6em 的外边距 */
                                  /* 左边和右边:20px 的外边距  */
      
      margin: 10px 3% -1em;       /* 上边:10px 的外边距 */
                                  /* 左边和右边:3% 的外边距   */
                                  /* 下边:     -1em 的外边距 */
      
      margin: 10px 3px 30px 5px;  /* 上边:10px 的外边距 */
                                  /* 右边:3px 的外边距  */
                                  /* 下边:30px 的外边距 */
                                  /* 左边:5px 的外边距  */
      
      margin: 2em auto;           /* 上边和下边:2em 的外边距 */
                                  /* 水平方向居中            */
      
      margin: auto;               /* 上边和下边:无外边距 */
                                  /* 水平方向居中        */
      
    3. 注意事项

      • 当只指定一个值时,该值会统一应用到全部四个边的边距上。
      • 指定两个值时,第一个值会应用于上边和下边的边距,第二个值应用于左边和右边
      • 指定三个值时,第一个值应用于上边,第二个值应用于右边和左边,第三个则应用于下边的边距。
      • 指定四个值时,依次(顺时针方向)作为上边右边下边,和左边的边距。
  5. 显示隐藏效果

    1. visibility样式特性:显示或隐藏元素而不更改文档的布局。该属性还可以隐藏 [<table>]中的行或列。

      /* Keyword values */
      visibility: visible;
      visibility: hidden;
      visibility: collapse;
      
      /* Global values */
      visibility: inherit;
      visibility: initial;
      visibility: unset;
      

      visible元素正常显示。

      hidden隐藏元素,但是其他元素的布局不改变,相当于此元素变成透明。要注意若将其子元素设为 visibility: visible,则该子元素依然可见。

      collapse关键字对于不同的元素有不同的效果: • 用于 [<table>]行、列、列组和行组,隐藏表格的行或列,并且不占用任何空间(与将 [display]: none 用于表格的行/列上的效果相当)。但是,计算其他行和列的大小时,仍会像显示折叠行或列中的单元格一样进行计算。此值允许从表中快速删除行或列,而不强制重新计算整个表的宽度和高度。 • 折叠的弹性元素和 ruby 元素会被隐藏,它们本来将要占用的空间会被移除。 • 对于其他元素,折叠处理与隐藏相同。

    2. display样式特性

      CSS display 属性设置元素是否被视为块或者内联元素以及用于子元素的布局,例如流式布局网格布局弹性布局

      形式上,display 属性设置元素的内部和外部的显示类型。外部类型设置元素参与流式布局;内部类型设置子元素的布局。一些 display 值在它们自己的单独规范中完整定义;例如,在 CSS 弹性盒模型的规范中,定义了声明 display: flex 时会发生的细节。

      /* precomposed values */
      display: block;
      display: inline;
      display: inline-block;
      display: flex;
      display: inline-flex;
      display: grid;
      display: inline-grid;
      display: flow-root;
      
      /* box generation */
      display: none;
      display: contents;
      
      /* two-value syntax */
      display: block flow;
      display: inline flow;
      display: inline flow-root;
      display: block flex;
      display: inline flex;
      display: block grid;
      display: inline grid;
      display: block flow-root;
      
      /* other values */
      display: table;
      display: table-row; /* all table elements have an equivalent CSS display value */
      display: list-item;
      
      /* Global values */
      display: inherit;
      display: initial;
      display: revert;
      display: revert-layer;
      display: unset;
      

其他知识点

  1. id传参时,构造函数中不能加引号,但是要在调用函数中加引号,这是由于构造函数中的参数需要是一个变量,如果加了引号就变成字符串及固定的id文字了,那样不符合调用的逻辑

  2. className 特性对元素样式进行访问,获取或设置指定元素的 class 属性的值。

    let cName = elementNodeReference.className;
    
    elementNodeReference.className = cName;
    
  3. 鼠标事件

    1. onmouseover当鼠标移动到一个元素上时,会在这个元素上触发 mouseover 事件。

      element.onmouseover = event handling code
      
    2. onmouseout当鼠标离开一个元素上时,会在这个元素上触发 onmouseout 事件。

      <!doctype html>
      <html>
      <head>
      <title>onmouseover/onmouseout event example</title>
      <script type="text/javascript">
          function initElement()
          {
              var p = document.getElementById("foo");
      
              p.onmouseover = showMouseOver;
              p.onmouseout = showMouseOut;
          };
      
          function showMouseOver()
          {
              var notice = document.getElementById("notice");
              notice.innerHTML = '检测到鼠标移进';
          }
      
          function showMouseOut()
          {
              var notice = document.getElementById("notice");
              notice.innerHTML = '检测到鼠标移出';
          }
      
      </script>
      <style type="text/css">
          #foo {
          border: solid blue 2px;
          }
      </style>
      </head>
      <body onload="initElement()";>
          <span id="foo">移动鼠标,在该元素上移进移出</span>
          <div id="notice"></div>
      </body>
      </html>
      
  4. switch评估一个表达式,将表达式的值与case子句匹配,并执行与该情况相关联的语句

    switch (expression) {
      case value1:
        // 当 expression 的结果与 value1 匹配时,执行此处语句
        [break;]
      case value2:
        // 当 expression 的结果与 value2 匹配时,执行此处语句
        [break;]
      ...
      case valueN:
        // 当 expression 的结果与 valueN 匹配时,执行此处语句
        [break;]
      [default:
        // 如果 expression 与上面的 value 值都不匹配,执行此处语句
        [break;]]
    }
    

    一个 switch 语句首先会计算其 expression。然后,它将从第一个 case 子句开始直到寻找到一个其表达式值与所输入的 expression 的值所相等的子句(使用 严格运算符 (en-US)===)并将控制权转给该子句,执行相关语句。(如果多个 case 与提供的值匹配,则选择匹配的第一个 case,即使这些 case 彼此间并不相等。)

    如果没有 case 子句相匹配,程序则会寻找那个可选的 default 子句,如果找到了,将控制权交给它,执行相关语句。若没有 default 子句,程序将继续执行直到 switch 结束。按照惯例,default 子句是最后一个子句,不过也不需要这样做。

    可选的 [break]语句确保程序立即从相关的 case 子句中跳出 switch 并接着执行 switch 之后的语句。若 break 被省略,程序会继续执行 switch 语句中的下一条语句。

案例:一个简单的场景选择小游戏

<html>
	<head>
		<title></title>
		<style>
			span.decision{
			font-weight: bold;
			background-color: aqua;
			border: thin solid;
			padding: 5px;
			margin: 5px;
			}

			span.decisionhover{
			font-weight: bold;
			color: #ffffff;
			background-color: #000000;
			border: thin solid #dddddd;
			padding: 5px;
			margin: 5px;
			}

		</style>

		<script type="text/javascript">
			var curScene = 0;

			/* 用DOM方法+函数实现动态替换文字 */
			function replaceNodeText(id, newText){
				var node = document.getElementById(id);
				while (node.firstChild){
					node.removeChild(node.firstChild);
				}
				node.appendChild(document.createTextNode(newText));
			
			}
	
			function changeScene(decision)
			{
				var message = "";
				var decision1 = "", decision2 = "";

				switch(curScene){
					case 0:
						curScene = 1;
						message = "Your journey begins at a fork in the road.";
						decision1 = "Take the Path";
			  			decision2 = "Take the Bridge";
						document.getElementById("decision2").style.visibility = "visible";
						break;
					case 1:
						if (decision == 1) {
							curScene = 2
							message = "You have arrived at a cute little house in the woods.";
							decision1 = "Walk around Back";
							decision2 = "Knock on Door";
						}
						else {
							curScene = 3;
							message = "You are standing on the bridge overlooking a peaceful stream.";
							decision1 = "Walk across Bridge";
							decision2 = "Gaze into Stream";
						}
						break;
					case 2:
						if (decision == 1) {
							curScene = 4
							message = "Peeking through the window, you see a witch inside the house.";
							decision1 = "Sneak by Window";
							decision2 = "Wave at Witch";
						}
						else {
							curScene = 5;
							message = "Sorry, a witch lives in the house and you just became part of her stew.";
							decision1 = "Start Over";
							decision2 = "";
							document.getElementById("decision2").style.visibility = "hidden";

						}
						break;
					case 3:
						if (decision == 1)
						{
							curScene = 6;
							message = "Sorry, a troll lives on the other side of the bridge and you just became his lunch.";
							decision1 = "Start Over";
			    			decision2 = "";
							document.getElementById("decision2").style.visibility = "hidden";

						}
						else
						{
							curScene = 7;
							message = "Your stare is interrupted by the arrival of a huge troll.";
							decision1 = "Say Hello to Troll";
			    			decision2 = "Jump into Stream";
						}
						break;
					case 4:
						if (decision == 1)
						{
							curScene = 8;
							decision1 = "?";
			    			decision2 = "?";
						}
						else
						{
							curScene = 5;
							message = "Sorry, you became part of the witch's stew.";
							decision1 = "Start Over";
			    			decision2 = "";
							document.getElementById("decision2").style.visibility = "hidden";

						}
						break;
					case 5:
						curScene = 0;
						decision1 = "Start Game";
						decision2 = "";
						document.getElementById("decision2").style.visibility = "hidden";

						break;
					case 6:
						curScene = 0;
						decision1 = "Start Game";
			  			decision2 = "";
						document.getElementById("decision2").style.visibility = "hidden";

						break;
					case 7:
						if(decision == 1)
						{
							curScene = 6;
							message = "Sorry,you became the troll's tasty lunch.";
							decision1 = "Start Over";
			    			decision2 = "";
							document.getElementById("decision2").style.visibility = "hidden";

						}
						else
							curScene = 9;
							decision1 = "?";
			    			decision2 = "?";
						break;
					case 8:
						break;
					case 9:
						break;
				}

				document.getElementById("sceneimg").src = "scene" + curScene + ".png";

				replaceNodeText("scenetext",message);
				replaceNodeText("decision1",decision1);
				replaceNodeText("decision2",decision2);

				//显示决策路径历史
				var history = document.getElementById("history");
				if (curScene != 0){
					var decisionElem = document.createElement("p");
					decisionElem.appendChild(document.createTextNode("Decision" + decision + "-> Scene" + curScene + ":" + message));
					history.appendChild(decisionElem);
				}
				else{
					while(history.firstChild)
					history.removeChild(history.firstChild);
				}

				/* 用DOM方法实现 
				var sceneText = document.getElementById("scenetext");
				while (sceneText.firstChild){
					sceneText.removeChild(sceneText.firstChild);
				}
				sceneText.appendChild(document.createTextNode(message));
				*/

				/* 用innerHTML方法实现在页面内显示场景描述信息
				var sceneDesc;
				if(message)
					//alert(message);
					sceneDesc = document.getElementById("scenetext").innerHTML = message;
				*/
			}

			
			
		</script>
		
	</head>
	<body>
		<div style="margin-top:100px; text-align:center">
			<img id="sceneimg" src="scene0.png" alt="Stick Figure Adventure"/>
			<br/>
			<div id="scenetext"></div><br/>
			Please choose:

			<!-- 用span标签来实现同行显示的动态文字按钮 -->
			<span id="decision1" class="decision" onclick="changeScene(1)" onmouseover=" this.className = 'decisionhover'" onmouseout=" this.className = 'decision'">Start Game!</span>
			<span id="decision2" class="decision" onclick="changeScene(2)" onmouseover=" this.className = 'decisionhover'" onmouseout=" this.className = 'decision'" style="visibility:hidden"></span>

			<!-- 用input实现按钮,但无法实现动态按钮上面的信息提示
			<input type="button" id="decision1" value="1" onclick="changeScene(1)"/>
			<input type="button" id="decision2" value="2" onclick="changeScene(2)"/>
			-->

			<div id="history"></div>
		</div>
	</body>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值