JavaScript (简称 JS)
JavaScript 最初只是为了完成简单的表单验证(验证数据合法性), 结果后来不小心就火了.
当前 JavaScript 已经成为了一个通用的编程语言
JavaScript 的能做的事情:
我们说,Web前端三剑客:HTML、CSS、JavaScript,它们看上去是三种不同的技术,但在实际中却是相互搭配使用的。
HTML是用来标记内容的(重在内容组织上)
HTML是超文本标记语言的简称,它是一种不严谨的、简单的标识性语言。它用各种标签将页面中的元素组织起来,告诉浏览器该如何显示其中的内容。
为什么说HTML是不严谨的呢?因为HTML标签即使不闭合,也并不会影响页面内容的组织。
CSS是用来修饰内容样式的(重在内容样式美化展示上)
CSS是层叠样式表的简称,它用来表现HTML文件样式的,简单说就是负责HTML页面中元素的展现及排版。
JavaScript是用来做交互的
JavaScript是一种脚本语言,即可以运行在客户端也能运行在服务器端。JavaScript的解释器就是JS引擎,JS引擎是浏览器的一部分。而JavaScript主要是用来扩展文档交互能力的,使静态的HTML具有一定的交互行为(比如表单提交、动画特效、弹窗等)。
HTML与CSS及JS的关系
这三者99%的情况下都是搭配使用的,但也不是绝对的,具体关系是:
HTML与CSS、JS是不同的技术,可以独立存在;
HTML一般需要CSS和JS来配合使用,否则单一HTML文档无论是功能还是展示上效果都不理想;
CSS一般是不能脱离HTML或XML的,如果CSS脱离了HTML和XML,那就没有存在的必要的;
JS可以脱离HTML和CSS而独立存在;
JS可以操作HTML和CSS。
浏览器分成渲染引擎 + JS 引擎.
JS 引擎逐行读取 JS 代码内容, 然后解析成二进制指令, 再执行
光有 JS 语法, 只能写一些基础的逻辑流程.
但是要想完成更复杂的任务, 完成和浏览器以及页面的交互, 那么久需要 DOM API 和 BOM API.
这主要指在浏览器端运行的 JS. 如果是运行在服务端的 JS , 则需要使用 node.js 的 API, 就不太需要关注 DOM 和BOM
直接嵌入到 html 元素内部
<input type="button" value="点我一下" onclick="alert('haha')">
注意, JS 中字符串常量可以使用单引号表示, 也可以 使用双引号表示.
HTML 中推荐使用双引号, JS 中推荐使用单引号.
写到 script 标签中
<script>
alert("haha");
script>
写到单独的 .js 文件中
<script src="hello.js">script>
alert("hehe");
注意, 这种情况下 script 标签中间不能写代码. 必须空着(写了代码也不会执行). 适合代码多的情况.
单行注释 // [建议使用]
多行注释 /* */
// 我是单行注释
/*
我是多行注释
我是多行注释
我是多行注释
*/
使用 ctrl + / 切换注释.
多行注释不能嵌套. 形如这种代码就会报错
/*
/*
我是多行注释
我是多行注释
我是多行注释
*/
*/
输入: prompt
弹出一个输入框
// 弹出一个输入框
prompt("请输入您的姓名:");
输出: alert
弹出一个警示对话框, 输出结果
// 弹出一个输出框
alert("hello");
输出: console.log
在控制台打印一个日志(供程序员看)
// 向控制台输出日志
console.log("这是一条日志");
创建变量(变量定义/变量声明/变量初始化)
var name = 'zhangsan';
var age = 20;
var 是 JS 中的关键字, 表示这是一个变量.
= 在 JS 中表示 “赋值”, 相当于把数据放到内存的盒子中. = 两侧建议有一个空格
每个语句最后带有一个 ; 结尾. JS 中可以省略 ; 但是建议还是加上.
注意, 此处的 ; 为英文分号. JS 中所有的标点都是英文标点.
初始化的值如果是字符串, 那么就要使用单引号或者双引号引起来.
初始化的值如果是数字, 那么直接赋值即可.
使用变量
console.log(age); // 读取变量内容
age = 30; // 修改变量内容
例题展示: 弹框提示用户输入信息, 再弹框显示
var name = prompt("请输入姓名:");
var age = prompt("请输入年龄:");
var score = prompt("请输入分数");
alert("您的姓名是: " + name);
alert("您的年龄是: " + age);
alert("您的分数是: " + score);
也可以把三个输出内容合并成一次弹框
var name = prompt("请输入姓名:");
var age = prompt("请输入年龄:");
var score = prompt("请输入分数");
alert("您的姓名是: " + name + "\n" + "您的年龄是: " + age + "\n" + "您的分数是: " + score + "\n");
- 表示字符串拼接, 也就是把两个字符串首尾相接变成一个字符串.
- \n 表示换行
var a = 10; // 数字
var b = "hehe"; // 字符串
var a = 10; // 数字
a = "hehe"; // 字符串
JS 中内置的几种类型
JS 中不区分整数和浮点数, 统一都使用 “数字类型” 来表示.
数字进制表示
计算机中都是使用二进制来表示数据, 而人平时都是使用十进制.
因为二进制在使用过程中不太方便(01太多会看花眼).
所以在日常使用二进制数字时往往使用 八进制 和 十六进制 来表示二进制数字.
var a = 07; // 八进制整数, 以 0 开头
var b = 0xa; // 十六进制整数, 以 0x 开头
var c = 0b10; // 二进制整数, 以 0b 开头
注意:
各种进制之间的转换, 不需要手工计算, 直接使用计算器即可.
特殊的数字值
var max = Number.MAX_VALUE;
// 得到 Infinity
console.log(max * 2);
// 得到 -Infinity
console.log(-max * 2);
// 得到 NaN
console.log('hehe' - 10);
注意:
console.log(isNaN(10)); // false
console.log(isNaN('hehe' - 10)); // true
基本规则
字符串字面值需要使用引号引起来, 单引号双引号均可.
var a = "haha";
var b = 'hehe';
var c = hehe; // 运行出错
如果字符串中本来已经包含引号
var msg = "My name is "zhangsan""; // 出错
var msg = "My name is \"zhangsan\""; // 正确, 使用转义字符. \" 来表示字符串内部的引号.
var msg = "My name is 'zhangsan'"; // 正确, 搭配使用单双引号
var msg = 'My name is "zhangsan"'; // 正确, 搭配使用单双引号
转义字符
有些字符不方便直接输入, 于是要通过一些特殊方式来表示.
\n , \ , ’ , " , \t
求长度
使用 String 的 length 属性即可
var a = 'hehe';
console.log(a.length);//4
var b = '哈哈';
console.log(b.length);//2
字符串拼接
使用 + 进行拼接
var a = "my name is ";
var b = "zhangsan";
console.log(a + b);
注意, 数字和字符串也可以进行拼接
var c = "my score is ";
var d = 100;
console.log(c + d);
注意, 要认准相加的变量到底是字符串还是数字
console.log(100 + 100); // 200
console.log('100' + 100); // 100100
表示 “真” 和 “假”
boolean 原本是数学中的概念 (布尔代数).
在计算机中 boolean 意义重大, 往往要搭配条件/循环完成逻辑判断.
Boolean 参与运算时当做 1 和 0 来看待.
如果一个变量没有被初始化过, 结果就是 undefined, 是 undefined 类型
var a;
console.log(a)
undefined 和字符串进行相加, 结果进行字符串拼接
console.log(a + "10"); // undefined10
undefined 和数字进行相加, 结果为 NaN
console.log(a + 10);
null 表示当前的变量是一个 “空值”.
var b = null;
console.log(b + 10); // 10
console.log(b + "10"); // null10
注意:
null 和 undefined 都表示取值非法的情况, 但是侧重点不同.
null 表示当前的值为空. (相当于有一个空的盒子)
undefined 表示当前的变量未定义. (相当于连盒子都没有)
if 语句
基本语法格式
条件表达式为 true, 则执行 if 的 { } 中的代码
// 形式1
if (条件) {
语句
}
// 形式2
if (条件) {
语句1
} else {
语句2
}
// 形式3
if (条件1) {
语句1
} else if (条件2) {
语句2
} else if .... {
语句...
} else {
语句N
}
三元表达式
是 if else 的简化写法.
条件 ? 表达式1 : 表达式2
条件为真, 返回表达式1 的值. 条件为假, 返回表达式2 的值.
注意, 三元表达式的优先级是比较低的.
switch
switch (表达式) {
case 值1:
语句1;
break;
case 值2:
语句2:
break;
default:
语句N;
}
重复执行某些语句
while 循环
while (条件) {
循环体;
}
执行过程:
continue :结束这次循环
break:结束整个循环
for 循环
for (表达式1; 表达式2; 表达式3) {
循环体
}
执行过程:
创建数组
使用 new 关键字创建
// Array 的 A 要大写
var arr = new Array();
使用字面量方式创建
var arr = [];
var arr2 = [1, 2, 'haha', false]; // 数组中保存的内容称为 "元素"
注意: JS 的数组不要求元素是相同类型.
获取数组元素
使用下标的方式访问数组元素(从 0 开始)
var arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '小猫凯迪';
console.log(arr);
如果下标超出范围读取元素, 则结果为 undefined
console.log(arr[3]); // undefined
console.log(arr[-1]); // undefined
注意: 不要给数组名直接赋值, 此时数组中的所有元素都没了.
相当于本来 arr 是一个数组, 重新赋值后变成字符串了
var arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
arr = '小猫凯迪';
新增数组元素
1. 通过修改 length 新增
相当于在末尾新增元素. 新增的元素默认值为 undefined
var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
2. 通过下标新增
如果下标超出范围赋值元素, 则会给指定位置插入新元素
var arr = [];
arr[2] = 10;
console.log(arr)
此时这个数组的 [0] 和 [1] 都是 undefined
3. 使用 push 进行追加元素
代码示例: 给定一个数组, 把数组中的奇数放到一个 newArr 中.
var arr = [9, 5, 2, 7, 3, 6, 8];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0) {
newArr.push(arr[i]);
}
}
console.log(newArr);
删除数组中的元素
使用 splice 方法删除元素
var arr = [9, 5, 2, 7];
// 第一个参数表示从下表为 2 的位置开始删除. 第二个参数表示要删除的元素个数是 1 个
arr.splice(2, 1);
console.log(arr);
// 结果
[9, 5, 7]
目前咱们已经用到了数组中的一些属性和方法.
arr.length, length 使用的时候不带括号, 此时 length 就是一个普通的变量(称为成员变量, 也叫属性)
arr.push(), arr.splice() 使用的时候带括号, 并且可以传参数, 此时是一个函数 (也叫做方法)
语法结构
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
function hello() {
console.log("hello");
}
// 如果不调用函数, 则没有执行打印语句
hello();
// 调用函数
hello();
// 定义函数
function hello() {
console.log("hello");
}
参数个数
实参和形参之间的个数可以不匹配. 但是实际开发一般要求形参和实参个数要匹配
sum(10, 20, 30); // 30
sum(10); // NaN, 相当于 num2 为 undefined.
JS 的函数传参比较灵活, 这一点和其他语言差别较大. 事实上这种灵活性往往不是好事
函数表达式
var add = function() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(add(10, 20)); // 30
console.log(add(1, 2, 3, 4)); // 10
console.log(typeof add); // function
此时形如 function() { } 这样的写法定义了一个匿名函数, 然后将这个匿名函数用一个变量来表示.
后面就可以通过这个 add 变量来调用函数了
作用域
某个标识符名字在代码中的有效范围.
在 ES6 标准之前, 作用域主要分成两个
// 全局变量
var num = 10;
console.log(num);
function test() {
// 局部变量
var num = 20;
console.log(num);
}
function test2() {
// 局部变量
var num = 30;
console.log(num);
}
test();
test2();
console.log(num);
// 执行结果
10
20
30
10
创建变量时如果不写 var, 则得到一个全局变量
function test() {
num = 100;
}
test();
console.log(num);
// 执行结果
100
作用域链
背景:
内部函数可以访问外部函数的变量. 采取的是链式查找的方式. 从内到外依次进行查找
var num = 1;
function test1() {
var num = 10;
function test2() {
var num = 20;
console.log(num);
}
test2();
}
test1();
// 执行结果
20
执行 console.log(num) 的时候, 会现在 test2 的局部作用域中查找 num. 如果没找到, 则继续去 test1 中查找. 如果还没找到, 就去全局作用域查找.
基本概念
对象是指一个具体的事物.
“电脑” 不是对象, 而是一个泛指的类别. 而 “我的联想笔记本” 就是一个对象.
在 JS 中, 字符串, 数值, 数组,函数都是对象.
每个对象中包含若干的属性和方法.
1. 使用字面量创建对象
使用 { } 创建对象
var a = {}; // 创建了一个空的对象
var student = {
name: '蔡徐坤',
height: 175,
weight: 170,
sayHello: function() {
console.log("hello");
}
};
使用对象的属性和方法:
// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
2. 使用 new Object 创建对象
var student = new Object(); // 和创建数组类似
student.name = "蔡徐坤";
student.height = 175;
student['weight'] = 170;
student.sayHello = function () {
console.log("hello");
}
console.log(student.name);
console.log(student['weight']);
student.sayHello();
注意, 使用 { } 创建的对象也可以随时使用 student.name = “蔡徐坤”; 这样的方式来新增属性
3. 使用 构造函数 创建对象
前面的创建对象方式只能创建一个对象. 而使用构造函数可以很方便 的创建 多个对象.
例如: 创建几个猫咪对象
var mimi = {
name: "咪咪",
type: "中华田园喵",
miao: function () {
console.log("喵");
}
};
var xiaohei = {
name: "小黑",
type: "波斯喵",
miao: function () {
console.log("猫呜");
}
}
var ciqiu = {
name: "刺球",
type: "金渐层",
miao: function () {
console.log("咕噜噜");
}
}
此时写起来就比较麻烦. 使用构造函数可以把相同的属性和方法的创建提取出来, 简化开发过程.
基本语法
function 构造函数名(形参) {
this.属性 = 值;
this.方法 = function...
}
var obj = new 构造函数名(实参);
注意:
this 相当于 “我”
使用构造函数重新创建猫咪对象
function Cat(name, type, sound) {
this.name = name;
this.type = type;
this.miao = function () {
console.log(sound); // 别忘了作用域的链式访问规则
}
}
var mimi = new Cat('咪咪', '中华田园喵', '喵');
var xiaohei = new Cat('小黑', '波斯喵', '猫呜');
var ciqiu = new Cat('刺球', '金渐层', '咕噜噜');
console.log(mimi);
mimi.miao();
理解 new 关键字
new 的执行过程:
JavaScript 的对象和 Java 的对象的区别
1. JavaScript 没有 “类” 的概念
对象其实就是 “属性” + “方法” .
类相当于把一些具有共性的对象的属性和方法单独提取了出来, 相当于一个 “月饼模子”
在 JavaScript 中的 “构造函数” 也能起到类似的效果.
而且即使不是用构造函数, 也可以随时的通过 { } 的方式指定出一些对象
在 ES6 中也引入了 class 关键字, 就能按照类似于 Java 的方式创建类和对象了.
2. JavaScript 对象不区分 “属性” 和 “方法”
JavaScript 中的函数是 “一等公民”, 和普通的变量一样. 存储了函数的变量能够通过 ( ) 来进行调用执行.
3. JavaScript 对象没有 private / public 等访问控制机制.
对象中的属性都可以被外界随意访问.
4. JavaScript 对象没有 “继承”
继承本质就是 “让两个对象建立关联”. 或者说是让一个对象能够重用另一个对象的属性/方法.
JavaScript 中使用 “原型” 机制实现类似的效果.
例如: 创建一个 cat 对象和 dog 对象, 让这两个对象都能使用 animal 对象中的 eat 方法.
通过 proto 属性来建立这种关联关系 (proto 翻译作 “原型”)
当eat方法被调用的时候,先在自己的方法列表中寻找, 如果找不到,就去找原型中的方法, 如果原型中找不到, 就去原型的原型中去寻找… 最后找到Object那里, 如果还找不到, 那就是未定义了。
5. JavaScript 没有 “多态”
多态的本质在于 “程序猿不必关注具体的类型, 就能使用其中的某个方法”.
C++ / Java 等静态类型的语言对于类型的约束和校验比较严格. 因此通过 子类继承父类, 并重写父类的方法的方式 来实现多态的效果.
但是在 JavaScript 中本身就支持动态类型, 程序猿在使用对象的某个方法的时候本身也不需要对对象的类型做出明确区分. 因此并不需要在语法层面上支持多态.
例如:
在 Java 中已经学过 ArrayList 和 LinkedList. 为了让程序猿使用方便, 往往写作
List<String> list = new ArrayList<>()
然后我们可以写一个方法:
void add(List<String> list, String s) {
list.add(s);
}
我们不必关注 list 是 ArrayList 还是 LinkedList, 只要是 List 就行. 因为 List 内部带有 add 方法.
当我们使用 JavaScript 的代码的时候
function add(list, s) {
list.add(s)
}
add 对于 list 这个参数的类型本身就没有任何限制. 只需要 list 这个对象有 add 方法即可. 就不必
像 Java 那样先继承再重写绕一个圈子.
JS 分成三个大的部分
WebAPI 就包含了 DOM + BOM.
这个是 W3C 组织规定的. (和制定 ECMAScript 标准的大佬们不是一伙人).
API 是一个更广义的概念. 而 WebAPI 是一个更具体的概念, 特指 DOM+BOM
所谓的 API 本质上就是一些现成的函数/对象, 让程序猿拿来就用, 方便开发.
相当于一个工具箱. 只不过程序猿用的工具箱数目繁多, 功能复杂.
DOM 全称为 Document Object Model.
W3C 标准给我们提供了一系列的函数, 让我们可以操作:
一个页面的结构是一个树形结构, 称为 DOM 树.
树形结构在数据结构阶段会介绍. 就可以简单理解成类似于 “家谱” 这种结构
页面结构形如
重要概念:
这些文档等概念在 JS 代码中就对应一个个的对象.
所以才叫 “文档对象模型” .
前面的几种方式获取元素的时候都比较麻烦. 而使用 querySelector 能够完全复用前面学过的 CSS 选择器知识, 达到更快捷更精准的方式获取到元素对象.
var element = document.querySelector(selectors);
<div class="box">abc</div>
<div id="id">def</div>
<h3><span><input type="text"></span></h3>
<script>
var elem1 = document.querySelector('.box');
console.log(elem1);
var elem2 = document.querySelector('#id');
console.log(elem2);
var elem3 = document.querySelector('h3 span input');
console.log(elem3);
</script>
使用 querySelectorAll 用法和上面类似.
<div class="box">abc</div>
<div id="id">def</div>
<script>
var elems = document.querySelectorAll('div');
console.log(elems);
</script>
JS 要构建动态页面, 就需要感知到用户的行为.
用户对于页面的一些操作(点击, 选择, 修改等) 操作都会在浏览器中产生一个个事件, 被 JS 获取到, 从而进行更复杂的交互操作.
浏览器就是一个哨兵, 在侦查敌情(用户行为). 一旦用户有反应(触发具体动作), 哨兵就会点燃烽火台的狼烟(事件),后方就可以根据狼烟来决定下一步的对敌策略
<button id="btn">点我一下</button>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
alert("hello world");
}
</script>
注意: 这个匿名函数相当于一个回调函数, 这个函数不需要程序猿主动来调用, 而是交给浏览器, 由浏览器自动在合适的时机(触发点击操作时) 进行调用.
1. innerText
Element.innerText 属性表示一个节点及其后代的“渲染”文本内容
// 读操作
var renderedText = HTMLElement.innerText;
// 写操作
HTMLElement.innerText = string;
不识别 html 标签. 是非标准的(IE发起的). 读取结果不保留html源码中的 换行 和 空格
<div>
<span>hello world</span>
<span>hello world</span>
</div>
<script>
var div = document.querySelector('div');
// 读取 div 内部内容
console.log(div.innerText);
// 修改 div 内部内容, 界面上就会同步修改
div.innerText = 'hello js hello js';
</script>
可以看到, 通过 innerText 无法获取到 div 内部的 html 结构, 只能得到文本内容.
修改页面的时候也会把 span 标签当成文本进行设置.
2. innerHTML
Element.innerHTML 属性设置或获取HTML语法表示的元素的后代.
// 读操作
var content = element.innerHTML;
// 写操作
element.innerHTML = htmlString;
识别 html 标签. W3C 标准的. 读取结果保留html源码中的 换行 和 空格
<div>
<span>hello world</span>
<span>hello world</span>
</div>
<script>
var div = document.querySelector('div');
// 读取页面内容
console.log(div.innerHTML);
// 修改页面内容
div.innerHTML = 'hello js'
</script>
可以看到 innerHTML 不光能获取到页面的 html 结构, 同时也能修改结构. 并且获取到的内容保留的空格和换行
可以通过 Element 对象的属性来直接修改, 就能影响到页面显示效果
<img src="rose.jpg" alt="这是一朵花" title="玫瑰花">
<script>
var img = document.querySelector('img');
console.dir(img);
</script>
此时可以看到 img 这个 Element 对象中有很多属性
<img src="rose.jpg" alt="这是一朵花" title="玫瑰花">
<script>
var img = document.querySelector('img');
// console.dir(img);
console.log(img.src);
console.log(img.title);
console.log(img.alt);
</script>
<img src="rose.jpg" alt="这是一朵花" title="玫瑰花">
<script>
var img = document.querySelector('img');
img.onclick = function () {
if (img.src.lastIndexOf('rose.jpg') !== -1) {
img.src = './rose2.png';
} else {
img.src = './rose.jpg';
}
}
</script>
此时点击图片就可以切换图片显示状态.
表单(主要是指 input 标签)的以下属性都可以通过 DOM 来修改
input 具有一个重要的属性 value, 这个 value 决定了表单元素的内容
如果是输入框, value 表示输入框的内容, 修改这个值会影响到界面显式; 在界面上修改这个值也会影响到代码中的属性
如果是按钮, value 表示按钮的内容. 可以通过这个来实现按钮中文本的替换
CSS 中指定给元素的属性, 都可以通过 JS 来修改.
行内样式操作
element.style.[属性名] = [属性值];
element.style.cssText = [属性名+属性值];
“行内样式”, 通过 style 直接在标签上指定的样式. 优先级很高.
适用于改的样式少的情况
类名样式操作
element.className = [CSS 类名];
修改元素的 CSS 类名. 适用于要修改的样式很多的情况
分成两个步骤
1. 创建元素节点
使用 createElement 方法来创建一个元素
var element = document.createElement(tagName[, options]);
<div class="container">
</div>
<script>
var div = document.createElement('div');
div.id = 'mydiv';
div.className = 'box';
div.innerHTML = 'hehe';
console.log(div);
</script>
此时发现, 虽然创建出新的 div 了, 但是 div 并没有显示在页面上. 这是因为新创建的节点并没有加入到DOM 树中.
上面介绍的只是创建元素节点, 还可以使用:
我们以 createElement 为主即可.
2. 插入节点到 dom 树中
element.appendChild(aChild)
<div class="container">
</div>
<script>
var div = document.createElement('div');
div.id = 'mydiv';
div.className = 'box';
div.innerHTML = 'hehe';
var container = document.querySelector('.container');
container.appendChild(div);
</script>
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
如果 referenceNode 为 null 则 newNode 将被插入到子节点的末尾.
注意: referenceNode 引用节点不是可选参数
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv, container.children[0]);
</script>
注意1: 如果针对一个节点插入两次, 则只有最后一次生效(相当于把元素移动了)
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
// 此处的 children 里有 4 个元素
container.insertBefore(newDiv, container.children[0]);
// 此处的 children 里有 5 个元素(上面新插了一个), 0 号元素是 新节点,
// 1 号元素是 11, 2号节点是 22, 所以是插入到 22 之前.
container.insertBefore(newDiv, container.children[2]);
</script>
注意2: 一旦一个节点插入完毕, 再针对刚刚的节点对象进行修改, 能够同步影响到 DOM 树中的内容
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv, container.children[0]);
// 插入完毕后再次修改 newDiv 的内容
newDiv.innerHTML = '我是新节点2';
</script>
使用 removeChild 删除子节点
oldChild = element.removeChild(child);
预期效果
<button type="button" id="reset">重新开始一局游戏</button>
<br>
请输入要猜的数字:<input type="text" id="number">
<button type="button" id="button">猜</button>
<br>
已经猜的次数:<span id="count">0</span>
<br>
结果:<span id="result"></span>
<script>
var inputE = document.querySelector("#number");
var countE = document.querySelector("#count");
var resultE = document.querySelector("#result");
var btn = document.querySelector("#button");
var resetBtn = document.querySelector("#reset");
// 随机生成一个 1-100 的数字
var guessNumber = Math.floor(Math.random() * 100) + 1// 0 - 1 之间的数
var count = 0;
// on: 当
// click: 点击
// 事件驱动(Event-Drive):只要真正发生了点击事件时,才执行该函数
btn.onclick = function() {
count++;
countE.innerText = count;
var userGuess = parseInt(inputE.value);
if (userGuess == guessNumber) {
resultE.innerText = "猜对了";
resultE.style = "color: gray;";
} else if (userGuess < guessNumber) {
resultE.innerText = "猜小了";
resultE.style = "color: blue;";
} else {
resultE.innerText = "猜大了";
resultE.style = "color: red;";
}
};
resetBtn.onclick = function() {
guessNumber = Math.floor(Math.random() * 100) + 1
count = 0;
countE.innerText = count;
resultE.innerText = "";
inputE.value = "";
}
</script>
预期效果
创建页面布局
创建 表白墙.html
<h1>表白墙</h1>
<p>输入后点击提交, 会将信息显示在表格中</p>
<span>谁: </span>
<input type="text">
<span>对谁: </span>
<input type="text">
<span>说什么: </span>
<input type="text">
<input type="button" value="提交">
此时效果形如
调整样式
<div class="container">
<h1>表白墙</h1>
<p>输入后点击提交, 会将信息显示在表格中</p>
<div class="row">
<span>谁: </span>
<input class="edit" type="text">
</div>
<div class="row">
<span>对谁: </span>
<input class="edit" type="text">
</div>
<div class="row">
<span>说什么: </span>
<input class="edit" type="text">
</div>
<div class="row">
<input type="button" value="提交" class="submit">
</div>
</div>
<style>
* {
margin: 0;
padding: 0;
}
.container {
width: 400px;
margin: 0 auto;
}
h1 {
text-align: center;
padding: 20px 0;
}
p {
color: #666;
text-align: center;
font-size: 14px;
padding: 10px 0;
}
.row {
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
span {
width: 100px;
line-height: 40px;
}
.edit {
width: 200px;
height: 30px;
}
.submit {
width: 304px;
height: 40px;
color: white;
background-color: orange;
border: none;
}
</style>
此时效果形如
实现提交
// 给点击按钮注册点击事件
var submit = document.querySelector('.submit');
submit.onclick = function () {
// 1. 获取到编辑框内容
var edits = document.querySelectorAll('.edit');
var from = edits[0].value;
var to = edits[1].value;
var message = edits[2].value;
console.log(from + "," + to + "," + message);
if (from == '' || to == '' || message == '') {
return;
}
// 2. 构造 html 元素
var row = document.createElement('div');
row.className = 'row';
row.innerHTML = from + '对' + to + '说: ' + message;
// 3. 把构造好的元素添加进去
var container = document.querySelector('.container');
container.appendChild(row);
// 4. 同时清理之前输入框的内容
for (var i = 0; i < 3; i++) {
edits[i].value = '';
}
}
实现点击按钮的动画效果
需要使用伪类选择器.
伪类选择器种类有很多. 此处的 :active 表示选中被按下的按钮
.submit:active {
background-color: #666;
}
创建页面布局
创建 待办事项.html
<div class="nav">
<input type="text">
<button>新建任务</button>
</div>
<div class="container">
<div class="todo">
<h3>未完成</h3>
<div class="row">
<input type="checkbox">
<span>吃饭</span>
<button>删除</button>
</div>
</div>
<div class="done">
<h3>已完成</h3>
</div>
</div>
实现页面样式
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 800px;
margin: 0 auto;
display: flex;
}
.todo,
.done {
width: 50%;
height: 100%;
}
.container h3 {
height: 50px;
text-align: center;
line-height: 50px;
background-color: #333;
color: #fff;
}
.nav {
width: 800px;
height: 100px;
margin: 0 auto;
display: flex;
align-items: center;
}
.nav input {
width: 600px;
height: 50px;
}
.nav button {
width: 200px;
height: 50px;
border: none;
background-color: orange;
color: #fff;
}
.row {
height: 50px;
display: flex;
align-items: center;
}
.row input {
margin: 0 10px;
}
.row span {
width: 300px;
}
.row button {
width: 50px;
height: 40px;
}
</style>
实现页面行为
实现新增
// 实现新增任务
var addTaskButton = document.querySelector('.nav button');
addTaskButton.onclick = function () {
// 1. 获取到任务内容的输入框
var input = document.querySelector('.nav input');
// 2. 获取到输入框内容
var taskContent = input.value;
// 3. 根据内容新建一个元素节点
var row = document.createElement('div');
row.className = 'row';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
var span = document.createElement('span');
span.innerHTML = taskContent;
var button = document.createElement('button');
button.innerHTML = '删除';
row.appendChild(checkbox);
row.appendChild(span);
row.appendChild(button);
// 4. 把新节点插入到 todo 中
var todo = document.querySelector('.todo');
todo.appendChild(row);
}
点击复选框后将元素放到 “已完成”
注意:
// 修改 addTaskButton.onclick
addTaskButton.onclick = function () {
// 上方的部分不变...
// 5. 给 checkbox 注册点击事件
checkbox.onclick = function () {
//
var row = this.parentNode;
// 注意! 是先触发 checked 为 true, 然后再调用 onclick 函数
if (this.checked) {
var target = document.querySelector('.done');
} else {
var target = document.querySelector('.todo');
}
target.appendChild(row);
}
}
点击删除按钮删除该任务
// 修改 addTaskButton.onclick
addTaskButton.onclick = function () {
// 上方的部分不变...
// 6. 给删除按钮注册点击事件
button.onclick = function () {
var row = this.parentNode;
var grandParent = row.parentNode;
grandParent.removeChild(row);
}
}