1、项目流程与数据库
1.课程体系
阶段1(服务器开发): 项目导入/数据库/JS基础/NodeJS
阶段2(前端核心技术): HTML/AJAX/CSS/bootstrap
阶段3(前端进阶技术):JS高级/DOM&BOM/jquery/VueJS
阶段4(H5移动开发):VueJS组件库/HTML5技术/微信开发/HybirdAPP
阶段5(框架技术):AngularJS/ReactJS/Python
2.Window操作系统中常用的快捷键
Alt+Tab: 切换窗口(向右)
Alt+Shift+Tab: 切换窗口(向左)
Window+d 显示/隐藏桌面
Window+r 打开“运行”窗口 输入cmd打开命令行窗口
Window+e 打开“资源管理器”
Alt+F4 关闭当前窗口
练习:不使用鼠标——进入C:/xampp/htdocs,创建demo.html,使用编辑器打开,输入内容;保存使用浏览器打开该文件;最后删除demo.html
3.软件工程
无软件阶段 bug -> debug
软件作坊 IBM ->Dos->Microsoft->Windows->Bill Gates
软件工程
软件过程(开发流程)
软件测试
软件度量
软件质量保证
4.软件的开发流程
软件过程/软件的生命周期
1)软件定义期
(1)可行性研究阶段
技术、人力、设备、时间、资金、回报、政策、风俗...
(2)需求分析阶段
功能性需求、非功能性需求
2)软件开发期
(1)概要设计阶段——设计师
子系统、模块、各自功能、模块间的接口
(2)详细设计阶段——架构师
页面、主题内容、对象、属性、方法
(3)编码实现阶段
UI设计:效果图
前端:把效果图转换为html/css/js代码
后端:为前端提供页面需要的数据
(4)测试阶段——软件测试工程师
3)软件维护期
(1)项目部署阶段
将项目部署到服务器
(2)项目维护阶段
5.学子商城功能性需求
前台:www.codeboy.com 后台:www.codeboy.com/admin/login.html (1)前台子系统: 商品模块、用户模块、购物车模块 (2)后台子系统: 商品模块、用户模块、订单模块 (3)移动端子系统: 商品模块、用户模块、购物车模块 |
6.web项目中的服务器
Server: 为客户端提供各种服务的功能强大的计算机。
访问服务器:
(1)服务器地址: 域名/IP地址
(2)对应的服务的端口号
(3)提供该服务所有使用的协议
http://www.codeboy.com:80
协议 域名/IP地址 端口
7.访问自己电脑上的web服务器
启动web服务器 /webServer/start.cmd
http://127.0.0.1:80 通过自己电脑的IP地址
http://localhost:80 通过自己电脑服务器的域名
练习:在public下创建4.html,随便输入内容,分别使用域名和IP地址访问该文件。
获取自己电脑在局域网的IP地址
在命令行下输入 ipconfig
http://172.163.100.134:80 通过局域网IP来访问服务器
练习:同桌之间互相访问对应的服务器
Mysql
day01
关系型数据库
Server->Database->Table->Row->Column
mysql
服务器端:开启服务
客户端:连接
连接
mysql.exe -h127.0.0.1 -P3306 -uroot -p
mysql -uroot
mysql -uroot < c:/....
交互模式
脚本模式
常用管理命令
show databases;
use 名字;
show tables;
desc 表名;
quit;
sql命令
增删改查
drop database if exists ...
create database..
use ...
create table
insert into
select * from ...
update ... set ... where
delete from ... where
标准SQL语句分类
DDL: Data Define Language 定义数据结构 CREATE/DROP/ALTER DML: Data Manipulate Language 操作数据 INSERT/UPDATE/DELETE DQL: Data Query Language 查询数据 SELECT DCL: Data Control Language 控制用户权限 GRANT(授权)/REVOKE(收权) |
1.计算机存储字符
(1)如何存储英文字符
ASCII: 总共有128个,对所有的英文字母和符号进行编码。
hel 104101108
Latin-1: 总共有256,兼容ASCII码,同时对欧洲符号进行了编码。MySQL默认使用这种编码。
(2)如何存储中文字符
GB2312: 对常用6千多汉字进行了编码,兼容ASCII
GBK: 对2万多汉字进行了编码,兼容GB2312
BIG5: *繁体字编码,兼容ASCII
Unicode: 对世界上主流国家常用的语言进行了编码,兼容ASCII,不兼容GB2312,GBK,BIG5。具体分为UTF-8,UTF-16,UTF-32存储方案。
(3)解决mysql存储中文乱码
sql脚本文件另存为的编码
客户端连接服务器的编码(SET NAMES UTF8)
服务器端创建数据库使用的编码(CHARSET=UTF8)
练习:编写脚本文件01_sina.sql,创建数据库sina,设置存储编码为UTF8,进入该数据库,创建数据表news保存新闻数据,包含nid,title(标题),ctime(发表时间),content(内容),author(作者),cfrom(来源);插入若干条数据。在交互模式下查询数据。
2.mysql中的列类型
创建数据表的时候,指定的列可以存储的数据类型
CREATE TABLE t1( nid 列类型 );
(1)数值型 引号可加可不加
TINYINT 微整型,占1个字节 范围-128~127
SMALLINT 小整型,占2个字节,范围-32768~32767
INT 整型,占4个字节,范围
-2147483648~2147483647
BIGINT 大整型,占8个字节
FLOAT 单精度浮点型,占4个字节,最多3.4E38,可能产生计算误差。
DOUBLE 双精度浮点型,占8个字节,范围比BIGINT大的多,也可能查收计算误差。
DECIMAL(M,D) 定点小数,不会产生计算误差;M代表总的有效位数,D代表小数点后的有效位数。
BOOL 布尔型,只有两个值TRUE/1、FALSE/0,TRUE和FALSE不能加引号;真正存储数据的时候,会变成TINYINT,数据是1和0
(2)日期时间型 必须加引号
DATE 日期型 '2018-10-31'
TIME 时间型 '14:30:50'
DATETIME 日期时间型 '2018-10-31 14:30:50'
(3)字符串型 必须加引号
VARCHAR(M) 变长字符串,不会产生空间浪费,操作速度相对慢,M最大值时65535。
CHAR(M) 定长字符串,可能产生空间浪费,操作速度相对快,M最大值是255;用于存储手机号码、身份证号码等固定长度的字符串。
TEXT(M) 大型变长字符串,M最多2G
CHAR(5) |
VARCHAR(5) |
|
a |
a\0\0\0\0 |
a\0 |
ab |
ab\0\0\0 |
ab\0 |
abcde |
abcde |
abcde |
一二三 |
一二三\0\0 |
一二三\0 |
CREATE TABLE t1(
id INT,
age TINYINT,
commontCount INT,
price DECIMAL(6,2), #9999.99
phone CHAR(11),
article VARCHAR(5000),
sex BOOL, # 1->男 0->女
pubTime DATE
);
练习:编写02_xuezi.sql文件,先丢弃再创建数据库xuezi,设置存储的编码为UTF8,进入该数据库,创建保存笔记本数据的表laptop,包含lid,title(标题),price(价格),stockCount(库存量),shelfTime(上架时间),isIndex(是否显示在首页);插入4条数据
练习:编写脚本文件03_tedu.sql,创建数据库tedu,设置存储的编码为UTF8;进入该数据库,创建保存部门数据的表dept,包含did,dname(部门名称),empCount(员工数量);插入以下数据
10 研发部 3
20 运营部 2
30 市场部 2
创建保存员工数据的表emp,包含eid,ename(姓名),sex(性别),birthday(生日),salary(工资)
插入若干条数据。
3.列约束
mysql可以对要插入的数据进行特定的验证,只有满足条件才允许插入到数据表中,否则被认为非法的插入。
例如:一个人的性别只能是男或者女,一个人的年龄0~100
(1)主键约束——PRIMARY KEY
声明了主键约束的列上的值不能出现重复,一个表中只能有一个主键,通常加在编号列。设置了主键约束就不能使用NULL值。
表中查询的记录会按照主键由小到大的顺序排序——加快查找速度。
NULL 表示空,在插入数据时,无法确定要保存的数据。例如:无法确定员工的工资,生日都可以使用NULL |
(2)非空约束——NOT NULL
声明了非空约束的列上不能插入NULL值
课后任务
(1)复习今天内容,重新编写代码
(2)练习
编写脚本文件xz.sql,创建数据库xz,进入该数据库;
创建保存笔记本家族的表laptop_family,包含fid,fname,laptopCount笔记本数量
10 联想 2 20 戴尔 2 30 小米 3
创建保存笔记本数据的表laptop,包含lid,title,price,spec规格,detail商品介绍,shelfTime,isOnsale是否在售,familyId所属家族编号;插入若干条数据。
(3)预习列约束
复习
ASCII/Latin-1/GB2312/GBK/BIG5/Unicode
脚本/客户端连接/服务器端
列类型
数值型
TINYINT/SMALLINT/INT/BIGINT
FLOAT/DOUBLE/DECIMAL/BOOL
日期时间型
DATE/TIME/DATETIME
字符串型
VARCHAR/CHAR/TEXT
1.列约束
(1)主键约束——PRIMARY KEY
(2)非空约束——NOT NULL
(3)唯一约束——UNIQUE
声明了唯一约束的列上不能插入重复的值,允许插入NULL,而且允许插入多个NULL
(4)检查约束——CHECK
检查约束可以对插入的数据进行自定义验证
CREATE TABLE student(
score TINYINT CHECK(score>=0 AND score<=100)
);
mysql不支持检查约束,会降低数据的插入速度。
(5)默认值约束——DEFAULT
可以使用DEFAULT关键字声明默认值,有两种方式可以应用默认值
INSERT INTO family VALUES(50, '华硕', DEFAULT);
INSERT INTO family(fid,fname) VALUES(60,'荣耀');
练习:设置笔记本的默认价格为6999,分别应用两种默认值插入数据。
(6)外键约束——FOREIGN KEY
声明了外键约束的列,取值必须在另一个表的主键列上出现过,两者的列类型要保持一致,允许使用NULL或者多个NULL
FOREIGN KEY(列) REFERENCES 数据表(主键列)
2.mysql中的自增列
AUTO_INCREMENT: 自动增长,假如一个列声明了自增列,无需手动赋值;直接赋值为NULL,会获取当前的最大值,然后加1插入。
注意:
只适用于整数型的主键列上
自增列允许手动赋值
练习:创建脚本文件01_tedu.sql,创建数据库tedu;进入该数据库
创建部门表dept,包含(did,dname)
10 研发部 20 市场部 30 运营部 40 测试部
创建员工表emp,包含(eid,ename,sex,birthday,salary,deptId 所属部门编号)
插入15条记录
3.简单查询
(1)查询特定的列
示例:查询所有员工的姓名、工资
SELECT ename,salary FROM emp;
练习:查询所有员工的编号,姓名,性别,生日
SELECT eid,ename,sex,birthday FROM emp;
(2)查询所有的列
SELECT * FROM emp;
SELECT eid,ename,sex,birthday,salary,deptId FROM emp;
(3)给列起别名
示例:查询所有员工的姓名和工资,使用汉字别名
SELECT ename AS 姓名,salary AS 工资 FROM emp;
练习:查询所有员工的编号,姓名,性别,生日,使用汉字别名
SELECT eid AS 编号,ename AS 姓名,sex 性别,birthday 生日 FROM emp;
练习:查询所有员工编号和姓名,使用一个字母作为别名
SELECT eid a,ename b FROM emp;
在起别名的时候,AS关键字可以省略,保留空格。 |
(4)显示不同的记录/合并相同的记录
示例:查询出员工都在哪些部门
SELECT DISTINCT deptId FROM emp;
练习:查询出都有哪些性别的员工
SELECT DISTINCT sex FROM emp;
(5)在查询时执行计算
示例:计算2+3*5+7.4*3.5
SELECT 2+3*5+7.4*3.5 AS 结果;
练习:查询所有员工的姓名及其年薪
SELECT ename,salary*12 FROM emp;
练习:假设每个员工工资增加500,年终奖5000,查询所有员工的姓名及其年薪,给列别起中文别名。
SELECT ename AS 姓名,(salary+500)*12+5000 AS 年薪 FROM emp;
(6)查询结果集排序
示例:查询所有的部门,结果集按照部门编号升序排列
SELECT * FROM dept ORDER BY did ASC;#ascendant
示例:查询所有的部门,结果集按照部门编号降序排列
SELECT*FROM dept ORDER BY did DESC;#descendant
练习:查询所有员工,结果集按照工资的降序排列
SELECT * FROM emp ORDER BY salary DESC;
练习:查询所有员工,结果集按照年龄从小到大排列
SELECT * FROM emp ORDER BY birthday DESC;
练习:查询所有员工,结果集按照姓名升序排列
SELECT * FROM emp ORDER BY ename;
练习:查询所有员工,结果集按照工资降序排列,如果工资相同,按照姓名排序
SELECT * FROM emp ORDER BY salary DESC,ename;
练习:查询所有员工,结果集按照性别升序排列,如果性别相同,按照生日降序排列。
SELECT * FROM emp ORDER BY sex,birthday DESC;
ORDER BY可以按照数值、日期/时间、字符串来排序 默认按照ASC升序排列 |
(7)条件查询
示例:查询出编号为5的员工所有列
SELECT * FROM emp WHERE eid=5;
练习:查询出姓名叫King的员工的编号,工资,姓名
SELECT eid,salary,ename FROM emp WHERE ename='king';
练习:查询出20号部门下员工所有的列
SELECT * FROM emp WHERE deptId=20;
练习:查询出女员工所有的列
SELECT * FROM emp WHERE sex=0;
练习:查询出工资为5000以上的员工所有列
SELECT * FROM emp WHERE salary>=5000;
比较运算符:> < >= <= = !=(不等于) |
练习:查询出1991-1-1后出生的员工所有列
SELECT * FROM emp WHERE birthday>'1991-1-1';
练习:查询出不在10号部门的员工所有列
SELECT * FROM emp WHERE deptId!=10;
练习:查询出没有明确部门的员工所有列
SELECT * FROM emp WHERE deptId IS NULL;
练习:查询出有明确部门的员工所有列
SELECT * FROM emp WHERE deptId IS NOT NULL;
练习:查询出工资在6000以上男员工所有列
SELECT * FROM emp WHERE salary>6000 AND sex=1;
练习:查询出工资在5000~7000之间员工所有列
SELECT * FROM emp WHERE salary>=5000 AND salary<=7000;
SELECT * FROM emp WHERE salary BETWEEN 5000 AND 7000;
练习:查询出工资在5000以下和7000以上的员工所有列
SELECT * FROM emp WHERE salary<5000 OR salary>7000;
SELECT * FROM emp WHERE salary NOT BETWEEN 5000 AND 7000;
练习:查询出1990年之前和1993之后出生的员工所有列
SELECT * FROM emp WHERE birthday<'1990-1-1' OR birthday >'1993-12-31';
SELECT * FROM emp WHERE birthday NOT BETWEEN '1990-1-1' AND '1993-12-31';
练习:查询出1993年出生的员工所有列
SELECT * FROM emp WHERE birthday>='1993-1-1' AND birthday<='1993-12-31';
SELECT * FROM emp WHERE birthday BETWEEN '1993-1-1' AND '1993-12-31';
练习:查询出20号部门和30号部门的员工所有列
SELECT * FROM emp WHERE deptId=20 OR deptId=30;
SELECT * FROM emp WHERE deptId IN(20,30);
练习:查询出不在20号部门和30号部门员工所有列
SELECT * FROM emp WHERE deptId NOT IN(20,30);
IS NULL/IS NOT NULL AND/OR BETWEEN ... AND../NOT BETWEEN...AND... IN( )/NOT IN ( ) |
(8)模糊条件查询
示例:查询姓名中含有字母e的员工所有列
SELECT * FROM emp WHERE ename LIKE '%e%';
练习:查询姓名中以e结尾的员工所有列
SELECT * FROM emp WHERE ename LIKE '%e';
练习:查询姓名中倒数第2个字符为e的员工所有列
SELECT * FROM emp WHERE ename LIKE '%e_';
% 可以匹配任意多个字符 >=0 _ 可以匹配任意1个字符 =1 以上两个匹配必须使用LIKE关键字 |
(9)分页查询
假如查询的结果集中有太多的数据,一次显示不完,可以分页显示。
需要有两个条件:当前的页码、每页的数据量
SELECT * FROM emp LIMIT start,count;
start: 是一个数字,表示从哪一条开始读取;
start=(当前的页码-1)*每页的数据量 |
count:是一个数字,表示每页的数据量
注意:start和count的值必须是整数,不能是字符串形式。
假设每页显示5条记录
第1页:SELECT * FROM emp LIMIT 0,5;
第2页:SELECT * FROM emp LIMIT 5,5;
第3页:SELECT * FROM emp LIMIT 10,5;
第4页:SELECT * FROM emp LIMIT 15,5;
第5页:SELECT * FROM emp LIMIT 20,5;
课后任务:
(1)复习今天内容,删除代码保留注释,重新编写SQL语句
(2)查询出工资在8000以上的女员工的姓名、性别、生日,结果集按照按照工资降序排列,取前3个人。
(3)查看学子商城资料,编写数据库(见文件)
Javascript基础
Day01
查询出工资在8000以上的女员工的姓名、性别、生日,结果集按照按照工资降序排列,取前3个人。
SELECT ename,sex,birthday,salary FROM emp
WHERE salary>8000 AND sex=0
ORDER BY salary DESC
LIMIT 0,3;
项目中的时间
2019-3-4 2019年3月4日 3/4/2019 2019/3 2019-3 9:53 9:53:30
距离计算机元年(1970-1-1 0:0:0)的毫秒数
1秒=1000毫秒
2019-1-1 --10:14
49*365*24*60*60*1000
性别 男/女 woman/man boy/girl
1/0
1.复杂查询
(1)聚合查询/分组查询
示例:查询所有员工的数量
SELECT COUNT(eid) FROM emp;
SELECT COUNT(*) FROM emp; #推荐写法
练习:使用员工的姓名来查询数量
SELECT COUNT(ename) FROM emp;
练习:使用员工的部门编号来查询数量
SELECT COUNT(deptId) FROM emp;
练习:查询所有女员工的数量
SELECT COUNT(*) FROM emp WHERE sex=0;
聚合函数 函数是一个功能体,提供若干数据,产出结果——饺子机 COUNT(..)/SUM(..)/AVG(..)/MAX(..)/MIN(..) |
练习:查询所有员工的工资总和是多少
SELECT SUM(salary) FROM emp;
练习:查询出男员工的平均工资是多少
SELECT SUM(salary)/COUNT(*) FROM emp WHERE sex=1;
SELECT AVG(salary) FROM emp WHERE sex=1;
练习:查询出工资最高的员工
SELECT MAX(salary) FROM emp;
练习:查询出工资最低的员工
SELECT MIN(salary) FROM emp;
练习:查询年龄最大的员工的生日
SELECT MIN(birthday) FROM emp;
分组查询:只能查询分组条件和聚合函数 |
示例:查询出每个部门工资最高的员工的工资
SELECT deptId,MAX(salary) FROM emp GROUP BY deptId;
练习:查询出男女员工的数量,最高工资,平均工资
SELECT sex,COUNT(*),MAX(salary),AVG(salary) FROM emp GROUP BY sex;
YEAR(..) 获取日期中的年份 MONTH(..) 获取日期中的月份 |
练习:查询出1991年出生的员工所有列
SELECT * FROM emp WHERE YEAR(birthday)=1991;
练习:查询3月份出生的员工所有列
SELECT * FROM emp WHERE MONTH(birthday)=3;
(2)子查询
把一个SQL语句的查询结果作为另一个SQL语句的查询条件 |
示例:查询出研发部所有的员工
步骤1:查询出研发部的部门编号——10
SELECT did FROM dept WHERE dname='研发部';
步骤2:查询出10号部门所有的员工
SELECT * FROM emp WHERE deptId=10;
综合:
SELECT * FROM emp WHERE deptId=(SELECT did FROM dept WHERE dname='研发部');
练习:查询出工资比tom高的员工有哪些
步骤1:查询出tom的工资是多少——6000
SELECT salary FROM emp WHERE ename='tom';
步骤2:查询出比6000高的员工
SELECT * FROM emp WHERE salary>6000;
综合:
SELECT * FROM emp WHERE salary>( SELECT salary FROM emp WHERE ename='tom');
练习:查询出和tom同一年出生的员工有哪些
步骤1:查询出tom的出生年份——1990
SELECT YEAR(birthday) FROM emp WHERE ename='tom';
步骤2:查询出1990年出生的员工有哪些
SELECT * FROM emp WHERE YEAR(birthday)=1990;
综合:
SELECT * FROM emp WHERE YEAR(birthday)=(
SELECT YEAR(birthday) FROM emp WHERE ename='tom'
);
(3)多表查询
示例:查询出所有的员工姓名及其部门名称
SELECT ename,dname FROM emp,dept;
错误:产生笛卡尔积
解决方法:添加查询条件
SELECT ename,dname FROM emp,dept WHERE did=deptId;
上述多表查询结果是SQL-92的查询语法,无法查询出没有部门的员工,没有员工的部门 SQL-99中提出了新的多表查询语法 |
(1)内连接——和SQL-92查询结果一致
SELECT ename,dname FROM emp INNER JOIN dept ON deptId=did;
(2)左外连接——显示左侧表中所有的记录
SELECT ename,dname FROM emp LEFT OUTER JOIN dept ON deptId=did;
OUTER 关键字可以省略
(3)右外连接——显示右侧表中所有的记录
SELECT ename,dname FROM emp RIGHT OUTER JOIN dept ON deptId=did;
OUTER 关键字可以省略
(4)全连接
显示左侧和右侧表中所有的记录——FULL JOIN
mysql不支持全连接
UNION 合并相同的记录
UNION ALL 不合并相同的记录
(SELECT ename FROM emp_us)
UNION
(SELECT ename FROM emp_cn);
把左外连接的结果和右外连接的结果合并
(SELECT ename,dname FROM emp LEFT OUTER JOIN dept ON deptId=did)
UNION
(SELECT ename,dname FROM emp RIGHT OUTER JOIN dept ON deptId=did);
2.学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
程序员必做50题
https://wenku.baidu.com/view/af66e2f14afe04a1b071de42.html
3.JS概述
(1)历史
1995年,JS最早出现在Netscape的浏览器中
1996年,IE3中也出现JS,称为JScript
1997年,ECMA组织,制定标准 ECMAScript
2009年,遵循CommonJS规范,开始向服务端发展
(2)现状
既可以运行在客户端浏览器,也可以运行在服务器端
(3)特点
跨平台,支持所有的操作系统
解释型语言,编译一行执行一行
基于对象
弱类型类型
(4)应用场景
制作浏览器端的交互效果
创建web服务器,操作数据库等
4.JS的开发环境
(1)浏览器端自带的JS解释器
(2)服务器端NodeJS解释器
https://nodejs.org nodejs下载地址
node -v 查看当前安装的nodejs版本
(3)执行JS代码
浏览器
创建01.js和01.html两个文件
在01.html中引入01.js文件
<script src="01.js"></script> |
NodeJS
node C:/xampp/..../01.js 回车
5.JS语法规范
(1)区分大小写
(2)每行代码结尾的分号可加可不加,建议都加
(3)分为单行注释(//...)和多行注释(/*...*/)
6.变量
用于存储数据的容器
x=1
(1)声明变量
var x=1;
使用关键字var声明了一个变量,名称叫x,存储的值是1
(2)变量的命名规则
变量名称可以使用字母、数字、下划线、美元符号,其中不能以数字开头。
不能使用关键字和保留字作为变量名称,例如:var、if、break...
user_name userPwd isLogin cityName
(3)变量的注意
var z;
变量只是声明未赋值,此时的值是undefined
可以为变量多次赋值,并且赋不同类型的值
(4)一次性声明多个变量
var a=1,b=2,c;
多个变量之间用逗号隔开
练习:声明语文、数学、和总成绩三个变量;总成绩为空,然后把语文和数学的和赋值给总成绩;打印三个变量。
7.常量
一旦声明不能再重新赋值
const PI=3.14;
8.数据类型
分为原始类型和引用类型
原始类型分为数值型、字符串型、布尔型、未定义型(undefined)、空(null)
(1)数值型
分为整型和浮点型
整型在内存中占4个字节,浮点型占8个字节
课后任务
(1)复习今天内容,整理思维导图
(2)练习:
使用变量保存圆的半径,常量保存圆周率;声明两个变量保存面积和周长;最后打印面积和周长。
声明多组变量保存商品的单价和数量,最后计算商品的总价。
(3)预习JS的数据类型
Day02
JS
浏览器端和服务器端
var $_a1=1,b=2;
const pi=3.14;
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1.数据类型
原始类型和引用类型
(1)数值型
整型
8进制 0 1 ... 7 10, 以0开头,例如 010->8
16进制 0 1 .... 9 a b c d e f 10
a~f 代表10~15,以0X开头,例如0XC->12
字母不区分大小写
0XFF -> 255
浮点型
分为普通小数和指数型小数
3.14 3.14e3->3140 3.14e-2 ->0.0314
(2)字符串型
任意的数据被引号包含就是字符串型,不区分单双引号
typeof 数据 检测数据类型
查看任意一个字符的Unicode码
'a'.charCodeAt() //97
练习:查看自己名字的Unicode码
(3)布尔型
在程序中表示真或者假
true/false
常用于存储一些是否的结果,例如是否注册,是否登录,是否为会员
isLogin=true isVip=false
(4)未定义型
声明了变量未赋值,结果就是undefined
(5)空
只有一个值null,用于引用类型数据中
2.数据类型转换
(1)隐式转换
数字+字符串 数字被转成了字符串类型
2+'3' // '23'
数字+布尔值 布尔值被转成了数字 true->1 false->0
2+true //3
2+false //2
字符串+布尔值 布尔值被转成字符串
'b'+true //'btrue'
JS中加号(+)的作用
执行加法运算
执行字符串拼接
练习:查看一下程序的执行结果
var a=2,b=true,c='tedu'; console.log(a+b+c); //'3tedu' console.log(b+c+a);//'truetedu2' console.log(c+a+b);//'tedu2true' |
使用 - * / 执行运算
将运算符两端的非数字转为数字,最终运算结果还是数字;转数字的过程中自动调用Number
(2)强制转换
①将任意类型转为数值型
Number(数据)
如果要转的字符串中含有非数字,则返回NaN(Not a Number)
undefined -> NaN
null -> 0
②将任意数据转为整型
parseInt(数据)
parseInt('2.3c') //2
如果字符串以非数字开头,则返回NaN,布尔型,undefined,null返回NaN
③将任意数据转为浮点型
parseFloat(数据)
parseFloat('2.3c') //2.3
和parseInt用法几乎一致,只是返回时浮点型。
④将数值型转为字符串类型
toString()
var num=12;
num.toString() //'12'
num.toString(16) // c
转换为字符串的同时,可以设置要转换的进制
3.运算符
由运算符连接的操作数据,所组成的形式称为表达式
(1)算术运算符
+ - * / % ++ --
% 取余
++ 自增,在原来的基础之上加1
-- 自减,在原来的基础之上减1
console.log(num++); 先打印num的值,再执行自增
console.log(++num); 先执行自增,然后打印num的值
练习:
var a=2; console.log(a++ + ++a); //6 var b=7; console.log(--b + b--); //12 |
(2)比较运算符
> < >= <= == != ===(全等于) !==(全不等于)
返回一个布尔型的值
== 只是比较值是否相同
=== 不仅比较值,还会比较类型是否相同
3>'10' //false
数字和字符串比较,字符串会转成数字
'3'>'10' //true
两个字符串比较,比较首字符的Unicode码
'3' ->51 '1'->49
3>'10a' //false
'10a'隐式转为了NaN,NaN和任何值比较(> < == === >= <=)都返回false
NaN==NaN false
(3)逻辑运算符
|| 或者 && 并且 ! 非
返回一个布尔型的结果
|| 关联的两个条件只需要满足其一,结果就是true,否则false
&& 关联的两个条件都满足,结果是true,否则false
! 取反 !true ->false !false->true
练习:声明两个变量保存用户名和密码,如果用户名是'root',并且密码是'123456',打印true,否则打印false
练习:声明一个变量保存年龄,如果年龄大于90岁,或者小于3岁,打印true,否则打印false
逻辑短路
&& 当第1个条件为false的时候,就不需要再执行第2个条件
|| 当第1个条件为true的时候,就不需要再执行第2个条件
练习:以下程序运行是否报错
var num=3; num>5 && console.log(a); num<1 || console.log(a); |
(4)位运算符
在执行位运算符的时候,会把数字转成二进制进行运算。
1 10 11 100 101 110 111 1000 1001 1010
2 4 8
85=64+16+4+1
1000000+10000+100+1
1010101
按位与(&) 上下两位都是1,结果是1,否则是0
按位或(|) 上下两位含有1,结果是1,否则是0
按位异或(^) 上下两位不同为1,相同为0
按位右移(>>) 删除二进制的最后的位数
按位左移(<<) 在二进制的最后补0
(5)赋值运算符
= += -= *= /= %=
课后任务
(1)复习今天内容,整理思维导图
(2)练习
声明一个变量保存年份,判断这个年份是否为闰年,如果是打印‘闰年’——逻辑短路
闰年:4年一闰(能被4整除),还有两个
(3)预习if、if-else、switch-case语句
Day03
复习
数值、字符串、布尔型、未定义、空
数据类型转换
隐式转换 + - * / 3>'2' 3>null
强制转换 Number/parseInt/parseFloat/toString(8)
运算符
算术运算符 + - * / % ++ --
比较运算符 > < >= <= == != === !==
逻辑运算符 || && ! 逻辑短路
位运算符 & | ^ >> <<
赋值运算符 = += -= *= /= %=
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1.三目运算符
由三组操作数据或表达式组成的形式
条件表达式 ? 表达式1 : 表达式2
如果条件表达式为true,执行表达式1;
如果条件表达式为false,执行表达式2
练习:声明变量保存用户名和密码,如果用户名是root,并且密码是123456,打印登录成功,否则打印登录失败
2.浏览器端函数
alert() 弹出警示框
prompt() 弹出提示框(输入框),需要使用变量保存输入的值;值的类型是字符串型
练习:两次弹出提示框,使用变量保存后,计算两个数字相加的和,并将和使用警示框弹出。
3.流程控制
程序分为顺序执行、选择执行、循环执行
程序 = 数据 + 算法
(1)if语句
满30减15
if(条件表达式){ 语句1; } 语句2; |
如果if后的大括号中只有一行语句,可以省略大括号。
false的几种情况,通常会和取反(!)一起使用。
0 '' undefined null NaN
(2)if-else语句
if(条件表达式){ 语句1; }else{ 语句2; } |
练习:使用弹出提示框分别输入商品的单价和数量,如果商品的总价满500,则打八折;假如当前卡内的余额为600,如果足够支付总价,打印pay success,否则打印pay error。
06_exercise.html 06_exercise.js
(3)if-else嵌套
if(条件表达式1){ 语句1; }else if(条件表达式2){ 语句2; }else...if(条件表达式n){ 语句n; }else{ 语句n+1; //以上所有的条件表达式都是false } |
(4)switch-case语句
switch(表达式){ case 值1: //如果表达式的值为值1 语句1; break; case 值2: 语句2; break; ... case 值n: 语句n; break; default: 语句n+1;//以上所有的结果都是false } |
注意:在case中表达式和值在比较的时候使用的是全等于(===),要求值和类型都满足结果才是true
对比if-else嵌套和switch-case语句
相同点:两者都可以用于多项分支语句
不同点:if-else可以判断相等或者不等的情况,使用范围更广;switch-case只能用于全等于(===)的情况,结构上更为清晰合理,执行效率更高。
4.循环执行
循环:就是一遍又一遍执行相同或者相似的代码
循环的两个要素:
循环的条件:控制循环的次数
循环体:重复执行的相同或者相似代码
(1)while循环
while(循环条件){ //结果是布尔型的值 循环体 } |
课后任务
(1)复习今天内容,整理思维导图
(2)练习:
使用switch-case来根据成绩判断标准
使用while循环打印 11~20之间所有整数
使用while循环打印1~100之间所有奇数
使用while循环打印20 22 24 26 28 30
(3)预习do-while循环,for循环,循环嵌套
Day04
复习
浏览器端函数 alert()/prompt()
流程控制
顺序执行、选择执行、循环执行
if(条件表达式){ 语句1; }
if(条件表达式){ 语句1; }else{ 语句2; }
条件表达式 ? 语句1 : 语句2;
if(条件表达式1){ 语句1; }else if(条件2){ }...else{ }
switch(表达式){
case 1:
语句1;
break;
default:
语句..
}
循环: 循环条件 循环体
1.break关键字
可以结束任何形式的循环
练习:使用变量保存一个数字,无限循环弹出提示框,获取输入的值,用输入的值和保存的数字比较,如果猜大了,弹出警示框'big',如果猜小了,弹出警示框'small',否则弹出警示框 'right'。
03_break.js 03_break.html
2.do-while循环
do{ 循环体; }while(循环条件); |
练习:打印50~1之间所有的整数
练习:打印1~100之间所有的偶数
练习:打印50~30之间所有能被5整除的数字
练习:计算1~100之间所有能被3整除的数字的和
练习:计算10的阶乘 !10 10*9....1
练习:声明一个变量保存密码'123456',无限循环弹出提示框,在提示框中输入密码,如果输入正确,结束循环。
05_dowhile.js 05_dowhile.html
3.for循环
for(表达式1;表达式2;表达式3){ 循环体 } 表达式1:初始值 表达式2:循环的条件 表达式3:循环的增量 |
练习:计算1~100所有能被7整除的数组的和
练习:打印72~39之间所有的奇数
练习:计算1~20之间所有能被3整除的数的乘积
练习:打印本世纪(2000~2100)所有的闰年
练习:假设本金10000,年利率是4%,5年后本金和利息一共有多少
4.break和continue
break:结束循环,不会再执行循环体以及增量等。
continue,跳过本次循环体,还会继续执行增量以及循环条件
练习:计算1~100之间所有偶数的和(遇到奇数跳过)
练习:打印1~100之间所有的数组,如果能被3或者4整除跳过。1 2 5 7 10 11 13...
练习:打印本世纪前10个闰年
5.循环嵌套
*
**
***
****
*****
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*9....
课后任务:
(1)复习今天内容,整理思维导图
(2)练习
打印倒着的九九乘法表
9*9=81 8*9=72
8*8=64
1*1
计算1~100之间的和,当和大于4000的时候,提前结束循环,打印当前的和是多少
(3)预习js中的自定义函数
Day05
复习
while(循环条件){ 循环体 }
do{ 循环体 }while(循环条件);
for(初始值;循环条件;循环增量){ 循环体 }
循环嵌套
任意循环之间都可以相互嵌套
break/continue
var i=0,sum=0; do{ i++; if(i%2==0){ continue; } if(i%5==0){ break; } sum+=i; }while(i<=10); |
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1.函数
parseInt()/parseFloat()...
分为系统函数和自定义函数
函数:function,是一个功能体,可以接收若干个数据,返回特定的结果。用于封装反复执行的代码——饺子机
(1)创建普通函数
function 函数名称(){ 函数体——封装的反复执行的代码 } |
调用:函数名称()
练习:创建函数,封装10+20的计算结果并打印出来,调用3次。
练习:创建函数,封装计算1~100之间所有整数的和并打印结果,调用3次
(2)创建带有参数的函数
function 函数名称(参数列表){ //形参 -> 用于接收数据 函数体 } |
调用: 函数名称(参数列表) //实参 ->实际要传递的数据
参数列表:创建函数时的参数称为形参,调用函数时的参数称为实参,在调用的时候实参会赋值给形参;多个参数之间用逗号隔开;如果实参的个数小于形参的个数,则未赋值的形参为undefined。
练习:创建函数getSum,传递1个参数,计算1~任意数字之间所有整数的和,调用3次。
练习:创建函数getRun,传递2个参数,计算任意两个年份之间的闰年个数,调用3次。
(3)创建带有返回值的函数
function 函数名称(参数列表){ 函数体 return 返回值; //函数的返回结果 } |
调用:函数名称(参数列表)
函数调用后会得到return的值。
注意事项:
如果没有return或者return后没有返回值,则返回undefined
return后的所有代码不会被执行
练习:创建函数getMax,传递2个参数,返回两个数字中的最大值。
练习:创建函数getMax,传递3个参数,返回三个数字中的最大值。
练习:创建函数getStatus,传递1个参数,根据状态码返回对应的中文
1-等待付款 2-等待发货 3-运输中 4-已签收 5-已取消
练习:创建函数getDays,传递1个参数(年份),返回任意年份的天数365/366。
2.变量的作用域
作用域:变量或者函数可访问范围。
全局作用域:在全局作用域下声明的变量,可以在任意合法位置访问到。
函数作用域:在函数中使用var声明的变量,只能在函数内部访问到。
变量的提升
JS程序执行前,当前作用域下使用var声明的变量,会将声明提升到最前,但是赋值还是在原来的位置
3.函数的作用域
和变量作用域一样,也分为全局作用域和函数作用域
函数声明提升
和变量提升一样,使用function关键字创建的函数,声明也会提升到所在作用域最前边。在任意合法都可以调用。
4.递归(掌握)
在函数的内部调用自身
递归的使用:
要有跳出的条件,结合着return来跳出。
练习:使用递归来计算1~任意数字之间所有整数的和。
练习:使用递归来计算任意数字的阶乘。
!10 = 10*9*8...*1
斐波那契数列
1 1 2 3 5 8 13 21 34 55 89....
课后任务
(1)复习今天内容,整理思维导图
(2)练习
使用递归和普通函数来计算斐波那契数列
(3)预习js中的自定义对象
Day06
复习
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1.匿名函数
没有名称的函数 function(){ }
创建函数——函数声明 function 函数名称(){ } |
(1)创建函数——函数表达式
var 函数名称=function(形参列表){ 函数体 return 返回值; } 调用 函数名称() |
对比函数声明和函数表达式的区别
函数声明存在函数提升,可以在任意位置创建,也可以在任意合法位置调用。
函数表达式不存在函数提升,只能先创建再调用。
(2)匿名函数自调用
创建一个独立的函数作用域,防止污染全局。
(function(形参列表){ 函数体; //封装的代码 })(实参列表); |
(3)回调函数
将匿名函数以参数传递
function fn(a){ //调用的时候,实参赋给形参a //a就是函数名称,如果执行匿名函数体,只需要调用a a(); } fn(function(){ .... }); |
2.全局函数
parseInt 将数据转为整型
parseFloat 将数据转为浮点型
isNaN 判断一个值是否为NaN,是->true 不是->false
isFinite 判断一个值是否为有限值, 是->true,不是->false
3/0 -> Infinity 无限值
eval 执行字符串中的表达式 eval('1+1') -> 2
练习:使用弹出提示框输入一组JS表达式,使用eval来执行这组表达式,并打印出来。
06_eval.js 06_eval.html
encodeURI 对URI进行编码
decodeURI 对已编码的URI进行解码
3.对象
对象就是一组属性和方法(功能)的集合。
一个员工:编号,姓名,性别,生日,工资,部门
哪些是对象?
某个人的手机: 属性有品牌、颜色、内存、CPU,功能有看视频,听音乐,玩游戏...
某一个饭盒: 属性有大小、颜色、品牌,方法盛饭、摔...
——万物皆对象
(1)JS中的对象
内置对象:JS提供的
宿主对象:根据JS不同的执行环境来划分
自定义对象:自己创建的对象
(2)自定义对象
对象字面(直接)量
内置构造函数
自定义构造函数
(3)对象字面量
使用大括号{} 创建空对象
属性名和属性值之间用冒号隔开
多组属性之间用逗号隔开
属性名引号可加可不加,如果含有特殊字符,必须加
练习:创建一个商品对象,包含的属性有编号、标题、价格、上架时间、是否在售。
(4)访问对象的属性
对象.属性名
对象['属性名'] 如果属性名不加引号,会认为是变量
练习:创建手机对象,属性有编号,品牌,尺寸,颜色;修改尺寸和颜色,添加内存属性。
(5)内置构造函数创建对象
new Object() //创建一个空对象
需要单独添加每一个属性
练习:创建一个汽车对象,含有属性型号、品牌、颜色、长度。
(6)检测是否含有属性
对象.属性名 === undefined
true -> 不存在 false->存在
'属性名' in 对象
true -> 存在 false -> 不存在
对象.hasOwnProperty('属性名')
true -> 存在 false -> 不存在
(7)遍历属性
访问对象中的每一个属性
for(var key in 对象){ key 对象中每个属性名 对象[key] 每个属性名对应的属性值 } |
练习:创建对象,包含5组属性,每一组属性是一个价格,使用遍历属性,来获取价格的总和。
(8)对象中的方法
var person={ name:'jerry', say:function(){ //say就是成员方法 this.name // this指代当前的对象 } } person.say();//调用成员方法 |
练习:创建手机对象,属性有品牌,颜色,尺寸;方法打电话,发短信,看视频...
课后任务
(1)复习今天内容,整理思维导图
(2)练习
创建一个圆对象,属性有半径、圆周率;方法有计算圆的面积和周长。
创建一个长方形对象
(3)课后预习数组
Day07
复习
匿名函数 function(){ }
创建函数 var fn=function(a){ return a; }
自调用 (function(){ var n=1; })();
回调函数
function add(num1){ num1() }
add(function(){ .... })
对象
属性和方法的集合
内置、宿主、自定义
var person={};
var animal=new Object();
person['name'] person.age
for(var key in 对象){ 对象[key] }
检测属性是否存在
对象.属性名 === undefined
'属性名' in 对象
对象.hasOwnProperty('属性名')
方法
{ say:function(){ this.name } }
person.say();
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
数组
数组是由多个元素组成的集合,每个元素就是一个数据。
1.创建数组
(1)数组字面量
[ 元素1,元素2,元素3... ]
练习:创建数组,保存若干个成绩
练习:创建数组,保存若干个大学名称
(2)访问数组中的元素
数组[下标]
下标是从0开始,第一个元素下标0,最后一个元素下标是长度减1
练习:创建数组,保存若干个国家名称,单独添加2个,修改其中的元素,打印结果。
(3)使用内置构造函数
new Array(元素1,元素2,元素3...)
new Array(3) 初始化元素个数为3,后期可以添加更多元素
练习:创建数组,保存若干个编程语言的名称
练习:创建数组,初始化长度为5,保存篮球场上五个位置。
2.获取数组长度
数组.length 可以获取到数组中元素个数
在数组的末尾添加元素
数组[ 数组.length ] = 值
3.数组的分类
数组分为索引数组和关联数组
索引数组:以数字作为下标
关联数组:以字符串作为下标,只能先创建数组,然后单独添加元素。
练习:创建数组,添加员工的编号、姓名、性别、工资、生日,下标使用字符串。
4.遍历数组
(1)for-in
for(var key in 数组){ key 要遍历的数组元素的下标(数字也可以是字符串) 数组[key] 获取下标对应的元素 } |
练习:创建数组,包含多个分数,使用for-in遍历该数组,获取总成绩。
(2)循环
for(var i=0;i<数组.length;i++){ i代表下标 数组[i] 代表下标对应的元素 } |
循环只能遍历索引数组,无法遍历关联数组。
练习:创建函数,传递一个参数(数组),返回平均工资。
练习:创建数组,包含多个汽车品牌,把数组中品牌名称为'宝马'的元素修改为'BMW'
练习:创建函数getCount,传递两个参数(数组、要查找的值),返回任意一个值在数组中出现的次数。
练习:创建函数getIndex,传递两个参数(数组、要查找的值),返回任意一个值在数组中出现位置的下标,如果找不到返回-1.
练习:创建函数getMax,传递一个参数(数组),返回最大值。
5.数组中的方法(API)
API 应用程序编程接口、预定义好的一些方法和函数
toString() 将数组中的元素按照逗号分隔转化成字符串
join('-') 将数组中的元素按照指定的字符分隔转换为字符串,默认是逗号。
concat(arr1,arr2...) 拼接多个数组
slice(start, end) 截取数组中的元素,start开始的下标,end结束的下标,不包含end本身;如果是负数表示倒数。
练习:创建数组,包含a~g,每个字母是一个元素;截取b~c,e~g;拼接成一个新数组。
splice(start,count,value1,value2..) 删除数组中的元素,start开始的下标,count删除的长度,value表示删除后补充的元素。
练习:创建数组,包含a~h,每个字母是一个元素;删除d、e,将f替换m,在下标为2的位置插入元素z。
课后任务
(1)复习今天内容,整理思维导图
(2)练习
使用数组遍历翻转数组中的元素
a~h h~a
使用冒泡排序将一组数字进行从小到大的排序
数组遍历
(3)预习字符串对象及相关API
Day08
复习
数组
创建数组
数组字面量 [元素1,元素2...]
内置构造函数 new Array(元素1,元素2...)
数组访问 数组[下标]
数组的长度 数组.length 数组[数组长度]
数组分类 索引数组 关联数组
遍历数组 for(var key in 数组){ 数组[key] }
for(var i=0;i<数组.length;i++){ 数组[i] }
数组API toString/join/concat/slice/splice
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1.数组API
reverse() 翻转数组中的元素
sort() 对数组中的元素排序,默认是按照Unicode码从小到大
对数字排序 sort(function(a,b){ return a-b;//从小到大 //return b-a; //从大到小 }) |
push() 在数组的末尾添加元素,返回添加后的长度,原数组会发生变化
pop() 删除数组末尾的一个元素,返回删除后的元素,原数组会发生变化
unshift() 在数组的开头添加元素
shift() 在数组的开头删除一个元素
2.二维数组
数组中的每个元素也是数组
var arr=[ [], [], []... ] |
访问二维数组中的元素 arr[下标][下标]
3.字符串操作
包装对象: 目的是让原始类型数据可以向引用类型数据,具有一组属性和方法。
JS中提供了三种包装对象: String、Number、Boolean
将任意类型转为字符串
new String(数据) 强制转为字符串,返回对象
String(数据) 强制转为字符串,返回字符串
注意事项: 包装对象和普通的字符串用法没有区别。
(1)转义字符 —— \
转换字符本身的意义
\n 将普通字符n转义成换行符
\' 将有特殊意义的引号转换成普通字符
\t 将普通字符t转义成制表符(tab键效果)
...
练习:打印出现 welcome to chi\na
(2)字符串API
toUpperCase() 将英文字母转为大写
toLowerCase() 将英文字母转为小写
练习:初始化4个英文字母(有大小写)保存到变量中,循环弹出提示框,输入4个字符(不区分大小写),如果输入正确结束循环。 06_exercise.html 06_exercise.js
length 获取字符串的长度
charAt() 获取下标对应的字符 字符串[下标]
charCodeAt() 获取某个字符的Unicode码
练习:遍历字符串'javascript',获取a字符出现的次数。
indexOf(value,start) 查看某个字符的下标,value要查找的字符串,start开始查找的下标,找不到返回-1
lastIndexOf(value) 查看某个字符最后一次出现的下标
练习:声明变量保存邮箱,检测是否为邮箱格式,如果是打印true,否则打印false。判断字符串中是否含有@
slice(start, end) 截取字符串,start开始的下标,end结束的下标,不包含end本身;如果end为空截取到最后。
substr(start, count) 截取字符串,start开始的下标,count截取的长度,如果count为空截取到最后。
练习:使用变量保存身份证号,截取其中的出生年,月,日,性别。 打印 1997年10月26日 性别男
练习:使用变量保存邮箱,分别截取邮箱的用户名和域名
练习:将一个英文单词的首字母转大写,其它转小写
welCome -> Welcome
split() 按照指定的字符将字符串分隔为数组
练习:使用split获取邮箱中的用户名和域名(jerry@126.com)
4.匹配模式
作用:用于查找、替换字符串
tom tum toom tem 正则表达式
replace(value1,value2) 查找并替换,value1是要查找的字符串,value2是要替换的字符串;value1可以使用正则表达式的写法 /china/ig
i -> ignore 忽略大小写
g->global 全局查找
match(value) 用于查找匹配的字符串,返回数组
search(value) 用于查找匹配的字符串,返回满足条件的第一个的下标,如果找不到返回-1;可以使用i,不能使用g
5.Math对象
Math对象不需要使用new创建,可以直接使用
PI 获取圆周率
abs() 获取绝对值
floor() 向下取整
ceil() 向上取整
round() 四舍五入取整
max() 获取一组数字的最大值
min() 获取一组数字的最小值
pow(x,y) 获取x的y次幂
random() 获取随机数 >=0 <1
Day09
复习
push/pop/unshift/shift/reverse/sort
字符串
包装对象
String Number Boolean
new String()/String()
var a='hello'
var person={}
var arr=[];
转义字符 \
toUpperCase()/toLowerCase()/charAt()/
indexOf()/lastIndexOf()/slice()/substr()/split()/join()
匹配模式
replace()/match()/search()
Math对象
PI/abs()/floor()/ceil()/round()/max()/min()/
pow()/random()
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1~33 随机取6个数,不能重复 红球
1~16 随机取1个数,和前边的没关系 篮球
1.Date对象
用于对日期时间进行存储和计算
new Date('2019/3/14 9:47:30')
new Date(2019,2,14,9,47,30); //第二个参数月份范围0~11
new Date() 存储当前的系统时间
new Date(1000*60*60*24) 存储的是距离计算机元年的毫秒数所对应的日期时间
(2)获取Date对象中日期时间
getFullYear/getMonth(范围0~11)/getDate/getHours
getMinutes/getSeconds/getMilliseconds/
getDay(星期 0~6)/getTime(距离计算机元年毫秒数)
练习:创建对象保存'2019-10-1 10:30:50',打印
2019年10月01日 10点30分50秒 星期二
(3)转为本地字符串格式
toLocaleString() // 年-月-日 时:分:秒
toLocaleDateString() //年-月-日
toLocaleTimeString() //时:分:秒
(4)设置日期时间
setFullYear/setMonth/setDate/setHours/setMinutes
setSeconds/setMilliseconds/setTime
setTime设置后,可能会影响到其它的日期时间
(5)复制Date对象
把已经创建的Date对象以参数形式传递给构造函数
var d1=new Date();
var d2=new Date(d1); //复制d1对象
练习:创建Date对象,保存员工的入职时间'2019-3-15';3年后合同到期,计算到期时间;合同到期前一个月续签合同,假如是周末,提前到周五,计算续签时间;提前一周通知人准备续签,计算提醒时间;
2.Number对象
new Number(值) 将数据转为数值型,返回对象
Number(值) 将数据转为数值,返回数值
toFixed(n) 保留小数点后n位
toString(n) 将数值转为字符串,n表示进制,默认是10
3.Boolean对象
new Boolean(值) 将数据转为布尔型,返回对象
Boolean(值) 将数据转为布尔型,返回布尔型
!!值 隐式将数据转为布尔型
toString() 将布尔型数据转为字符串
4.错误处理
SyntaxError: 语法错误,错误的使用中文,缺少括号等;出现后所有的代码都不执行。
ReferenceError: 引用错误,使用了未声明的变量,属于运行时的错误,影响后边代码的执行。
TypeError: 类型错误,错误的使用了数据,例如变量当做函数来用;属于运行时的错误,影响后边代码的执行。
RangeError: 范围错误,参数的使用超出了范围;属于运行时的错误,影响后边代码的执行
try{ 尝试执行的代码,可能出现错误 }catch(err){ err: 捕获到错误 具体处理错误的内容 } |
练习:初始化一个变量add,尝试调用add函数,传递两个数字参数;如果执行错误,给add赋值一个匿名函数,然后再调用add。
5.ES6新特性
ECMAScript 6
ECMAScript 2015 2016 2017
《ES6入门》
http://es6.ruanyifeng.com/
(1)块级作用域
使用let关键字声明变量,只能在块级作用域下使用,不能被外部访问,不存在变量提升。
块级作用域:{ } for、while、do-while、if...
(2)箭头函数 =>
是回调函数的另一种写法,和匿名函数不完全一样。
sort( (a,b)=>{ return a-b; } ) |
如果箭头函数的函数体中只有一行代码,并且是return形式的,可以简化为 sort( (a,b)=>a-b )
练习:创建函数add,传递两个参数,每个参数都是回调函数,在回调函数中返回一个数字;在函数add中计算两个数字相加的和。
课后任务
(1)复习今天内容,整理思维导图
(2)练习
计算2019-5-1 9:30:00 距离 2019-12-25日相差的天,小时,分钟,秒钟。
(3)复习服务器,预习nodejs中的模块概念
Nodejs
day01
学习一门编程语言的基本步骤
(1)了解背景知识:历史、现状、特点、应用场景。
(2)搭建开发环境,编写hello world
(3)常量和变量
(4)数据类型
(5)运算符
(6)逻辑结构
(7)通用小程序
(8)函数和对象
(9)第三方框架、库
(10)实用的项目
1.ES6
(1)函数参数的默认值
ES6允许为形参设置默认值,如果没有传递实参,自动使用形参的默认值。
练习:创建函数getSex,传递一个参数(0或者1),根据值打印对应的性别;如果参数为空,默认为0.
(2)模板字符串
` 在此之间就是模板字符串 ${JS表达式} ` |
练习:创建一个图书的对象,包含编号,标题,价格,作者,是否在售(1/0);使用模板字符串打印这些内容
2.nodejs概述
(1)对比JS和nodejs
JS运行在浏览器端,有很多浏览器,代码存在兼容性;nodejs在服务器端只有一个环境,代码不存在兼容性。
两者都有内置对象、宿主对象、自定义对象;JS中宿主对象BOM&DOM,nodejs有大量的扩展对象。
JS用于浏览器端的交互效果,nodejs用于服务器端的操作,例如数据库的操作,文件的操作...
(2)nodejs运行模式
脚本模式
node c:/xampp/.../01.js 回车
交互模式
node 回车 进入交互模式
退出: ctrl+c两次 .exit 回车
3.全局对象
nodejs: global
在交互模式下,声明的变量和创建的函数都属于是全局对象下的,可以使用global来访问;
例如:var a=1; 可以global.a访问
脚本模式下,文件中的变量和函数都不是全局对象下的,不能使用global来访问
JS: window
在浏览器下,文件中的变量和函数都是全局对象的,可以使用window来访问; 例如 var a=1; window.a
(1)console对象
global.console.log() 打印日志
global.console.info() 打印消息
global.console.warn() 打印警告
global.console.error() 打印错误
global.console.time('字符串') 开始计时
global.console.timeEnd('字符串') 结束计时
开始和结束的字符串要保持一致
练习:使用计时查看计算for、while、do-while循环100000次的耗时。
(2)process对象
process.arch 查看当前CPU架构
process.platform 查看当前的操作系统
process.env 查看当前计算机的环境变量
process.version 查看当前nodejs的版本号
process.pid 查看当前的进程编号
process.kill() 通过进程编号杀死某一个进程
(3)Buffer对象
缓冲区:在内存中存储数据的区域
创建buffer
var buf=Buffer.alloc(5, 'abcde')
将buffer数据转为字符串
buf.toString()
(4)全局函数
parseInt/parseFloat/isNaN/isFinite/encodeURI/
decodeURI/eval
一次性定时器
var timer=setTimeout( 回调函数, 间隔的时间 ) 当间隔的时间到了,会执行回调函数;单位是毫秒 clearTimeout(timer) 清除一次性定时器 |
周期性定时器
var timer=setInterval( 回调函数, 间隔的时间 ) 每隔一段时间,执行一次回调函数 clearInterval(timer) 清除周期性定时器 |
练习:使用周期性定时器每隔三秒钟打印'hello',打印三次后,清除定时器。
立即执行
var timer=setImmediate( 回调函数 ) clearImmediate(timer) |
process.nextTick( 回调函数 ) |
3.模块
模块就是一个独立的功能体,每一个文件、目录都可以称为一个模块。
在nodejs下模块分为自定义模块、核心模块(官方提供)、第三方模块
nodejs自动会给每一个模块添加构造函数
(function(exports,require,module,__filename,__dirname){ //程序员写的代码 }) |
require() 是一个函数,用于引入一个模块 module 指代当前的模块 module.exports 是当前模块导出的对象,是供其它的模块使用的属性和方法(公开的内容) exports 等价于 module.exports |
课后任务
(1)复习今天内容,整理思维导图
(2)练习
创建两个模块,主模块(main.js)和功能模块(circle.js);在功能模块中创建两个函数,分别传递1个参数(半径),计算圆的周长和面积,导出这两个函数; 在主模块中引入功能模块,并调用两个函数。
(3)预习querystring,url,fs模块
day02
全局对象
nodejs: global js: window
function fn(){ }
console.log/info/warn/error/time/timeEnd
process.arch/platform/env/version/pid/kill()
Buffer.alloc(5,'abcde') toString()
setTimeout/clearTimeout
setInterval/clearInterval
setImmediate/clearImmediate
process.nextTick
模块系统
(function(exports,require,module,__filename,__dirname){
//写的代码
module.exports === exports
})
1.模块中的参数
__filename 当前模块的完整路径和模块名称
__dirname 当前模块的完整路径
2.模块
以路径开头 |
不以路径开头 |
|
文件模块 |
require('./circle.js') 常用于用户自定义模块,如果后缀名为js,可以省略 |
require('querystring') 常用于引入官方提供的核心模块 |
目录模块 |
require('./02_2') 到02_2目录下寻找package.json文件中main属性对应的模块,如果找不到引入index.js |
require('04_2') 会自动到node_modules中寻找目录模块04_2,如果当前目录下没有,会继续往上一级目录寻找,直到顶层目录;常用于第三方模块 |
练习:创建模块03_1.js,引入当前目录下03_2目录模块;在03_2下含有文件fun.js,导出一个函数add(计算两个数字相加),在03_1.js中引入并调用。
练习:在05目录下创建05_1.js,引入不以路径开头的目录模块05_2,包含文件focus.js,在文件中导出函数计算三个数字相加,在05_1.js中引入并调用。
3.包和npm
包: package,就是node_modules下的目录模块,其中含有package.json文件,是包说明文件。
npm: 用于下载安装包的工具
下载的网站:www.npmjs.com
切换到安装的目录
cd 完整的路径
进入要安装的目录,在空白区域按住shift键,单击鼠标右键,在此处打开powershell窗口
使用npm安装
npm install 包的名称
4.查询字符串模块
查询字符串:浏览器向服务器发请求,传递数据的一种方式。
http://www.jd.com/search?ky=电脑&lid=20
parse() 将查询字符串格式化为对象
stringify() 将对象转换成查询字符串
练习:获取百度搜索中查询字符串中的关键字 手机
ie=utf-8&tn=baidu&wd=手机
5.URL模块
操作URL
parse() 将URL格式化为对象
protocol 协议
hostname 主机名(域名/IP地址)
port 端口
pathname 请求的文件在服务器上的路径
query 查询字符串
format() 将对象转换成URL
练习:获取URL中查询字符串中的数据。
http://www.codeboy.com:8080/web/1902.html?sid=10&name=tom
将URL格式化为对象,获取查询字符串
将查询字符串格式化为对象,获取到数据
08_exercise.js
6.文件系统模块
(1)查看文件的状态
fs.stat( fd, callback )/fs.statSync( fd )
fd 文件的路径
callback 回调函数,用来查看结果
err 可能产生的错误信息
stats 具体的文件状态
isDirectory() 是否为目录
isFile() 是否为文件
对比同步和异步操作
同步: 会阻止后边代码的执行,只有执行完毕才会执行后边代码;是通过返回值获取结果。
异步:不会阻止后边代码的执行,放在整个线程的最后执行;是通过回调函数获取结果。
(2)创建目录
fs.mkdir( fd, callback )/fs.mkdirSync( fd )
(3)移除目录
fs.rmdir( fd, callback )/fs.rmdirSync( fd )
(4)读取目录
fs.readdir(fd, callback)/fs.readdirSync(fd)
callback 回调函数
err 可能产生的错误
files 读取的目录中的文件
练习:读取目录05中的文件有哪些
(5)写入(创建)文件
fs.writeFile(fd, data, callback)/fs.writeFileSync(fd,data)
fd 文件的路径
data 要写入的数据
callback 回调函数
如果文件不存在创建文件,如果文件已经存在,会清空文件中的内容,然后写入。
(6)追加写入(创建)
fs.appendFile(fd, data, callback)/
fs.appendFileSync(fd, data)
练习:在文件num1.txt中写入'hello',运行多次。
课后任务
(1)复习今天内容,整理思维导图
(2)练习:
创建目录mydir,在该目录下创建文件data.txt,并写入以下数据,每个对象中的数据占一行。
[{id:1, name:'tom', age:18}, {id:2,name:'kate',age:20} ]
(3)预习http协议,nodejs的http模块
day03
以路径开头 |
不以路径开头 |
|
文件模块 |
require('./circle.js') |
require('fs') |
目录模块 |
require('./04_2'); package.json中的main属性 |
require('mysql') 到node_modules中寻找目录模块mysql |
包和npm
npm install 包名称
querystring parse/stringify
url parse/format
fs stat/statSync/mkdir/rmdir/readdir/writeFile/
appendFile
同步和异步
1.fs模块
(1)判断文件是否存在
fs.existsSync(path) 判断文件是否存在
存在 true 不存在 false
(2)读取文件
fs.readFile(fd, callback)/fs.readFileSync(fd)
fd 文件的路径
callback 回调函数
err 可能产生的错误
data 读取的数据,格式为buffer形式
(3)删除文件
fs.unlink(fd, callback)/fs.unlinkSync(fd)
练习:完成一个文件计数器。
判断文件num.txt是否存在,不存在创建,并写入数据0;
读取num.txt中的数据,然后让读取的值加1,并打印
把加1后的值再次清空写入到num.txt中
全程使用同步方法 03_num.js
2.http协议
是浏览器和web服务器之间的通信协议
(1)通用头信息
Request URL: 请求的URL,对应浏览器地址栏内容,要向服务器获取哪些内容
Request Method: 请求的方法, GET/POST...,获取内容的方式
Status Code: 响应的状态码
1**: 正在请求,没有结束
2**: 成功的响应
3**: 响应的重定向,跳转到另一个网址;通常结合着响应头信息中location一起使用
4**: 客户端错误
5**: 服务器端错误
Remote Address: 请求的服务器的IP地址和端口号
(2)响应头信息
Connection: 连接的方式, keep-alive持续连接
Content-Type: 响应的文件类型
Content-Length: 响应的文件长度
Location: 当响应重定向的时候,跳转的URL
(3)请求头信息
Accept: 客户端接收的文件类型有哪些
Accept-Encoding: 客户端接收的文件压缩形式
User-Agent: 客户端发送请求使用的浏览器
(4)请求主体
可有可无,客户端向服务器端传递数据
3.http模块
既可以模拟浏览器向服务器端发请求,也可以创建web服务器
(1)模拟浏览器
http.get( url, callback )
get 请求的方法
callback 回调函数,用来获取服务器端的响应
res 响应的对象
statusCode 获取响应的状态码
res.on('data', function(buf){ })
通过事件来获取响应的内容,当有数据传递自动触发
通过回调函数来接收响应的内容
buf就是响应的内容,格式为buffer
练习:使用http模块下的get方法向tmooc发请求,并获取响应的状态和响应的内容 05_exercise.js
http://www.tmooc.cn/course/100072.shtml
(2)创建web服务器
var server=http.createServer() 创建web服务器
server.listen(8080) 分配8080端口,监听端口变化
server.on('request', function(req,res){ })
接收浏览器的请求,是一个事件,当有请求自动触发
通过回调函数来接收请求,做出响应
req 请求的对象
url 请求的URL,显示端口后的部分
method 请求的方法
headers 请求的头信息
res 响应的对象
writeHead(code, obj) 设置响应的状态码和头信息
code 状态码 obj 头信息对象
write() 设置响应的内容
end() 结束响应,并发送响应内容到浏览器
练习:创建web服务器,监听端口8081,接收浏览器的请求
/login 响应内容 this is login page
/member 响应内容 <h2>welcome</h2>
/ 重定向到 /login
以上都没有 响应内容 404 not found
07_http_server.js
4.express框架
基于nodejs,快速、开放、极简的web开发框架
www.expressjs.com.cn
安装 npm install express
(1)路由
浏览器向web服务器发请求,web服务器根据请求的方法和请求的URL来做出响应。
三要素:请求的方法、请求的URL、响应(回调函数)
课后任务
(1)复习今天内容,整理思维导图
(2)练习
使用http模块创建web服务器,接收浏览器的请求,根据请求的URL来做出不同的响应
/index 响应内容 this is homepage
/login 响应内容 <h2>please login</h2>
/ 重定向 /index
其它 响应 404 not found
(3) 预习浏览器向服务器发送请求的方式get/post
预习express中间件
day04
http协议
通用头信息
请求方法、请求URL、响应的状态码
响应头信息
Content-Type: text/html text/plain
Location: http://www.codeboy.com /index
请求头信息
请求主体
http模块
向服务器发请求
http.get(url, function(res){ res.statusCode
res.on('data', function(buf){ });
});
创建web服务器
http.createServer()
listen(8080)
express框架
express()
listen(8080)
路由
1.express框架
(1)路由
req对象
method 请求的方法
url 请求的URL
headers 请求的头信息
query 获取查询字符串数据,格式化为对象
res对象
send() 响应内容并发送,不能多次使用,如果是数字需要转成字符串
sendStatus() 响应状态码对应的中文 200->ok
sendFile() 响应文件并发送
redirect() 响应的重定向
练习:创建路由并响应
get /index 响应<h1>这是首页</h1>
get /member 响应文件member.html
get / 响应重定向到 /index
post /register 响应 注册成功
2.post和get请求
post请求是通过表单提交(现阶段)来传递数据,服务器端是通过事件来获取数据,后期可以使用中间件简化。
req.on('data', function(buf){ buf就是获取的数据,格式为buffer,需要使用查询字符串模块格式化为对象 }) |
get请求通过查询字符串传递数据,服务器端使用req.query获取数据,结果是对象。
post请求安全性较高,速度较慢,注册、登录使用post提交。get请求安全性较低,速度较快,搜索中使用get提交。
练习:创建路由,请求方法get,请求的URL: /reg,响应一个文件 reg.html; 在html创建注册的页面(用户名、密码、手机),点击提交,向服务器发送get请求,请求URL: /myreg,响应'注册成功'。
3.使用路由传递数据
设置路由中接收的名称
server.get('/detail/:lid', function(req,res){ req.params //获取路由传递的数据,格式为对象 }); |
浏览器传递数据
http://127.0.0.1:8080/detail/5
5就是传递的数据,被lid所接收
练习:创建购物车的路由,请求方法:get,请求URL: /shopping,传递商品的价格(price)和名称(pname),把接收的两项响应到浏览器中。
商品模块 /list /delete /update
用户模块 /list /delete /update
4.路由器
路由在使用过程中,不同模块下的路由可能出现相同的URL,把同一个模块下的路由挂载到特定的前缀,例如: 商品模块下列表路由 /product/list,用户模块下的列表路由 /user/list
路由器就是自定义的模块,存放了所有模块下的路由
const express=require('express'); var router=express.Router(); //创建空的路由器对象 router.get('/list', function(req,res){ });//往路由器添加路由 module.exports=router; |
web服务器下使用路由器
const userRouter=require('./user.js');//引入路由器模块 server.use('/user',userRouter);//把路由器挂载到/user下,访问形式 /user/list |
练习:创建商品模块路由器(product.js),添加路由商品列表、商品删除,在web服务器下引入,并挂载到/product。
5.中间件
中间件作用为主要业务逻辑所服务器
分为应用级中间件,路由级中间件,内置中间件,第三方中间件,错误处理中间件。
(1)应用级中间件
每一个中间件都是一个函数,需要配合其它的中间件或者路由使用。
server.use( function(req,res,next){ } ) 拦截所有请求
server.use('/reg', function(req,res,next){ })
拦截特定的请求,当请求的URL为/reg,才会执行回调函数。
练习:创建路由(请求方法:get,请求URL:/view)响应当前的浏览次数,每次浏览,响应次数加1.
在中间件外部创建变量,设置初始值0,中间件中变量加1,在路由中响应浏览次数(变量) send(0)
(2)路由级中间件
将路由器挂载到特定前缀,就是使用路由级中间件
server.use('/user', userRouter);
(3)内置中间件
在express中只有一个内置的中间件
课后任务
(1)复习今天内容,复习mysql的SQL语句
(2)练习
创建web服务器,向服务器请求查询生日文件(birth.html),在html中点击提交再次向服务器发请求,根据身份证号显示出生的年月日和性别(中间件);在路由中响应到浏览器
day05
1.内置中间件
express中只保留了一个内置的中间件
server.use( express.static( '目录' ) );
托管静态资源到某个目录,如果浏览器请求静态资源,自动到该目录下寻找,无需使用路由响应文件。
静态资源:html、css、客户端js、img...
练习:再次托管静态资源到files目录下,如果同时出现两个相同名称的文件,显示哪一个目录下的。
2.第三方中间件body-parser
可以将post请求的数据直接格式化为对象
//引入body-parser server.use( bodyParser.urlencoded({ extended:false }) ); urlencoded: 将post请求数据格式为对象 extended:不使用第三方qs模块,而使用核心模块querystring将查询字符串格式化为对象 |
在路由中获取post请求数据
req.body 返回对象
3.mysql模块
连接mysql数据库服务器
mysql.exe -h127.0.0.1 -P3306 -uroot -p
进入数据库 use xz;
INSERT INTO emp VALUES(....);
DELETE FROM emp WHERE uid=3;
UPDATE emp SET ename='tom',sex=0 WHERE eid=1;
SELECT eid,ename FROM emp;
(1)普通连接
var connection=mysql.createConnection( {} );创建连接对象,提供mysql服务器的主机名,端口号,用户名,密码,连接后要使用的数据库
connection.connect(); 执行连接
connection.query( sql, function(err, result){ } )
sql要执行的SQL语句,result,SQL语句的执行结果
connection.end() 关闭连接
(2)使用连接池
var pool=mysql.createPool({ }); 创建连接池对象,传递主机名,端口号,用户名,密码,使用的数据库,连接池大小
pool.query( sql,callback )
在SQL语句中可以使用占位符 ?
练习:创建web服务器,托管静态资源到public下,创建add.html(包含部门编号,部门名称)。06_add.js
点击表单中的提交按钮,向服务器发送请求,请求方法:post,请求URL:/add,创建对应的路由获取提交的数据。
将服务器接收的数据插入到tedu数据库下dept表中,
课后任务
(1)复习今天内容,整理思维导图
(2)创建web服务器,托管静态资源,点击提交,将数据插入到tedu数据库下的emp表中
day06
复习
步骤:
(1) web服务器 (app.js)
托管静态资源到public
使用body-parser中间件
使用路由器,挂载到指定的位置 例如挂载到 /user
(2)路由器( routes )
引入连接池模块
创建路由器对象
往路由器添加路由
在路由中使用连接池
导出路由器
(3)连接池模块(pool.js)
创建连接池对象
导出连接池对象
SELECT * FROM xz_user LIMIT start,count;
count: 每页的数据量
start: 开始查询的值
数据量10、页码
start=(页码-1)*数据量
1 0
2 10
创建商品模块路由器 product.js,
创建空的路由器对象
添加路由
导出路由器
把路由器导入到服务器下,挂载到/product下
阶段2: HTML、AJAX、CSS、BOOT
HTML
day01 HTML
李然 QQ:1535212067
一.课程安排,(20天)
1.HTML5 Basic(2天)
搭建网页结构
2.Ajax异步数据交换(3天)
异步完成前后端数据的交互
3.项目1(2天)
4.CSS样式表(4+2天),让页面变得好看
美化HTML
5.Bootstrap框架(4天)
简化css开发,
支持响应式开发
6.项目(2天)
总结:20天课程遇到问题
1.知识点细碎,没有条理 2.知识点量极大,单词量极大 |
二.web基础知识
HTML5:大前端技术 是html4.01升级版 XHTML1.0的升级版 1999年12月发布 2000年1月发布 语法松散 语法严谨 <input> <input/> |
1.web与internet
internet:全球性计算机互联网 俗称:互联网,因特网 web就是运行在internet上的一种应用程序 internet上的服务
|
2.internet上的应用程序,结构分类
1.C/S C:client 客户端 S:server 服务器 代表:QQ,LOL...... |
2.B/S B:Browser 浏览器 S:server服务器 |
C/S和B/S的区别 1.cs是需要升级 2.bs不需要升级 |
3.web运行原理
web:运行在internet上的一种B/S结构的应用程序 俗称网站 internet:为web运行提供了网络环境 web的工作原理: 基于浏览器和服务器以及通信协议来实现的数据传输和展示 通信协议:规范了数据是如何打包和传递 |
服务器 1.功能 存储数据 接收用户请求并给出响应 提供了程序的运行环境 具备一定的安全功能 2.服务器产品 Apache/Tomcat/IIS 3.服务器端技术 java/PHP/python/nodejs/C# |
浏览器 1.功能 代表用户发送请求 作为html.css.js的解析器,以图形化的界面展示给用户看 2.浏览器的产品 chrome safari Firefox oprea IE 3.浏览器技术 HTML5 CSS3 JS |
三.HTML入门
1.HTML是什么
HyperText Markup Language 超文本标记语言 标记:超文本的组成形式,具有自己独特的功能 语法:<关键字></关键字> |
2.HTML的特点
1.以.html或者.htm为后缀 2.由浏览器解析执行 3.使用带有<>的标记来标识 4.页面中可以执行js脚本 |
3.HTML基本语法学习
1.标记
又称,标签,元素,节点 语法<关键字></关键字> 每个标签都有自己的功能 我们要学习关键字和对应的功能 |
2.标记的分类
1.双标记(封闭类型标记) <关键字>....</关键字> ex:<a></a> <div></div> 2.单标记(非封闭类型标记),空标签 <关键字>或者<关键字/> <input>或者<input/> |
练习
新建文档01_ex.html 在文档中 写一对html标签 写一对head标签 写一对body标签 |
3.标签的嵌套
在一对标签中出现其他标签,形成功能嵌套关系 嵌套关系,必须子元素有缩进 注意嵌套层级不要混乱 推荐的写法
不推荐的的写法
错误的写法
|
4.属性
双标签 <a href="http://www.tmooc.cn/"></a> <关键字 属性1="值1" 属性2="值2" ...></关键字> 单标签 <input type="submit" value="登录"/> <关键字 属性1="值1" 属性2="值2" .../> 属性是对该标签的修饰 |
练习
在01_ex中添加b标签,内容随意 b标签拥有属性align="center" title="1111" 观察效果,提示:有一个属性不生效 |
4.1属性分类
1.通用属性,所有元素都有的属性 id:定义元素在页面中唯一的标识符 title:鼠标悬停在元素上所提示的文本 style:css中第一内联样式的属性 class:css中,引用类选择器的属性 2.专有属性,某个元素自带的属性,其它元素此属性不生效 |
总结
学习html,究竟怎么学? 记忆<关键字>,记忆超文本标签的特殊能力 记忆专有属性,记忆嵌套关系 |
5.html的注释
不被浏览器解析的文字 <!-- 这里是注释文字 --> |
四.HTML的文档结构
<!doctype html> <html> <head></head> <body></body> </html> |
1.文档类型声明<!doctype html> 告诉运行解析我的浏览器,如果你想正确的运行解析我这篇HTML文档,请使用h5的规则解析我 |
2.网页结构 <html> <head></head> <body></body> </html> 语法:<html></html> 标识网页的开头和结束 注意,一个.html文件中,有且只有一组html标签 <head></head>网页的头部,定义全局的信息 <body></body>网页的主体,展示的内容 |
练习
02_ex.html.完成最基本的网页结构 |
|
<head></head>中的元素
<body></body> 定义网页主体 body的属性 text="red"指定网页的字体颜色 bgcolor="yellow" 指定网页的背景颜色 15:18上课 |
关于editeplus快捷键
ctrl+b 快速在指定的浏览器中打开页面 ctrl+s 保存 定义快捷键 ctrl+d 删除当前行 ctrl+z 回退一步 ctrl+y 前进一步 alt+↑/↓ 移动当前行位置 ctrl+alt+↓ 复制当前行 |
五.文本标记
1.标题元素
<h1></h1>~~~<h6></h6> 在页面中以醒目的方式显示文本 特点:1.字体大小有变化 h1最大,h6最小 2.字体加粗 3.独占一行,上下有垂直间距 属性 align 设置标记内容水平对齐方式 取值:left/center/right |
2.段落标记
<p></p> 以突出的形式表现一段文字 特点:1.独占一行 2.文本上下有垂直间距 属性 align |
练习
03_ex.html中,模拟一份个人简历 |
3.换行标记
<br>或者<br/> |
4.水平分割线
<hr>或者<hr/> 属性 size="5px" 分割线粗细 以px为单位的数字 width="50%" 分割线宽度以px为单位的数字 % align="left" 分割线水平对齐 left/center/right color="orange" 分割线颜色 合法颜色值 |
5. 预格式化标签
保存了在编写代码时的回车和空格效果 在浏览器中解析显示 <pre></pre> |
6.特殊字符(实体)
html会出现空格折叠现象 把所有的空格都解析成一个空格 把所有的回车都解析成一个空格 <br> 空格 < < > > © © ® ® × × 人民币 & |
练习
Copyright © 2000-2019 <北京达内版权所有> |
7.文本样式标签
<i></i> <em></em> 斜体 <b> </b> <strong> </strong> 加粗 <s></s> <del></del> 删除线 语义 <u></u> 下划线 <sup></sup>上标 <sub></sub>下标 |
8.分区元素,如果不写样式,页面中是看不到的
1.块分区<div></div> 用于页面中的布局效果 特点,单独成行 |
2.行分区<span></span> 一行文字如果有多种样式,使用span 特点,与其他span元素共用一行 span中不允许嵌套块级元素 |
9.块级元素和行内元素
1.块级元素 页面上,单独成行的元素,都是块级元素 ex:h1~h6,p,div 块级元素默认排列方式,由上到下排列 |
2.行内元素 页面上,多个元素共用一行 ex:span em i b strong sub sup u s del 行内元素默认排列方式,由左往右排列 |
六.图像和链接
作业
1.熟练完成nodejs接口11个
2.图片可以不写
3.使用div完善个人简历
day02 图像&列表&表格
一.图像和链接
1.图像的使用
<img>或<img/> 属性 src="图片资源路径" <img src="图片资源路径"> |
2.URL
Uniform Resource Locator 统一资源定位符,俗称路径 |
3.url的表现形式
1.绝对路径---使用网络资源的时候使用 完整的路径 通信协议+主机名称+文件目录结构+资源名称 优点:不占用本地存储空间 缺点:不稳定 使用网络资源发展出来的行业---图床 练习:01_ex中再从tmooc中,盗一张图,显示 |
|
2.相对路径---使用本服务器资源的时候使用
|
4.图片的属性
src 设置图片资源路径 source的缩写-数据源 title:鼠标悬停时,显示的文字 alt:图片加载错误时,显示的文字 width:设置图片的宽 height:设置图片的高 注意:如果设置的宽高比,与原始图片宽高比不一致,会出现图片的失真。 解决图片的失真,宽高属性,只写一个,另外一个自适应 |
5.链接
1.语法 <a href></a> 属性 href 链接的路径 target打开页面的方式 取值:_self 默认值,在当前页面中打开新网页 _blank 在新页面打开网页 |
||||
2.a标签其它表现形式
|
6.a标签的锚点操作
1.什么是锚点 锚点,就是页面中的一个记号 可以通过超链接的方式链接到记号位置处 2.锚点的使用
练习
|
二.表格
1.表格语法
<table></table> 行 <tr></tr> table row 列 <td></td> table data <table> <tr> <td>数据内容</td> </tr> </table> 编写4行4列的表格,内容随意 |
2.属性
table标签的属性 border:设置表格的边框 width="200px" 设置表格宽 height="200px" 设置表格高 align="center" 设置表格水平对齐方式 bgcolor="pink" 设置表格背景颜色 bordercolor="red" 设置表格边框颜色 cellpadding="10px" 设置表格内边距 边框到内容的距离(以左和上为准) cellspacing="10px" 设置表格的外边距 边框到边框的距离 |
练习
04_ex.html 设置表格尺寸400px*400px,4*4的表格 表格背景pink 边框1px,边框颜色yellow 表格水平居中 表格内边距5px 外边距10px |
tr的属性 align left/center/right 设置当前行内容的水平对齐方式 valign top/middle/bottom 设置当前行内容垂直对齐方式 bgcolor="yellow" 设置当前行的背景颜色 |
td的属性 width="70px" 设置当前单元格宽度,宽度过大会影响当前列 height="70px" 设置当前单元格的高度,高度过大,会影响当前行 align="right" 设置当前单元格内容的水平对齐方式 valign="top" 设置当前单元格内容的垂直对齐方式 bgcolor="blue" 设置当前单元格的背景颜色 colspan 跨列,列合并 rowspan 跨行,行合并 |
3.不规则的表格
1跨列 colspan="n" 第一步:从指定的单元格的位置处,横向向右合并N个单元格(n包括自己) 第二步:把被合并的单元格删除 |
2跨行 rowspan="n" 第一步:从指定的单元格的位置处,纵向向下合并N个单元格(n包括自己) 第二步:把被合并的单元格删除 |
4.表格可选标记
1.表格的标题 <caption> </caption> 注意,如果设置表格标题,<caption> </caption>必须紧跟<table> |
2.行/列的标题 使用<th></th>替换<td></td> <th></th>:加粗,居中 |
5.复杂表格的应用
1.行分组,默认不可见 可以将几个连续行,划分到一个组中,进行统一管理 表头<thead></thead> 表主体<tbody></tbody> 表脚<tfoot></tfoot> |
2.表格嵌套 被嵌套的表格,只能放在td中 |
练习
三.列表
1.列表的作用
最原始的作用,有条理的显示数据 列表是由列表类型和列表项组成 |
2.有序列表
项目中,有序列表就是显示数据,而且使用几率很小 <ol> order list--ol list item--li <li>打开冰箱门</li> <li>把大象放进冰箱</li> <li>关上冰箱门</li> </ol> 属性type=" " 标识项的类型 1/a/A/i/I start="" 标识项的起始数字 |
3.无序列表
四.结构标签
午间练习,把昨天作业中的图片,添加进去
第二阶段练习效果图示\day01_html_01作业\素材
作业:
1.11个nodejs接口
2.完成课程表
day03 列表表单
一.列表
1.无序列表
1.什么是无序列表
2.ul的属性
|
2.列表的嵌套
1.在li中嵌套其它元素 <ul> <li><img src="../image/06.png"></li> <li><img src="../image/07.png"></li> <li><img src="../image/08.png"></li> </ul> <ol> <li><a href="#">汤圆炒橘子</a></li> <li><a href="#">西红柿炒月饼</a></li> <li><a href="#">姜丝炒土豆丝</a></li> </ol> |
2.在li中嵌套其它列表 列表的嵌套,必须放在li中,不是语法要求,是语义要求 |
3.定义列表(h5新标签)
对一个名词,进行解释说明的时候,使用定义列表 <dl> 定义列表 <dt> </dt> 要解释说明的名词 <dd> </dd> 要解释说明的内容 </dl> |
二.结构标记
1.用于描述整个网页结构,取代div做布局的一套标记
为什么要使用结构标记,而不用div 结构标记的作用根div一模一样 结构标记是有语义,方便阅读 使用有语义的标签,可以让页面在搜索时更靠前 |
2.常用的结构标记
1.<header></header> 定义网页的头部,或者某个区域的顶部 2.<footer></footer> 定义网页的脚部,或者某个区域的底部 3.<nav></nav> 定义网页导航链接 4.<section></section> 定义网页主体内容 5.<aside></aside> 定义网页侧边栏 6.<article></article> 定义与文字相关的内容 比如,论坛,回帖,用户评论.... |
三.表单(重点&难点***********)
1.作用
1.提供可视化的输入控件 2.收集用户输入的信息,并提交请求给服务器 总结,form自带提交请求的功能 ajax提交不需要form支持 |
2.表单的组成
1.前端部分 提供表单控件,与用户交互的可视化控件 2.后端部分 后台接口对提交的数据进行处理 |
3.表单
<form></form> 属性:
|
||||||||||
4.表单控件,在form标签中,能够与用户进行交互的可视化元素
17:07~17:22休息 |
day04 表单控件
一.表单
1.其它元素
1.label元素 关联文本与表单控件 <label for="login_qq">QQ</label> 属性for,绑定要关联的表单控件的id值 效果,点击label文本,被关联的控件也被点中 |
2.为控件分组
<fieldset></fieldset>为控件分组 <legend></legend>分组的标题 |
3.浮动框架
<iframe></iframe> src 要引入的网页路径 width 设置iframe的宽度 height设置iframe的高度 需要js和dom的支撑 frameborder 浮动框架的边框 scrolling 设置滚动条 yes no auto |
4.新表单元素
在html5版本中,新提出来的表单控件
|
二.HTTP协议
1.URL
结构:协议+主机名称+目录结构+文件名称 URL完整的结构 <scheme>://<user>:<pwd>@<host>:<port>/<path>; <params>?<query>#<frag> |
|||
url完整结构详解
|
2.HTTP协议
HTTP HyperText Transfer Protocol 超文本传输协议 规范了数据是如何打包以及传递的(专门用于传输html文件) |
HTTP协议的历史 |
3.web请求原理详解
4.消息/报文Message
1.请求消息Request Message(请求起始行,请求头,请求主体) 2.响应消息Response Message(响应起始行,响应头,响应主体) |
5. Request Message
请求消息,客户端发送给服务器的数据块 由三部分组成:请求起始行,请求头,请求主体 |
||||
1. 请求起始行
2. 请求头
3. 请求主体
|
6. Response Message
响应消息,服务器发送给客户端的数据块 由三部分组成:响应起始行,响应头,响应主体 |
|||
1. 响应起始行
2. 响应头
3. 响应主体,服务器传给浏览器的数据 |
7.缓存
客户端将服务器响应回来的数据进行自动的保存 当再次访问的时候,直接使用保存的数据 |
缓存的优点? 1.减少冗余的数据传输,节省客户端流量 2.节省服务器带宽 3.降低了对服务器资源的消耗和运行的要求 4.降低了由于远距离传输而造成加载延迟 |
缓存的新鲜度和过期 1.请求--无缓存--连接服务器--存缓存--客户端得到 2.请求--有缓存--够新鲜--使用缓存--客户端得到 3.请求--有缓存--不新鲜--连服务器确认是否过期--没过期--更新缓存的新鲜度--客户端得到 4.请求--有缓存--不新鲜--连服务器确认是否过期--已过期--连服务器--存缓存--客户端得到 |
1.与缓存相关的消息头
Cache-Control:max-age=0 从服务器将文档传到客户端之时起, 此文档处于新鲜的秒数,这是一个相对时间 语法:Cache-Control:max-age=处于新鲜的秒数 Cache-Control:0 不缓存 |
2.在网页中添加缓存,需要修改消息头
<meta http-equiv="消息头属性" content="值"> |
8.HTTP性能优化
HTTP的连接过程 发起请求-->建立连接-->服务器处理请求-->访问资源-->构建响应-->发送响应-->记录日志 |
1.HTTP连接性能的优化
1.减少连接创建次数(开启持久连接) 2.减少请求次数 3.提高服务器端运行速度 4.尽可能减少响应数据的长度 |
2.安全的HTTP协议
HTTPS:安全版本的http协议 SSL:为数据通信特供安全支持 1.客户端发送请求--->SSL层加密--->服务器接收加密文件--->在SSL层解密,得到请求明文,对请求做处理 2.服务器发送响应--->SSL层加密--->客户端得到加密文件--->在SSL层解密,得到响应明文,解析响应内容 |
AJAX
day05 ajax
一.DOM(简单dom操作)
ajax提交请求,不需要使用form表单 但是,form表单自带收集数据的功能 不是用form标签,就没有自动收集数据的功能了 我们需要使用js的dom操作,手写代码,收集数据 |
1.使用dom
1.获取元素对象
2.获取/修改元素的值/内容
3.innerHTML详解
4.事件 onclick
|
二.Ajax
1.同步Synchronous
在一个任务进行的过程中,不能开启其他任务 同步访问:浏览器在向服务器发送请求时,浏览器只能等待服务器的相应,不能做其他事 出现场合: 1.地址栏输入url,访问页面(网速不好时,更明显) 2.a标签跳转 3.表单提交 |
2.异步Asynchronous
在一个任务开启时,可以开启其他任务。 异步的访问:浏览器在向服务器发送请求时,用户可以在页面上做其他操作 出现场合 1.用户名重复的验证 2.聊天室 3.百度搜索建议 4.股票走势图 |
1.什么是Ajax
Asynchronous JavaScript and XML 异步的 js 和 xml 本质:使用js提供的异步对象, 异步的向服务器发送请求, 并接收响应回来的数据 异步对象 XMLHttpRequest |
2.使用ajax
1.创建异步对象 2.创建请求 3.发送请求 4.接收响应数据 |
3.创建异步对象
var xhr=new XMLHttpRequest(); 这种创建方式,不兼容ie8以下的版本 |
4.使用异步对象打开连接,创建请求
xhr.open(method,url,isAsyn); method:string类型,请求的方法。比如 "get" ulr:string类型,请求的url.比如 "http://127.0.0.1:8080/login" isAsyn:boolean类型,是否才用异步访问的方式去访问服务器 |
5.发送请求
xhr.send(formdata) 注意:只有post请求的使用,才有请求主体formdata get方法不需要请求主体 所以使用get请求的时候,两种发送请求的写法 xhr.send()或者xhr.send(null) |
跨域问题,一定在xz的服务器中,托管静态资源文件夹中,编写html文件。不然会发生跨域问题。 运行此html文件,要使用访问服务器的方式运行,不要使用ctrl+b或者直接双击。 //1.创建异步对象 var xhr=new XMLHttpRequest(); //2.打开连接,创建请求 xhr.open("get","http://127.0.0.1:8080/demo/ajaxdemo",true); //3.发送请求 xhr.send(null); 15:30~15:45休息 |
6.绑定监听,接收响应
1.readyState属性
2. status属性
3.onreadystatechange 监听事件
4.常见错误
5.使用get提交,发送带参数的请求(dom)
|
作业:
1.使用get方法完成登录模块
2.使用get方法获取商品列表,把响应数据放到div中显示
3.提高题,注册验证,验证新用户名是否可用
模仿学子商城注册页,使用获取焦点和失去焦点事件
day06 ajax
一.Ajax
1.post请求
1.post接口 router.post("/login_post",(req,res)=>{ //获取用户名和密码 var $uname=req.body.uname; var $upwd=req.body.upwd; 2.使用post方法提交请求 注意:由于服务器默认接收普通字符 请求主体有特殊字符 需要在发送之前,设置请求头信息,改为发送所有字符 设置的位置,是在open之后,在send之前 //1.创建 xhr对象 var xhr=new XMLHttpRequest(); //4.绑定监听,接收响应 xhr.onreadystatechange=function(){ if(xhr.readyState==4&&xhr.status==200){ var result=xhr.responseText; alert(result); } } //2.打开连接,创建请求 xhr.open("post","/demo/login_post",true); //3.发送请求 //设置请求消息头,修改接收所有字符 xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); var formdata="uname="+uname.value+"&upwd="+upwd.value; xhr.send(formdata); |
2.作业,查userlist
任务1.重新完成userlist,要用onload事件(接口,页面)
任务2.重新完成post登陆(接口,页面)
3.Json
使用ajax访问服务器,服务器连接数据库,把结果通过相应传送给ajax. 前台ajax内部,xhr.responseText得到这个相应数据 这个相应数据的类型,string string放的是数组结构,每一个元素是什么? 1.js对象的数据格式
2.JSON数据格式
3.把json字符串转换成js对象数组
|
常见错误
原因:本机开启了另外一个mysql数据库 不是你自己xmapp中的mysql 解决方案:需要在任务管理器中把之前的mysql进程清除。然后重新开启xmapp的mysql 任务管理器,在开始按钮上点击右键打开 |
设置请求消息头,的代码,放在了open之前或者send之后 |
4.XML数据格式
XML:eXtensible Markup Language; 可扩展的 标记 语言 xml是html 的一个变种,专门负责承载数据用的 所以操作xml要使用dom xml的标记,是没有被预定义过,需要自定义 xml就是做数据传递,而不是数据展示 1.xml的语法
2.使用ajax访问xml数据
3.xml数据解析,使用dom
|
二.AJAX项目
新建mypro.js 在app.js中导入挂载 新建静态文件夹 mypro 在app.js中托管 所有接口写在mypro.js中 所有的html写在mypro文件夹里 |
1.登陆功能 post方法
作业:
1.完成用户列表页
2.完成注册页面的失去焦点验证,及用户注册
CSS
day08 css
一.CSS概述
1.CSS是什么
cascading style sheets 层叠样式表,级联样式表,简称样式表 |
2.作用
美化html页面 |
3.HTML与CSS的关系
html,负责网页的搭建,内容的展示 css,负责网页的修饰,样式构建 |
4.CSS与HTML的属性,使用原则
w3c建议,尽量使用css的方式取代html的属性 css的优势 1.样式代码可以高度重用 2.样式代码可维护性高 |
二.CSS的语法规范
1.使用css的方式
1.行内样式,内联样式 在元素的style属性中,声明样式(所有元素都有style属性) <any style="样式声明"></any>(any是任何元素的意思) 样式声明:样式属性:样式值;样式属性:样式值; 样式属性和值用:连接 多个样式声明用;连接 内联样式在项目中不用,由于不能重用,默认优先级最高。 只有在学习和测试使用。 |
2.内部样式 在head标签中,写style标签,在style中定义样式规则 <style> p{color:red;background:pink;font-size:36px;} </style> 样式规则: 选择器,就是规定页面中哪些元素可以使用此样式 {样式声明} 内部样式的重用,只能在当前页面内重用。 项目中较少使用,在学习和测试中使用较多 |
3.外部样式 单独创建一个.css文件,在这个文件内写样式 在.html的head标签中,是link引入此样式 <link rel="stylesheet" href="css的url"> 外部样式在项目中应用广泛 |
常用样式属性
color:blue; 字体颜色,取值是合法的颜色 font-size:36px; 字号大小,取值px为单位的数字 background:yellow 背景颜色,取值合法的颜色 |
练习
css3种使用方式 01_ex.html <h1>lorem</h1>内联,背景色为粉色,字体颜色为黄色 <h2>lorem</h2>内部,背景色为黄色,字体颜色为红 <h3>lorem</h3>外部,背景色为红色,字体颜色为蓝色 |
2.CSS的特性
1.继承性 作用在父元素的样式,大部分可以被子元素继承 |
2.层叠性 可以为一个元素定义多个样式规则 样式规则中的属性不冲突时,可以同时应用这个元素上 |
3.样式的优先级 如果样式声明冲突时,按照样式规则的优先级去应用 默认的优先级规则,由高到低: 1.最高,内联样式 2.内部 外部 就近原则 3.最低,浏览器默认样式 |
4.调整优先级 !important规则 放在属性值之后,与值之间使用空格隔开 作用:调整样式优先级,优先级提升 多个样式都有!important,按照就近原则应用 ex: h2{color:red !important;} |
练习
02_ex.html中 一个p标签,内容是假文 用内部样式设置文字颜色为蓝色,字号24px 用外部样式设置文字颜色为红色,字号40px 将外部样式引入,f12查看页面效果 然后内部样式和外部样式引入的位置,f12观察效果 尝试使用!important调整样式优先级 |
三.基础选择器 (重点***)
1.选择器的作用
规范了页面中哪些元素能够使用定义好的样式 选择器就是为了匹配元素(选择器就是一个条件,符合这个条件的元素就可以使用这个样式) |
2.基础选择器详解
1.通用选择器 *{样式声明} *{margin:0;padding:0} 所有元素的内外边距清0 |
2.元素选择器,标签选择器 页面中所有对应的元素,都应用这个样式 设置页面中某种元素的公有默认样式 ex:p{},div{} 特殊用法:body{margin:0;padding:0} body及内部所有元素的内外边距清0 |
3.ID选择器,专属定制 只对当前页,一个标签生效 <any id="id值"></any> #id值{样式声明} 一般id选择器在项目中很少单独使用,通常会作为子代选择器或者后代选择器的一部分 |
练习:
03_ex.html中有h2标签,内容是假文。此h2的id为text1 使用id选择器设置文本为紫色purple.背景为黄色 字体为斜体 font-style:italic;查看页面观察效果 再使用元素选择器,设置文本为红色,背景为pink 这里会对就近原则产生疑问 |
||||
4.类选择器 定义页面上某些元素的公共样式(类选择器,谁想用谁就可以用) 通过元素的class属性来引用样式 <p class="text-danger">Lorem ipsum dolor sit amet.</p> .text-danger{color:red;}
|
||||
练习:04_ex 页面中添加div和p元素,内容假文 用类选择器为所有元素设置字体为红色,字号为24px,用分类选择器为p元素设置背景为黑色 |
||||
5.群组选择器 将多个选择器使用逗号分隔,放在一起,定义一组公共样式 语法:选择器1,选择器2,选择器3,.....{} ex:div,p,#s1,.d2{color:red;background:yellow;} |
||||
6.后代选择器 通过元素的后代关系匹配元素 后代,一级或者多级的嵌套关系 语法:选择器1 选择器2 选择器3.....{样式声明} 存在的意义:更精准的匹配元素 |
||||
7.子代选择器 通过元素的子代关系匹配元素 子代,一级嵌套关系 语法:选择器1>选择器2>选择器3.....{} 存在的意义:更精准的匹配元素 |
||||
8.伪类选择器 匹配元素不同状态下的不同样式
|
||||
9.选择器的权值 权值:标识当前选择器的重要程度,权值越大优先级越高 !important >1000 内联样式 1000 id选择器 100 类选择器 10 元素选择器 1 *通用选择器 0 继承的样式 无 权值的特点 1.当一个选择器中含有多个选择器时,需要将所有的选择器的权值进行相加,然后比较,权值大的优先显示 2.权值相同,使用就近原则 3.群组选择器的权值单独计算,不能相加 4.样式后面加!important,直接获取最高优先级 内联样式不能加!important 5.选择器权值的计算不会超过自己的最大数量级(100个1加一起也不会大于10) |
四.尺寸和边框
1.尺寸属性
作用,改变元素的宽度和高度 width: 宽度 max-width最大宽度 min-width 最小宽度 height:高度 max-height最大高度 min-height最小高度 |
2.页面中允许设置尺寸的元素
1.所有的块级元素都可以设置 2.所有行内块元素都可以设置 input(除了单选多选以外) 3.本身具备尺寸属性的元素可以设置 img table 4.大部分行内元素都不能设置宽高 |
3.溢出处理
当内容较大,元素区域较小的时候,就会发生溢出效果 默认都是纵向溢出 overflow:默认值 visible 溢出部分可见 hidden 溢出部分隐藏 scroll 显示滚动条,溢出时滚动条可用 auto 自动,溢出时有滚动条,不溢出没有 overflow-x,设置水平轴的滚动条 overflow-y,设置垂直轴的滚动条 |
如何改成横向溢出 需要在宽度比较小的容器内部,添加一个宽度较大的元素。 在父容器上,写overflow。就可以横向溢出了 |
附加知识点---单位
尺寸单位 1.px 像素 2.in 英寸 1in=2.54cm 3.pt 磅值,多用于字体大小 1pt=1/72in 4.cm 5.mm 6.% 相对父级的百分比 7.em 相对于父级元素样式数据乘以的倍数 1.5em 8.rem 相对根元素数据乘以的倍数 boot默认1rem=16px |
作业
1.今天所有css的demo
2.继续完成ajax注册功能
验证用户名已存在的接口
注册接口
day09 css
附加知识点:合法颜色值
1.颜色的英文单词 2.#rrggbb 6个16进制的数字 ff 为255 3.#aabbcc简写成#abc #f00 #0f0 #00f #ff0 #f0f #0ff 4.rgb(0~255,0~255,0~255); rgb(100,12,23); 5.rgb(0%,10%,50%); 可以使用,但是项目不用 6.rgba(0~255, 0~255, 0~255,0~1) 1不透明,0全透明 |
一.尺寸和边框
1.尺寸
2.溢出
3.边框
边框的简写方式 border:width style color; width边框的宽度,以px为单位的数字 style 边框的样式 solid 实线 dotted 点点虚线 dashed 短线虚线 double 双实线 color 边框的颜色 合法的颜色,transparent透明 边框的简写方式,会同时设置4个方向的边框 |
边框的单边设置 border-top:10px solid #aaa; border-right:10px solid transparent; border-bottom:10px solid transparent; border-left:10px solid transparent; |
边框的单属性设置 使用单属性设置,必须保证边框有style属性 border-style:solid; border-width:3px; border-color:#f0f; |
单边单属性 border-方向-属性,一共12个 border-top-width border-top-style border-top-color border-right-width border-right-style border-right-color border-bottom-width border-bottom-style border-bottom-color border-left-width border-left-style border-left-color |
边框的倒角(圆角) border-radius:圆角的半径 取值:以px为单位的数字 % 50%就是一个圆 单角设置,需要两个方向的边,才能确定一个角 先写上下,再写左右 border-top-left-radius: border-top-right-radius: border-bottom-left-radius: border-bottom-right-radius: |
边框的阴影 box-shadow:h-shadow v-shadow blur spread color inset; h-shadow:水平方向偏移量 v-shadow:垂直方向偏移量 blur:阴影的模糊距离,数值越大,越模糊 spread:阴影的尺寸 color:阴影的颜色 inset:把向外的阴影,变成向内的阴影 |
练习
中午,完成最酷的日食或者月食(放射性符号) |
轮廓 边框的边框,绘制与边框周围的线条 outline:width style color; outline:none/0;去掉轮廓 border:none/0;去掉边框 |
二.框模型--盒子模型
框模型--元素在页面上实际占地空间的计算方式 浏览器默认的元素实际占地宽度 左外边距+左边框+左内边距+内容区域宽度+右内边距+右边框+右外边距 浏览器默认的元素实际占地高度 上外边距+上边框+上内边距+内容区域高度+下内边距+下边框+下外边距 外边距margin:边框以外的距离(元素与元素之间的距离) 内边距padding:边框与内容之间的距离 |
1.外边距margin
改变外边距,元素有位移效果 1.语法
2.简写方式
3.外边距的特殊效果
|
2.内边距padding
改变内边距的效果,感觉是改变了元素大小 不会影响其他元素,但是会改变元素自己占地尺寸,感觉上改变了元素本身的大小 |
1.语法:padding padding:v1;设置4个方向的内边距 padding-top padding-right padding-bottom padding-left 取值:以px为单位的数字 % |
2.简写方式 padding:v1;设置4个方向 padding:v1 v2; v1:上下,v2:左右。padding没有auto padding:v1 v2 v3; v1:上,v2:左右,v3:下 padding:v1 v2 v3 v4;上右下左 |
3.box-sizing属性
设置元素占地尺寸的计算方式 box-sizing
|
项目中,写样式的思路
从上往下写,从外往里写,从左往右写 1.尺寸,大体位置 2.边框,背景色 3.文本样式 4.微调 |
day10 css
一.边距
1.box-sizing
浏览器默认元素框模型 元素的实际占地宽度:左外边距+左边框+左内边距+内容区域宽度+右内边距+右边框+右外边距 默认box-sizing: content-box; 默认值 content-box 设置的width和height,只是在设置内容区域 border-box 设置的width和height,是边框内部的部分(包含边框) 元素实际占地宽度:左外边距+设置的width+右外边距 |
二.背景
1.背景颜色
2.背景图片
background-image:url(资源路径) 使用背景图片,可以让元素内部的子元素,堆叠显示在背景图上 而img标签,默认不可以堆叠显示 |
3.背景图片的平铺
background-repeat: 取值:repeat,默认值,平铺 no-repeat,不平铺,背景图只显示一次 repeat-x 在水平方向平铺 repeat-y 在垂直方向平铺 |
4.背景图片的定位
background-position: 取值 1.x y 以为单位的数字,定义横向位置和纵向位置 2.x% y% 0% 0% 左上 50% 50% 中间 3.关键字 x:left/center/right y:top/center/bottom |
5.背景图片的尺寸
background-size 取值:1.x y 以px为单位的数字,设置具体宽高 2.x% y%按父元素宽高%比设置 3.cover,填充,覆盖。让背景图充满整个容器,哪怕图片显示不全,也没关系 4.contain,包含。让容器可以包含整张图片,图片是显示完整的。容器有空白区域,没关系。 |
6.背景图片的固定
background-attachment: 取值:scroll,默认值,背景图会随窗口滚动条滚动 fixed 背景图相对于窗口固定,窗口滚动时,背景图位置不变,但是只会在原容器内显示 |
7.简写方式
在一个属性中指定背景的多个属性值 属性:background 取值:color url() repeat attachment position; 最精简的写法 backgrond:color/image11:01~11:16休息 |
二.渐变 gradient
1.什么是渐变
渐变是指多种颜色,平缓变化的一种显示效果 |
2.渐变的主要因素
色标:一种颜色,及其出现的位置 一个渐变,至少有两个色标 |
3.渐变分类
1.线性渐变,以直线的方式来填充渐变色 2.径向渐变,以圆形的方式来填充渐变色 3.重复渐变,将线性、径向渐变重复几次实现 |
4.线性渐变
background-image:linear-gradient(angle,color-point1, color-point2,.........); angle:表示渐变的方向,角度 取值 1.关键字 to top 从下往上 to right 从左往右 to bottom 从上往下 to left 从右往左 2.角度值 0deg to top 从下往上 45deg 90deg to right从左往右 180deg to bottom 从上往下 270deg to left 从右往左 color-point:色标 取值:颜色+以px为单位的数字 颜色+% |
5.径向渐变
background-image:radial-gradient(半径 at 圆心x 圆心y,color-point1,color-point2,.........) 半径:px为单位的数字,色标中写具体值半径无效,只有色标中使用%,半径才有效 圆心x 圆心y:圆心所在的位置 取值1. x y 以px为单位的数字 2.x% y% 3.关键字 x left/center/right y top/center/bottom |
6.重复渐变
重复线性渐变 background-image: repeating-linear-gradient( to bottom, #000 0px,#ff0 25px, #000 50px); |
重复径向渐变 background-image:repeating-radial-gradient( 50px at center center,#000 0px,#0ff 10px,#000 20px,#ff0 25px,#000 30px,#0ff 40px,#000 50px); |
7.浏览器兼容问题(ie8.0以下不考虑)
渐变属性,支持低版本浏览器的编写方法 chrome/safari -webkit- firefox -moz- IE -ms- opera -o- background:-webkit-linear-gradient(top,color-point1,color-point2,.....); 有前缀的方向,直接使用top/right/bottom/left 从哪里开始 没有前缀,要使用to top/to right/to bottom/to left 向哪个方向 |
三.文本格式化(重点*****)
1.字体属性
1.指定字号大小
2.设置字体的类型
3.字体加粗
4.字体样式
5.小型大写字母
6.字体属性简写方式
|
day11 css
一.文本格式化(****)
1.字体属性
2.文本属性
1.字体颜色
2.文本对齐方式
3.行高
4.文本线条修饰
5.首行缩进
6.文本阴影
练习:
|
二.表格
1.表格的常用属性
1.table的样式 之前学习的属性,基本都可以用
2.td/th的样式
练习
table特殊的表现方式
3.表格的特有属性
|
三.定位(**********************)
1.什么是定位
改变元素在页面中的位置 |
2.分类
1.普通流定位 2.浮动定位 3.相对定位 4.绝对定位 5.固定定位 |
3.普通流定位(默认文档流)
1.每个元素在页面上都有自己的空间 2.每个元素都是从父元素的左上角开始显示 3.块级元素按照从上到下的方式逐个排列,每个元素单独成行 4.行内元素是多个元素在一行中显示,从左往右逐个排列 |
4.浮动定位(重点***********)
让块级元素横向显示 float: 取值:1.left左浮动,让元素浮动后停靠父元素的左边,或者挨着左侧已浮动元素 2.right右浮动,让元素浮动后停靠父元素的右边,或者挨着右侧已浮动元素 3.none 默认值,无任何浮动 |
浮动的特点 1.元素一旦浮动,脱离文档流(不占页面空间,后面未浮动元素上前补位) 2.浮动元素会停靠在父元素的左边/右边,或者其它已浮动元素的边缘 3.父元素横向显示不下所有浮动元素时,最后显示不下的部分会自动换行 4.浮动解决多个块级元素在同一行显示的问题 |
5.浮动引发的特殊情况
1.浮动元素占位的问题
2.元素一旦浮动,如果元素未定义宽度,那么元素的宽度将以内容为准 3.元素一旦浮动,都会变为块级元素
4.文本,行内元素,行内块,是不会被浮动元素压在下面的 而是,巧妙的避开,环绕着浮动元素显示 |
6.清除浮动
元素一旦浮动,会对后续元素带来影响,后续元素会上前补位 如果后续元素不想上前补位,那么可以给后续元素设置清除浮动 clear: 取值:left 清除左浮动的影响 right 清除右浮动的影响 none 不清除 both 清除左和右浮动的影响 |
7.高度坍塌
块级元素的高度,如果不设置,默认高度是靠内容撑起来的 块级元素内部,所有元素如果都浮动,块级元素认为自己内部没有元素,所有撑不起来。发生了高度坍塌 |
解决方案: 1.为父元素设置高度,弊端:不是每次都知道高是多少 2.为父元素设置浮动 |
day12 css
一.显示方式
决定元素在网页中的表现形式 块级,行内,行内块,table |
1.语法
display: 取值:1.block 让元素的表现和块级元素一致 2.none 不显示元素,隐藏 3.inline 让元素的表现和行内一致 4.inline-block 让元素的表现和行内块一致 5.table 让元素的表现和table一致 |
块级元素:独占一行,可以设置尺寸,上下外边距生效 行内元素:共用一行,设置尺寸无效,上下外边距无效 行内块:共用一行,设置尺寸有效,上下外边距有效 table:独占一行,允许设置尺寸,尺寸以内容为准 |
二.显示效果
visibility 取值:1.visible 默认值,可见的 2.hidden 隐藏,不可见 |
Q:display: none和visibility:hidden的区别 display: none,隐藏,元素脱离文档流,本身不占据页面空间,后面元素会上来补位 visibility:hidden,隐藏,元素不脱离文档流,在页面不可见,但是占据位置 |
三.透明度
opacity 取值 0~1 值越小越透明 |
Q: opacity和rgba的区别 rgba只会改变当前的透明度 opacity,元素内部只要跟元素相关的颜色都会跟着改变透明 |
四.垂直对齐方式
vertical-align: 使用场合: 1.表格中 table/td 取值:top/middle/bottom 2.图片与文字的排版 img 控制图片与两边文字的垂直对齐方式 取值:取值:top/middle/bottom/baseline(基线,默认值) 通常会将所有的图片垂直对齐方式,更改为非基线以外的方式 |
五.光标的设置
cursor: 取值:1.default 箭头 2.pointer 小手 3.crosshair + 4.text 5.wait 等待 6.help 帮助 |
六.列表的样式
1.列表项标识
list-style-type: 取值 1.none 2.disc 3.circle 4.square |
2.列表项图像
list-style-image:url(路径); |
3.列表项的位置
设置列表项在li的外部还内部 list-style-position:inside/outside(默认值); |
4.简写方式
list-style:type image position; 最常用的写法 list-style:none;去掉列表项 |
练习,ul>li
七.定位---相对、绝对、固定定位
position: 取值:static 默认,静态(默认文档流定位) relative 相对定位 absolute 绝对定位 fixed 固定定位 当一个元素被position修饰,并且取值为 relative/absolute/fixed其中一种时, 那么这个元素被称为已定位元素 |
定位要配合偏移属性使用 当一个元素有position属性,并取值为relative/absolute/fixed 那么这个元素就解锁4个偏移属性,元素距离(方向)有多少px top: +往下 -往上 right: +往左 -往右 bottom: +往上 -往下 left:+往右 -往左 |
1.相对定位
相对谁定位,相对自己原来位置偏移某个距离 position:relative;配合4个偏移属性使用 特点:1.不脱离文档流 2.相对定位,如果不写偏移量,效果与没写定位是一样的。不影响任何布局(为了绝对定位做准备) 使用场合: 1.自身元素位置的微调 2.作为绝对定位子元素的已定位祖先级元素 |
2.绝对定位
position:absolute;配合偏移属性应用 特点:1.绝对定位的元素会相对于,离自己"最近的""已定位的""祖先元素",去实现位置的初始化 如果没有已定位的祖先元素,相对于body去实现位置的初始化 2.绝对定位,是脱离文档流的,不占据页面空间,后面元素会上前补位。 3.绝对定位的元素,会变成块级元素 |
3.固定定位
position:fixed;配合偏移量使用 将元素固定在页面上的某个位置,不会随着滚动条发生位置变化,一致固定在可视区域 特点:脱离文档流,位置相对于body初始化 元素不占页面空间 后续元素上前补位 元素变为块级 |
4.堆叠顺序
1.定位的脱离文档流和浮动的脱离文档流不是一个体系 2.默认,后定位的元素,堆叠顺序高 3.设置堆叠顺序 z-index:无单位数字 4.堆叠顺序对父子级无效,儿子永远在父亲的上面 5.只有已定位元素,有堆叠顺序 |
八.CSS3 CORE
1.复杂选择器
1.兄弟选择器 兄弟元素:具备相同父级元素的平级元素之间称为兄弟元素 兄弟选择器,只能往后找,不能往前找
|
2.属性选择器
id class name type value style title 允许通过元素所附带的属性及其值来匹配页面元素,很精准 1.[attr] attr表示任意属性 作用:匹配页面中所有带attr属性的元素 [id]{} [class]{} 2.elem[attr] 作用:匹配页面中所有带有attr属性的elem元素 div[id]{} 3.elem[attr1][attr2]... 作用:匹配页面中所有带有attr1和attr2属性的元素 p[title][id]{} 4.[attr=value] 作用:匹配页面中所有带有attr属性并且值为value的元素 5.模糊属性值 [attr^=value] 匹配属性值以value开头的元素 [attr$=value] 匹配属性值以value结尾的元素 [attr*=value] 匹配属性值中,有value的元素 [attr~=value] 匹配属性值中,有value这个独立单词的元素 |
3.伪类选择器
已经学过的伪类 :link :visited :hover :active :focus |
|||||
1.目标伪类 让被激活锚点,应用样式 选择器:target{} |
|||||
2.结构伪类
|
day13 css
一.复杂选择器
1.:empty
匹配内部没有任何元素的标签 注意:内部不许有空格,文字,元素 |
2.:only-child
匹配属于其父元素的唯一子元素 <p> <a href="">1</a> </p> a:only-child{ background:#ff0; } |
3.否定伪类
:not(selector) 将满足selector条件的元素排除在外 |
4.伪元素选择器
1. :first-letter或::first-letter 匹配元素的首字符 2. :first-line或: :first-line 匹配元素的首行 首字符和首行发生冲突时,使用首字符样式 3. ::selection 必须是两个: 匹配用户选取内容的样式 注意:只能修改文本颜色,背景颜色 |
||
4.伪元素选择器,内容生成 使用 css命令,添加的html元素,称之为伪元素 ::before或者:before 匹配到某元素的内容区域之前的部分 添加一个假的元素,元素内容使用content属性 元素的显示方式使用display控制 注意:content中只能添加文本或者url(图片) ::after或者: after 匹配到某元素的内容区域之后的部分
|
二.弹性布局(重点*************)
1.什么是弹性布局
弹性布局,是一种布局方式 主要解决某个元素中子元素的布局方式 为布局提供了很大的灵活性 |
2.弹性布局的相关概念
1.容器 要发生弹性布局的子元素,的父元素称为容器 就是设置display:flex那个元素 2.项目 要做弹性布局的子元素们,称之为项目 就是设置了display:flex那个元素的,子元素们 3.主轴 项目们排列方向的一条轴,称之为主轴 如果项目们是按照横向排列,那x轴就是主轴 如果项目们是按照纵向排列,那么y轴就是主轴 项目们排列顺序,主轴的起点和终点 4.交叉轴 与主轴垂直相交一条轴,叫做交叉轴 项目们在交叉轴上的对齐方式,是交叉轴的起点和终点 |
3.语法
将元素设置成弹性容器之后,他所有的子元素将变为弹性项目 都允许按照弹性布局的方式排列 属性:display: 取值:1.flex 将块级元素设置为容器 2.inline-flex 将行内元素变为容器 |
特点
1.元素设置为flex容器之后, 项目的float/clear/vertical-align/text-align属性失效 2.项目可以修改尺寸 |
4.容器的属性
|
5.项目的属性
只能设置在某一个项目上,不影响其他项目和容器的效果
|
三.CSS hack
由于不同的浏览器对css的解析认知不同,会导致同一份css在不同浏览器生成的页面效果不同 这种情况,我们开发人员要针对不同的浏览器写不同的css 让我们样式可以兼容不同的浏览器,正确显示效果 针对不同的浏览器写不同的css的过程,就叫做css hack 有些公司,还需要使用css hack tmooc上有拓展视频 |
四.转换(重点*************)
1.什么是转换
改变元素在页面中的位置,大小,角度,以及形状 2D转换,只在X轴和Y轴上发生转换效果 3D转换,增加了Z轴的转换效果 |
2.转换属性
属性:transform 取值:1.none 默认值,无任何转换效果 2.transform-function 表示1个或者多个转换函数。 如果是多个转换函数,中间用空格分开 |
3.转换原点
transform-origin: 取值:以px为单位数字 % 关键字x(left/center/right) y(top/center/bottom) 取值的个数 2个值,表示原点在x轴和y轴上的位置 3个值,表示原点在x轴,y轴和z轴上的位置 默认值:原点在元素的中心位置(center center) |
总结:学习转换,就是学习transform:后面的转换函数
4.2D转换
1.位移(改变元素的位置) 转换函数:translate() 取值:1. translate(x)指定元素在x轴上的位移距离 + 元素往右 - 元素往左 2. translate(x,y)指定元素在x轴和y轴上的位移距离 x:+ 元素往右 - 元素往左 y: + 元素往下 - 元素往上 3. translateX (x); 指定元素在x轴上的位移距离 4. translateY (y);指定元素在y轴上的位移距离 |
day14
一.转换
1.2D转换
1.位移 translate(),改变元素的位置 2.缩放,改变元素的大小
3.旋转,改变元素的角度
4.倾斜
练习:
|
2.3D转换
3D转换是模拟的 1.透视距离
2.3d旋转
|
二.过渡(重点******)过渡是动画的前身
1.什么是过渡
让css的值,在一段时间内平缓变化的效果 |
2.语法
1.指定过渡属性
2.指定过渡时长
3.过渡的时间曲线函数
4.过渡的延迟时间
5.过渡代码编写的位置
6.过渡的简写形式
练习
|
三.动画
1.什么是动画
使元素从一种样式逐渐变为另一种样式 其实就是将多个过渡效果放到一起 |
2.使用关键帧,来控制动画的每一个状态
关键帧 1.动画执行的时间点 2.在这个时间点上的样式 |
3.动画的使用步骤
1.使用关键帧声明动画
2.调用动画
3.动画的其他属性
|
4.动画的兼容性
如果要兼容低版本浏览,需要在动画声明的时候加前缀 @keyframes 动画名称{} @-webkit-keyframes 动画名称{} @-ms-keyframes 动画名称{} @-o-keyframes 动画名称{} @-moz-keyframes 动画名称{} |
三.CSS优化
css优化目的 1.减少服务器端压力 2.提升用户体验 |
1.CSS优化的原则
尽量的减少http的请求个数 页面的顶部,引入css文件 将css和js文件放到外部的独立文件中 |
2.CSS代码优化
合并样式(能写群组,就不单写,能用简写方式,就不单独定义属性) 缩小样式文件的大小(能重用就重用) 减少样式重写 避免出现空的href和src 选择更优的样式属性值 代码压缩 |
四.Bootstrap
1.响应式布局(css3 2010)
1.什么是响应式网页 Responsive web page 响应式/自适应网页 可以根据浏览设备不同(pc,pad,phone) 而自动改变布局,图片,文字效果,不会影响用户浏览体验 |
2.响应式网页必须做下面几件事
1.布局,不能固定元素宽度,必须是流式布局(默认文档流+浮动) 2.文字和图片大小随着容器的大小改变 3.媒体查询技术 响应式网页存在的问题:代码复杂程度几何性的增加 复杂网页,不适合使用响应式 |
3.如何测试响应式网页
1.使用真实设备 好处:真实可靠 缺点:成本高,测试任务巨大 2.使用第三方模拟软件测试 好处:不需要太多真实设备,测试方便 坏处:测试效果有限,有待进一步验证 3.使用chrome等浏览器自带的模拟软件 好处:简单方便 坏处:测试效果有限,需要进一步验证 |
4.编写响应式布局(重点********)
1.手机适配,在meta中声明viewport元标签 <meta name="viewport" content=" width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0 "> 在content,编写参数 width=device-width, 设置视口宽度为设备宽度 initial-scale=1.0, 设置视口的宽度能否缩放 1.0不能缩放 maximum-scale=1.0, 允许缩放的最大倍率 user-scalable=0 是否允许用户手动缩放 0 不能 |
||
最简洁的写法 <meta name="viewport" content="width=device-width, initial-scale=1"> |
||
2.所有的内容/文字/图片都使用相对尺寸,不使用绝对值 |
||
3.流式布局+弹性布局+媒体查询 完成响应式布局 |
||
4.媒体查询,CSS3 Media Query,做响应式必备技术
语法总结
|
作业:
1.使用动画完成时钟效果
2.使用媒体查询完成下面图示
BOOT
day15 bootstrap
https://daneden.github.io/animate.css/ 定义好的动画,在项目中直接使用 |
一.BootStrap
boot给我们封装好很多常用的样式,我们只需要调用类名 但是在项目中,对于很多样式,我们还是需要手写样式和媒体查询 |
BootStrap内容分为5部分 1.如何使用boot 2.全局css 3.组件 4.js插件 5.定制 sass 6.boot项目 |
1.如何使用boot
<meta name="viewport" content="width=device-width,initial-scale=1"/> |
2.全局CSS样式
container
container-fluid
1.按钮相关的class
2.图片相关
3.文字相关
4.列表相关的class
5.table相关的样式
|
3.辅助类
1.边框
2.浮动
3.显示
4.背景颜色
5.圆角
6.内外边距
7.尺寸
|
4.栅格布局(重点********************************)
1.web页面的布局方式一般三种
2.栅格使用
3.响应式栅格
|
day16 bootstrap
一.栅格布局
.container--->row--->col row的直接子元素只能是col 一个row分为12份,使用col-n来控制子元素占地几份 <div class="container"> <div class="row"> <div class="col-lg-3 col-md-6 col-sm-12"></div> <div class="col-lg-3 col-md-6 col-sm-12"></div> <div class="col-lg-3 col-md-6 col-sm-12"></div> <div class="col-lg-3 col-md-6 col-sm-12"></div> </div> </div> |
使用.col类,不添加数字时,自动处理布局 每一个col平均分配空间,col个数可以超过12个 |
注意:,不同屏幕有向上兼容的问题 col-xl-* 只能在xl屏幕有效 col-lg-* 在xl/lg 有效 col-md-*在xl/lg/md 有效 col-sm-*在xl/lg/md/sm 有效 |
列偏移 可以通过列偏移指定该列及后面的列向右移动 offset-*-n *: xl/lg/md/sm |
栅格嵌套 在col中重新写一个div.row |
二.弹性布局
d-block/inline/inline-block/none display所有值 d-*- block/inline/inline-block/none display的响应式 *:xl/lg/md/sm |
||
使用弹性布局,要在父元素上写class d-flex d-flex/d-inline-flex创建一个弹性容器 1.主轴方向
2.项目在主轴上的排列方式
boot对弹性布局,做了响应式封装 让开发者非常灵活的做响应式布局 |
三.表单
1.表单元素的排列方向 form-group 堆叠表单,垂直方向 form-inline 内联表单,水平方向(弹性布局) 2.表单元素的样式class form-control 是input元素的基本类 块级,w100,字体,背景,边框,过渡 col-form-label 设置输入文本与边框的距离 col-form-label-sm 距离较小 col-form-label-lg 距离较大 对于checkbox的样式 父级.form-check 相对定位,让子元素以父级定位 <input checkbox>的class form-check-input 绝对定位,要和. form-check配合使用 .form-text 块级,有上外边距 |
四.组件
网页中一些复杂的特殊效果,之前必须使用js、dom、jq 现在boot为我们封装好了很多组件,我们可以直接使用 方便,快捷。但是如果需要个性化的处理,比较繁琐 boot中,大量使用元素的自定义属性,来调用方法 |
1.下拉菜单
基本结构 <div class="dropdown"> <button class="dropdown-toggle" data-toggle="dropdown"></button> <ul class="dropdown-menu"></ul> </div> .dropdown-toggle 画三角 .dropdown-menu 隐藏 data-toggle="dropdown"自定义属性两个作用 1.当button被点击时,激活事件 2.激活的事件,是以dropdown的方式运行 |
2.按钮组
外层div中class如下几个值 .btn-group 横向按钮组 .btn-group-vertical 纵向按钮组 可以添加 btn-group-sm/lg调整按钮组大小 |
3.信息提示框
外层div的class alert 基本类 alert-danger/warning......提示框颜色 alert-dismissible 为了修饰内部.close 内层 span,取消信息提示框的小叉叉 .close,与父元素的. alert-dismissible配合使用 自定义属性 data-dismiss="alert" |
4.导航
1.水平导航
2.选项卡导航
3.胶囊导航
|
5.导航栏
最外层div.navbar . navbar-expand-lg/md/sm/xl 作为子元素ul.navbar-nav的后代选择器路径, 构成响应式导航栏 内层ul.navbar-nav 弹性,默认主轴column 如何改变主轴方向,配合父级navbar-expand-lg/md/sm/xl 在屏幕宽度足够的时候,横向显示项目, 在屏幕宽度不够的时候,纵向显示,构成响应式导航栏 li.nav-item a.nav-link |
day17 bootstrap
一.组件
1.导航栏
<div class="navbar navbar-expand-lg bg-dark"> div.navbar-expand-* 配合 ul.navbar-nav 在不同屏幕下,让导航横向或者纵向显示 |
2.折叠效果
<button data-toggle="collapse" data-target="#demo"> 折叠</button> <div class="collapse" id="demo">内容</div> 总结:a标签和button标签都可以绑定,指向元素 a使用的是href="#id" button使用的是data-target="#id" |
3.卡片
<div class="card"> <a class="card-link" href="#">标题</a> |
4.手风琴:卡片+折叠
<div id="parent"> 注意事项: 1..collapse不能和.card-body在同一个标签上, 不然会发生隐藏/显示的卡顿 解决方案div.collapse>div.card-body 2.几个折叠部分,可以同时打开,而不能开启一个,其它的都关闭 解决方案,在最外层div上写id="parent" 在所有div.collapse中添加事件的绑定data-parent="#parent" 这样就可以保证在最外层div中,只有一个折叠区域可以打开了 |
5.折叠导航栏
<div class="navbar navbar-expand-sm bg-dark navbar-dark"> 1.折叠div的要写div.navbar-collapse 原因:这个div本身有.collapse,作用是隐藏 .navbar-collapse配合父级的navbar-expand-sm 让当前div的display为flex,不再是none, 此div就显示 2.不隐藏的a标签,要写a.navbar-brand 字体变大,上下内边距,右外边距 3.按钮的样式使用button.navbar-toggler。这是boot专门为折叠导航提供的按钮样式,此样式与navbar-expand-sm配合,实现小屏以下按钮显示,小屏以上按钮隐藏 4.最外层div.navbar-dark/light.这个类对当前div没有任何样式的操作.他存在的意义,把内部的按钮和文字,设置成背景的反色。 由于他本身不对当前div有样式修改,所有当前div需要添加对应的背景色bg-dark/light |
6.媒体对象
Boot提供了很多类,来处理媒体相关的对象(图片,影音) <div class="media border p-3"> |
7.焦点轮播图(轮播时间需要去修改js的代码)
1.最外层大包裹和轮播图片 <div class="carousel" data-ride="carousel"> 结构 div.carousel 相对定位 >div.carousel-inner w100 溢出隐藏 >div.carousel-item display:none >img 事件:给最外层div div.carousel添加自定义属性data-ride="carousel" 然后给某一个 div.carousel-item添加类 .active 这样轮播图片就开始运动了 |
2.录播指示符 <!--3.轮播指示符--> 结构 ul.carousel-indicators>li 对ul的样式,定位,弹性 .carousel-indicators对后代li的样式 li的宽高,li背景,li的位置 我们可以按照自己的需求,重写这部分样式 .carousel-indicators li{ 此外,.carousel-indicators .active 让当前激活的li变成白色 我们要重写此样式 .carousel-indicators .active{ |
3.左右箭头 <a data-slide="next" href="#demo" class="carousel-control-next"> 结构 两个a标签 a.carousel-control-prev/next 这个样式设置了a的宽度,背景色,位置 我们需要重写此样式 .carousel-control-prev, 自定义属性 data-silde="next/prev" 注意要写href="#demo" |
8.模态框
模态框modal是覆盖在父窗体上的一个子窗体 模态框可以在不离开父窗体的情况下与用户有一些互动 <div id="mymodal" class="modal"> |
二.其他组件
1.徽章
基本类 badge 颜色 badge-danger/warning/success... 徽章的样式 badge-pill 胶囊 |
2.巨幕
巨大的内边距,有背景颜色,和圆角 class="jumbotron" |
3.分页
ul.pagination>li.page-item>a.page-link li的修饰类 .active 激活 .disabled 禁用 |
4.面包屑导航
ul.breadcrumb>li.breadcrumb-item 中间的连接符号需要自己重写样式 .breadcrumb-item + .breadcrumb-item::before{ |
5.进度条
div.progress>div.progress-bar+w-50+bg-danger 子div设置w宽度,就是进度条进度 子div设置背景,就是进度的颜色 子div设置条纹 progress-bar-striped 子div设置动画 progress-bar-animated 可以在同一个div.progress中写多个div.progress-bar |
bootstrap重点:响应式+栅格布局+SCSS
三.SCSS,动态的样式语言 (nodejs 8.11以上)
1.css有以下几个缺点
语法不够强大,没有变量和合理的样式复用机制 导致难以维护 我们要使用动态样式语言,赋予css新的特性 提高样式语言的可维护性 |
常见的动态样式语言 1.scss/sass (scss兼容sass,scss更接近css语法) 2.stylus 3.Less |
day18 bootstrap
一.scss boot的订制
SCSS是一款强化css的辅助工具 它和css的语法很像,在CSS的基础上,添加了变量,嵌套,混合,导入,函数等高级功能。这些拓展命令让css更加强大与优雅 |
浏览器不能直接解析运行scss文件,需要在项目中把scss转义成css文件。让浏览器解析。 |
scss可以让css开发更高效 |
1.SCSS的使用
scss在服务器端使用 1.安装nodejs解释器 v8.11以上 2.在线安装scss 在cmd控制台打印命令 npm install -g node-sass 3.无网络的安装 node-sass -v 4.测试是否安装正确 cmd中打印 node-sass -v 显示版本 |
2.SCSS文件转换成CSS文件
1.单文件转换 node-sass scss/01.scss css/01.css scss/01.scss 要转换的scss文件名和目录 css/01.css 转换后的css文件名和目录 保证执行命令的路径是scss/01.scss 的父级 可以在电脑中打开项目的路径,在路径文件夹下 按住shift点击鼠标右键,打开powershell窗口 输入上面命令 10:05~10:20休息 |
2.多文件转换,文件夹转换(一个命令把一个文件夹下所有的.scss都转换) node-sass scss(文件夹名称) -o css(文件夹名称) |
3.单文件监听 node-sass -w scss/01.scss css/01.css 开启,系统会盯着01.scss文件,当01.scss内容发生改变,保存的时候,自动转换为01.css |
4.多文件夹监听 node-sass -w scss -o css |
3.SCSS基础语法
1.变量
2.嵌套
3.导入
4.混合器
5.继承
|
4.运算
1.数字
2.颜色运算
|
三.函数
1.scss定义了很多函数,有些函数甚至可以直接在css语句中调用
rgba(r,g,b,alpha) hsl(h,s,l) h:hue色调 取值0~360,3个色段,120一个 s:saturation 饱和度 0.0%~100.0% l:lightness 亮度 0.0%~100.0% |
2.数学函数
round($val) 四舍五入 ceil($val) 向上取整 floor($val) 向下取整 min($v1,$v2.....) max($v1,$v2.....) random 随机数 |
3.字符串函数
unquote($str) 去掉$str的双引号 quote($str) 给$str添加双引号 to_upper_case($str); $str变大写 to_lower_case($str); $str变小写 |
4.自定义函数
@function get-width($n,$m){ @return $n - $m; } |
练习
定义一个带参数的函数get_mywidth($n) 函数内定义两个变量分为60px和10px 函数返回值为 $n乘以两个变量的最大值,再加上$n乘以俩个变量的最小值。将结果赋值给div的width属性 |
四.指令
@if(){} @else if(){} @else{} 注意:bool值的小括号可以去掉 |
练习
声明一个带参的函数,函数中判断参数 参数大于1,返回200px 参数等于1,返回100px 参数小于1,返回0 把返回赋值给div的width |
阶段3: JS、DOM&BOM、JQUERY、VUE
1.JS
day01 正则
张东
微信: 18301092802
准备:
1. 书: 犀牛书 JavaScript权威指南
2. 微信公众号: 前端大全
3. 上一届的笔记: 打印出来
千万不要记笔记!!!
概述:
JavaScript核心编程: 闭包,面向对象,ES5,ES6,异步编程
DOM: 为网页添加交互行为的一套程序——所有场合使用!
jQuery: DOM的简化版——PC
Vue: 自动化的框架
React:
正课:
1. 正则表达式
2. String中的正则API:
1. 正则表达式:
2. String中的正则表达式:
查找敏感词: 4种:
1. 查找一个固定的敏感词出现的位置
var i=str.indexOf("敏感词",starti)
在str中,从starti位置开始,找下一个敏感词出现的位置
返回值: 如果找到,返回敏感词第一个字的下标
如果没找到,返回-1
问题: 只能查找一个固定的敏感词,不支持正则!
2. 模糊查找一个敏感词的位置:
var i=str.search(/正则/i)
在str中查找符合正则要求的第一个敏感词出现的位置
返回值: 如果找到,返回敏感词第一个字的下标
如果没找到,返回-1
问题: 正则表达式默认区分大小写
解决: 在正则第二个/后加后缀i, 表示ignore
问题: 只能返回位置,不能返回内容
3. 查找敏感词内容
2种:
1. 只查找一个敏感词的内容:
var arr=str.match(/正则/i)
在str中查找第一个敏感词的[内容和位置]
返回值:
如果找到,返回一个数组:
["0":敏感词内容, "index": 下标i ]
如果没找到,返回null
数组:关联数组和索引数组
js底层一切都是关联数组,没有堆和栈
day02 String正则API&FegExp
每个案例三遍:
1. 代码+注释抄一遍
2. 保留注释,删除代码,自己试着把代码填回来
3. 都删掉,尝试将注释和代码一起写回来——自己会了
注释最重要!
正课:
1. String正则API
2. RegExp对象
3. ***Function对象
1. String正则API
查找:4种场景
1. 查找一个固定的关键词出现的位置:
var i=str.indexOf("敏感词",starti)
2. 用正则表达式模糊查找关键词的位置:
var i=str.search(/正则/i)
3. 查找关键词的内容:
1. 只查找第一个关键词的内容:
var arr=str.match(/正则/i)
arr:["0": 关键词内容, "index": 下标i ]
问题: 只能找一个敏感词
2. 查找所有敏感词的内容:
var arr=str.match(/正则/ig) global
arr:[ 敏感词1, 敏感词2, ... ... ]
返回所有找到的敏感词内容的列表
如果找不到返回null
强调: 凡是返回null的函数,都要先判断不是null,再使用。
4. 既查找所有关键词的内容,又能获得每个关键词的位置
reg.exec()
替换: 2种:
1. 简单替换: 将所有敏感词都替换为一致的新值
str=str.replace(/正则/ig,"新值")
2. 高级替换: 根据本次找到的敏感词的不同,动态选择不同的新值替换
str=str.replace(
/正则/ig,
//replace每找到一个敏感词,就自动调用一次回调函数
function(kword){ kword: y c y u
形参kword,自动获得本次找到的敏感词内容
return 返回的新值
kword.toUpperCase()
}// return Y C Y U
)
回调函数callback:咱们负责定义函数,然后将函数交给别的程序去自动执行。
特点: 1. 不一定立刻执行
2. 不止执行一次,可能反复执行
3. 自动传入参数
衍生: 删除敏感词: ——作业:
其实就是将敏感词替换为""
str=str.replace(/正则/ig,"")
切割: 将字符串按指定的分隔符,分割为多段子字符串
如何:
2种:
1. 简单切割: 分隔符是固定不变的
var arr=str.split("分隔符")
固定套路: 打散字符串为字符数组(按""切割)
var arr=str.split("")
2. 复杂切割: 分隔符不固定
var arr=str.split(/正则/)
2. RegExp对象:
什么是: 专门保存一条正则表达式,并提供用正则表达式执行查找和验证操作的方法。
何时: 只要在js中使用正则表达式,都要创建正则表达式对象
如何:
创建: 2种:
1. 用/方式:
var reg=/正则/ig;
问题: 不能在程序运行时,动态拼接正则,只能预先写死正则。
2. 用new:
var reg=new RegExp("正则","ig")
优势: 可在运行时动态拼接正则字符串
功能:
1. 验证:
var bool=reg.test(str)
验证str是否符合reg的格式要求
问题: 并不是完全匹配。只要在str中找到部分内容和reg匹配,就返回true!
解决: 要求从头到尾完整匹配
今后只要做验证,必须前加^,后加$
2. 查找: 查找所有敏感词的内容和位置
var arr=reg.exec(str)
在str中找下一个符合reg要求的敏感词的内容和位置
返回值: 同match不加g时一样
arr:[ "0": 敏感词内容, "index": 下标i ]
3. Function对象:
什么是: 保存一段可重用的代码段的对象,再起一个名字
为什么: 重用一段代码
何时: 只要发现一段代码需要反复使用时,都要定义为一个函数。
如何:
1. 声明方式:
function 函数名(形参列表){
函数体;
return 返回值;
}
var 返回值=函数名(实参列表)
问题: 会被声明提前:
2. 用赋值方式:
var函数名=function (形参列表){
函数体;
return 返回值;
}
day03 Function
正课:
1. Function对象
2. 面向对象
1. Function对象
创建: 3种:
1. 声明方式:
function 函数名(形参列表){
函数体;
return 返回值
}
会被声明提前
2. 赋值方式:
var函数名=function (形参列表){
函数体;
return 返回值
}
不会被声明提前
揭示: 函数其实也是一个对象
函数名其实只是一个简单的变量
3. 用new:
var 函数名=new Function("形参1","形参2",...,"函数体")
重载overload:
什么是: 相同函数名,不同形参列表的多个函数,在调用时可根据传入参数的不同,自动选择匹配的函数执行。
为什么: 减少函数的个数,减轻调用者的负担
何时: 一件事,可能根据传入的参数不同,选择执行不同的操作时
如何:
问题: js语言默认不支持重载的语法
因为js不允许多个同名函数同时存在
如果同时存在,只有最有一个会覆盖之前所有
解决: 用arguments对象变通实现
arguments: 每个函数中自带的接收所有实参值的类数组对象
每个函数: 所有函数中都有arguments对象
自带: 不用自己创建,直接使用
作用: 接收所有实参值
数据结构: 类数组对象——长的像数组的对象
相同: 1. 下标 2. length 3. for循环遍历
不同: 类型不同——类数组对象是对象家孩子,无权使用数组家的API
匿名函数:
什么是: 定义函数时,不起名的函数,称为匿名函数
为什么: 节约内存!
何时: 只要一个函数,只使用一次时,都要用匿名函数,而不是有名称的函数
如何: 2种:
1. 回调函数:
比如: setInterval/setTimeout(function(){...},1000)
arr.sort(function(a,b){return a-b})
str.replace(/正则/ig,function(kw){ ... })
2. 匿名函数自调: 也称为立即调用函数IIF
什么是: 定义一个匿名函数,然后立刻执行
为什么: 临时创建一个函数作用域,避免使用全局变量
何时: 今后所有的js代码,都要放在一个巨大的匿名函数自调中。
(function(){
自己的功能代码
})()
作业:
1. function fun(){
var n=999;
nAdd=function(){ n++ };
return function(){
console.log(n);
}
}
var getN=fun();
getN()//?
nAdd()
getN()//?
2. function fun(){
for(var i=0,arr=[]; i<3;i++){
arr[i]=function(){ console.log(i); }
}
return arr;
}
var funs=fun();
funs[0]();//?
funs[1]();//?
funs[2]();//?
day04 面向对象
正课:
1. 面向对象:
什么是成员变量: 在对象中,函数里面的变量是成员变量
Var lilei={
Sname:lilei,
Sage: 12
Iintr : Function (){
这里面的是成员变量
}
}
1. 面向对象:
什么是: 程序中都是用对象结构来描述现实中的事物
为什么: 便于大量数据的维护
何时: 所有程序都是用面向对象的思想管理数据和功能
如何: 面向对象三大特点: 封装,继承,多态
1. 封装:
什么是: 创建一个对象结构,保存一个事物的属性和功能
为什么: 便于大量数据的维护
何时: 今后所有数据都是先封装在对象中,再按需使用
如何: 3种:
1. 用{}创建一个对象:
var 对象名={
属性: 属性值,
... : ... ,
功能: function(){
... this.属性名 ...
}
}
访问对象的成员: 成员=属性+方法
访问属性: 对象名.属性
调用方法: 对象名.方法()
问题: 对象自己的方法内,想访问自己的属性,也不能直接属性,报错: 属性 未定义
为什么: 对象的属性没有直接保存在一个函数的作用域链中,而引擎不能擅自进入对象中获取数据。
解决一: 对象名.属性/方法
问题: 紧耦合: 对象名发生变化,必须同时改内部的对象名,一旦忘改,就出错!
解决二: 松耦合: 能不能自动获得对象名——this
什么是this: 正在调用当前函数的.前的对象
每个函数与生俱来的关键词,可自动获得.前的对象
鄙视时: this只和调用时.前的对象有关,和保存在哪儿毫无关系!
如果一个函数前没加任何.,默认是window.
总结: 何时: 只要对象自己的方法内,想使用对象自己的属性和其它方法时,都必须用this.
2. 用new: 2步: 同关联数组的创建过程
var obj=new Object(); //obj:{}
obj.属性名=值;
obj.方法名=function(){ ... }
Obj.sname=”li lei”
揭示了: js底层所有对象都是关联数组
vs 关联数组相比:
相同:
1. js中的对象,可随时添加新属性和新方法,而不会报错!
2. 访问对象中不存在的属性,不会报错,而是返回undefined
3. 访问对象中的成员,有两种方式:
简写: 对象名.属性名/方法名()
// ||等效
何时: 如果要访问的属性名是写死的
完整: 对象名["属性名"]/["方法名"] ()
何时: 如果要访问的属性只能在运行时动态获得
4. 对象也可以用for in遍历每个属性
缺点: 一次只能创建一个对象,如果反复创建多个相同结构的对象时,代码会很繁琐。
解决: 构造函数
3. 用构造函数反复创建多个相同结构的对象
什么是构造函数: 专门描述一类对象统一结构的函数
何时: 只要反复创建多个相同结构的对象
如何: 2步:
1. 定义构造函数:
function 类型名(形参1, 形参2, ... ){
this.属性名=形参1;
... = ...;
this.方法名=function(){ ... this.属性名 ...}
}
2. 用构造函数创建多个对象:
用new调用构造函数,创建出规定格式和功能的对象
var 对象名=new 类型名(属性值,属性值,...)
鄙视题: new的原理: 4件事:
1. 创建一片空的存储空间
2.
3. 用新的空对象作为主语调用构造函数
new Student(属性值,...)
=> new.Student(属性值,...) this->new{}
↓
=> this.属性名=形参
↓
=>new{}.属性名=属性值
在new{}中强行添加该新属性,并将属性值保存进对象中——野蛮的强行赋值方式
结果: new{}中就反复添加了规定的新属性和方法
4. 返回新对象的结果
凡是不带前缀的变量,只能在作用域链中查找 比如console.log (a)
Day05
正课:
1. OOP
2. ES5
1. OOP
三大特点: 封装,继承,多态
封装:
3. 用构造函数反复创建多个相同结构的对象:
function Student(sname,sage){
this.sname=sname;
this.sage=sage;
this.intr=function(){
console.log(`I'm ${this.sname},I'm ${this.sage}`);
}
}
//用new创建:
var lilei=new Student("Li Lei",11);
var hmm=new Student("Han Meimei",12);
console.log(lilei);
console.log(hmm);
lilei.intr();
hmm.intr();
问题: 将方法的定义放在构造函数内,会重复创建多个相同函数的副本,浪费内存。且,不便于维护。
解决: 1. 构造函数中不要包含方法定义
2. 将方法定义放在共同的爹中,让所有孩子共用!
继承:
什么是继承: 父对象中的成员,子对象无需重复创建,就可直接使用。
为什么继承: 代码重用,节约内存
何时继承: 多个孩子对象,都拥有相同的方法定义时,就要用继承,将方法保存在爹中,所有孩子自动共用。
如何实现继承: js中的继承都是自动继承原型对象
什么是原型对象: 在一个类型的大家庭中,集中保存所有孩子对象共用的成员的父对象
如何使用原型对象:
创建: 不用自己创建!买一赠一!
当创建构造函数(妈妈)时,自动附赠了一个原型对象(爹)
继承: 不用自己继承, new的第二步
让新创建的子对象,自动继承构造函数的prototype(爹)
向原型对象中添加共有成员: 需要自己做
Student.prototype.intr=function(){ ... }
妈妈 的 老公
如何使用原型对象中的共有成员:
用子对象调用共有成员:
var lilei=new Student(... ...);
lilei.intr()
//现在lilei里找,如果找到,就先用自己的
//如果没找到,才延_ _proto_ _属性先父对象中查找,只要找到,可直接使用,无需重复创建。
自有属性和共有属性:
什么是自有属性: 保存在子对象本地,仅当前子对象自己所有的属性
什么是共有属性: 保存在父对象中,所有子对象共有的属性
读取属性值: lilei.sname lilei.className
无论自有属性还是共有属性都可用子对象来读取
修改属性时: 如果修改自有属性,可用子对象修改
lilei.sage++;
如果修改共有属性: 只能用原型对象,不能用子对象修改共有属性。
如果强行用子对象修改共有属性,结果:会为当前子对象个人添加一个同名的自有属性。从此,该子对象与其他子对象分道扬镳。—— 错误的效果!
应该: 只要修改共有属性,必须用原型对象亲自改
Student.prototype.className="初三2班"
lilei.__proto__.intr() I'm undefined, I'm undefined
lilei.intr() I'm Li Lei, I'm 11
原型链:
什么是: 由多级原型对象,逐级继承,形成的链式结构
2个作用:
1. 存储着一个对象可用的所有属性和方法
2. 控制着成员的使用顺序: 先自有,再共有
vs 作用域链:
2个作用:
1. 存储着所有不用.就可访问的变量
2. 控制着变量的使用顺序,先局部,后全局
js内置类型: 11种:
Number String Boolean
Array Date RegExp Math
Error
Function Object
global(在浏览器中被更名为window)
自定义继承:
何时: 如果默认的爹不是想要的,可更改
如何: 2种:
1. 仅修改一个对象的父对象:
child.__proto__=father
设置child的爹为father
Object.setPrototypeOf(child, father)
2. 同时更换多个子对象的爹
更换妈妈的老公
Student.prototype=father
讲究时机: 必须在创建子对象之前换!
多态:
什么是: 一个函数在不同情况下表现出不同的状态
包括2种情况:
1. 重载
2. 重写(override):
什么是: 如果子对象觉得从父对象继承来的成员不好用,可在子对象本地创建同名成员,覆盖父对象中的成员。使用时,只要自己有,就先用自己的。
何时: 觉得从父对象继承来的成员不好用
如何: 只要在对象本地定义与父对象中同名的成员,即可。
2. ES5:
ECMAScript 第5个版本
1. 严格模式:
什么是: 比普通js运行机制,要求更严格的模式
为什么: js语言本身具有很多广受诟病的缺陷
何时: 今后所有的js程序,必须运行在严格模式下!
如何:
在当前作用域的顶部写:"use strict";——启用严格模式
规定:
1. 禁止给未声明变量赋值:
2. 静默失败升级为错误:
什么是静默失败: 执行不成功,但还不报错。
ES5中规定,所有静默失败,都升级为报错!
3. 匿名函数自调和普通函数调用中的this,不再指向window!而是this=undefined。
阶段3: JS、DOM&BOM、JQUERY、VUE
1.JS
day01 正则
张东
微信: 18301092802
准备:
1. 书: 犀牛书 JavaScript权威指南
2. 微信公众号: 前端大全
3. 上一届的笔记: 打印出来
千万不要记笔记!!!
概述:
JavaScript核心编程: 闭包,面向对象,ES5,ES6,异步编程
DOM: 为网页添加交互行为的一套程序——所有场合使用!
jQuery: DOM的简化版——PC
Vue: 自动化的框架
React:
正课:
1. 正则表达式
2. String中的正则API:
1. 正则表达式:
2. String中的正则表达式:
查找敏感词: 4种:
1. 查找一个固定的敏感词出现的位置
var i=str.indexOf("敏感词",starti)
在str中,从starti位置开始,找下一个敏感词出现的位置
返回值: 如果找到,返回敏感词第一个字的下标
如果没找到,返回-1
问题: 只能查找一个固定的敏感词,不支持正则!
2. 模糊查找一个敏感词的位置:
var i=str.search(/正则/i)
在str中查找符合正则要求的第一个敏感词出现的位置
返回值: 如果找到,返回敏感词第一个字的下标
如果没找到,返回-1
问题: 正则表达式默认区分大小写
解决: 在正则第二个/后加后缀i, 表示ignore
问题: 只能返回位置,不能返回内容
3. 查找敏感词内容
2种:
1. 只查找一个敏感词的内容:
var arr=str.match(/正则/i)
在str中查找第一个敏感词的[内容和位置]
返回值:
如果找到,返回一个数组:
["0":敏感词内容, "index": 下标i ]
如果没找到,返回null
数组:关联数组和索引数组
js底层一切都是关联数组,没有堆和栈
day02 String正则API&FegExp
每个案例三遍:
1. 代码+注释抄一遍
2. 保留注释,删除代码,自己试着把代码填回来
3. 都删掉,尝试将注释和代码一起写回来——自己会了
注释最重要!
正课:
1. String正则API
2. RegExp对象
3. ***Function对象
1. String正则API
查找:4种场景
1. 查找一个固定的关键词出现的位置:
var i=str.indexOf("敏感词",starti)
2. 用正则表达式模糊查找关键词的位置:
var i=str.search(/正则/i)
3. 查找关键词的内容:
1. 只查找第一个关键词的内容:
var arr=str.match(/正则/i)
arr:["0": 关键词内容, "index": 下标i ]
问题: 只能找一个敏感词
2. 查找所有敏感词的内容:
var arr=str.match(/正则/ig) global
arr:[ 敏感词1, 敏感词2, ... ... ]
返回所有找到的敏感词内容的列表
如果找不到返回null
强调: 凡是返回null的函数,都要先判断不是null,再使用。
4. 既查找所有关键词的内容,又能获得每个关键词的位置
reg.exec()
替换: 2种:
1. 简单替换: 将所有敏感词都替换为一致的新值
str=str.replace(/正则/ig,"新值")
2. 高级替换: 根据本次找到的敏感词的不同,动态选择不同的新值替换
str=str.replace(
/正则/ig,
//replace每找到一个敏感词,就自动调用一次回调函数
function(kword){ kword: y c y u
形参kword,自动获得本次找到的敏感词内容
return 返回的新值
kword.toUpperCase()
}// return Y C Y U
)
回调函数callback:咱们负责定义函数,然后将函数交给别的程序去自动执行。
特点: 1. 不一定立刻执行
2. 不止执行一次,可能反复执行
3. 自动传入参数
衍生: 删除敏感词: ——作业:
其实就是将敏感词替换为""
str=str.replace(/正则/ig,"")
切割: 将字符串按指定的分隔符,分割为多段子字符串
如何:
2种:
1. 简单切割: 分隔符是固定不变的
var arr=str.split("分隔符")
固定套路: 打散字符串为字符数组(按""切割)
var arr=str.split("")
2. 复杂切割: 分隔符不固定
var arr=str.split(/正则/)
2. RegExp对象:
什么是: 专门保存一条正则表达式,并提供用正则表达式执行查找和验证操作的方法。
何时: 只要在js中使用正则表达式,都要创建正则表达式对象
如何:
创建: 2种:
1. 用/方式:
var reg=/正则/ig;
问题: 不能在程序运行时,动态拼接正则,只能预先写死正则。
2. 用new:
var reg=new RegExp("正则","ig")
优势: 可在运行时动态拼接正则字符串
功能:
1. 验证:
var bool=reg.test(str)
验证str是否符合reg的格式要求
问题: 并不是完全匹配。只要在str中找到部分内容和reg匹配,就返回true!
解决: 要求从头到尾完整匹配
今后只要做验证,必须前加^,后加$
2. 查找: 查找所有敏感词的内容和位置
var arr=reg.exec(str)
在str中找下一个符合reg要求的敏感词的内容和位置
返回值: 同match不加g时一样
arr:[ "0": 敏感词内容, "index": 下标i ]
3. Function对象:
什么是: 保存一段可重用的代码段的对象,再起一个名字
为什么: 重用一段代码
何时: 只要发现一段代码需要反复使用时,都要定义为一个函数。
如何:
1. 声明方式:
function 函数名(形参列表){
函数体;
return 返回值;
}
var 返回值=函数名(实参列表)
问题: 会被声明提前:
2. 用赋值方式:
var函数名=function (形参列表){
函数体;
return 返回值;
}
day03 Function
正课:
1. Function对象
2. 面向对象
1. Function对象
创建: 3种:
1. 声明方式:
function 函数名(形参列表){
函数体;
return 返回值
}
会被声明提前
2. 赋值方式:
var函数名=function (形参列表){
函数体;
return 返回值
}
不会被声明提前
揭示: 函数其实也是一个对象
函数名其实只是一个简单的变量
3. 用new:
var 函数名=new Function("形参1","形参2",...,"函数体")
重载overload:
什么是: 相同函数名,不同形参列表的多个函数,在调用时可根据传入参数的不同,自动选择匹配的函数执行。
为什么: 减少函数的个数,减轻调用者的负担
何时: 一件事,可能根据传入的参数不同,选择执行不同的操作时
如何:
问题: js语言默认不支持重载的语法
因为js不允许多个同名函数同时存在
如果同时存在,只有最有一个会覆盖之前所有
解决: 用arguments对象变通实现
arguments: 每个函数中自带的接收所有实参值的类数组对象
每个函数: 所有函数中都有arguments对象
自带: 不用自己创建,直接使用
作用: 接收所有实参值
数据结构: 类数组对象——长的像数组的对象
相同: 1. 下标 2. length 3. for循环遍历
不同: 类型不同——类数组对象是对象家孩子,无权使用数组家的API
匿名函数:
什么是: 定义函数时,不起名的函数,称为匿名函数
为什么: 节约内存!
何时: 只要一个函数,只使用一次时,都要用匿名函数,而不是有名称的函数
如何: 2种:
1. 回调函数:
比如: setInterval/setTimeout(function(){...},1000)
arr.sort(function(a,b){return a-b})
str.replace(/正则/ig,function(kw){ ... })
2. 匿名函数自调: 也称为立即调用函数IIF
什么是: 定义一个匿名函数,然后立刻执行
为什么: 临时创建一个函数作用域,避免使用全局变量
何时: 今后所有的js代码,都要放在一个巨大的匿名函数自调中。
(function(){
自己的功能代码
})()
作业:
1. function fun(){
var n=999;
nAdd=function(){ n++ };
return function(){
console.log(n);
}
}
var getN=fun();
getN()//?
nAdd()
getN()//?
2. function fun(){
for(var i=0,arr=[]; i<3;i++){
arr[i]=function(){ console.log(i); }
}
return arr;
}
var funs=fun();
funs[0]();//?
funs[1]();//?
funs[2]();//?
day04 面向对象
正课:
1. 面向对象:
什么是成员变量: 在对象中,函数里面的变量是成员变量
Var lilei={
Sname:lilei,
Sage: 12
Iintr : Function (){
这里面的是成员变量
}
}
1. 面向对象:
什么是: 程序中都是用对象结构来描述现实中的事物
为什么: 便于大量数据的维护
何时: 所有程序都是用面向对象的思想管理数据和功能
如何: 面向对象三大特点: 封装,继承,多态
1. 封装:
什么是: 创建一个对象结构,保存一个事物的属性和功能
为什么: 便于大量数据的维护
何时: 今后所有数据都是先封装在对象中,再按需使用
如何: 3种:
1. 用{}创建一个对象:
var 对象名={
属性: 属性值,
... : ... ,
功能: function(){
... this.属性名 ...
}
}
访问对象的成员: 成员=属性+方法
访问属性: 对象名.属性
调用方法: 对象名.方法()
问题: 对象自己的方法内,想访问自己的属性,也不能直接属性,报错: 属性 未定义
为什么: 对象的属性没有直接保存在一个函数的作用域链中,而引擎不能擅自进入对象中获取数据。
解决一: 对象名.属性/方法
问题: 紧耦合: 对象名发生变化,必须同时改内部的对象名,一旦忘改,就出错!
解决二: 松耦合: 能不能自动获得对象名——this
什么是this: 正在调用当前函数的.前的对象
每个函数与生俱来的关键词,可自动获得.前的对象
鄙视时: this只和调用时.前的对象有关,和保存在哪儿毫无关系!
如果一个函数前没加任何.,默认是window.
总结: 何时: 只要对象自己的方法内,想使用对象自己的属性和其它方法时,都必须用this.
2. 用new: 2步: 同关联数组的创建过程
var obj=new Object(); //obj:{}
obj.属性名=值;
obj.方法名=function(){ ... }
Obj.sname=”li lei”
揭示了: js底层所有对象都是关联数组
vs 关联数组相比:
相同:
1. js中的对象,可随时添加新属性和新方法,而不会报错!
2. 访问对象中不存在的属性,不会报错,而是返回undefined
3. 访问对象中的成员,有两种方式:
简写: 对象名.属性名/方法名()
// ||等效
何时: 如果要访问的属性名是写死的
完整: 对象名["属性名"]/["方法名"] ()
何时: 如果要访问的属性只能在运行时动态获得
4. 对象也可以用for in遍历每个属性
缺点: 一次只能创建一个对象,如果反复创建多个相同结构的对象时,代码会很繁琐。
解决: 构造函数
3. 用构造函数反复创建多个相同结构的对象
什么是构造函数: 专门描述一类对象统一结构的函数
何时: 只要反复创建多个相同结构的对象
如何: 2步:
1. 定义构造函数:
function 类型名(形参1, 形参2, ... ){
this.属性名=形参1;
... = ...;
this.方法名=function(){ ... this.属性名 ...}
}
2. 用构造函数创建多个对象:
用new调用构造函数,创建出规定格式和功能的对象
var 对象名=new 类型名(属性值,属性值,...)
鄙视题: new的原理: 4件事:
1. 创建一片空的存储空间
2.
3. 用新的空对象作为主语调用构造函数
new Student(属性值,...)
=> new.Student(属性值,...) this->new{}
↓
=> this.属性名=形参
↓
=>new{}.属性名=属性值
在new{}中强行添加该新属性,并将属性值保存进对象中——野蛮的强行赋值方式
结果: new{}中就反复添加了规定的新属性和方法
4. 返回新对象的结果
凡是不带前缀的变量,只能在作用域链中查找 比如console.log (a)
Day05
正课:
1. OOP
2. ES5
1. OOP
三大特点: 封装,继承,多态
封装:
3. 用构造函数反复创建多个相同结构的对象:
function Student(sname,sage){
this.sname=sname;
this.sage=sage;
this.intr=function(){
console.log(`I'm ${this.sname},I'm ${this.sage}`);
}
}
//用new创建:
var lilei=new Student("Li Lei",11);
var hmm=new Student("Han Meimei",12);
console.log(lilei);
console.log(hmm);
lilei.intr();
hmm.intr();
问题: 将方法的定义放在构造函数内,会重复创建多个相同函数的副本,浪费内存。且,不便于维护。
解决: 1. 构造函数中不要包含方法定义
2. 将方法定义放在共同的爹中,让所有孩子共用!
继承:
什么是继承: 父对象中的成员,子对象无需重复创建,就可直接使用。
为什么继承: 代码重用,节约内存
何时继承: 多个孩子对象,都拥有相同的方法定义时,就要用继承,将方法保存在爹中,所有孩子自动共用。
如何实现继承: js中的继承都是自动继承原型对象
什么是原型对象: 在一个类型的大家庭中,集中保存所有孩子对象共用的成员的父对象
如何使用原型对象:
创建: 不用自己创建!买一赠一!
当创建构造函数(妈妈)时,自动附赠了一个原型对象(爹)
继承: 不用自己继承, new的第二步
让新创建的子对象,自动继承构造函数的prototype(爹)
向原型对象中添加共有成员: 需要自己做
Student.prototype.intr=function(){ ... }
妈妈 的 老公
如何使用原型对象中的共有成员:
用子对象调用共有成员:
var lilei=new Student(... ...);
lilei.intr()
//现在lilei里找,如果找到,就先用自己的
//如果没找到,才延_ _proto_ _属性先父对象中查找,只要找到,可直接使用,无需重复创建。
自有属性和共有属性:
什么是自有属性: 保存在子对象本地,仅当前子对象自己所有的属性
什么是共有属性: 保存在父对象中,所有子对象共有的属性
读取属性值: lilei.sname lilei.className
无论自有属性还是共有属性都可用子对象来读取
修改属性时: 如果修改自有属性,可用子对象修改
lilei.sage++;
如果修改共有属性: 只能用原型对象,不能用子对象修改共有属性。
如果强行用子对象修改共有属性,结果:会为当前子对象个人添加一个同名的自有属性。从此,该子对象与其他子对象分道扬镳。—— 错误的效果!
应该: 只要修改共有属性,必须用原型对象亲自改
Student.prototype.className="初三2班"
lilei.__proto__.intr() I'm undefined, I'm undefined
lilei.intr() I'm Li Lei, I'm 11
原型链:
什么是: 由多级原型对象,逐级继承,形成的链式结构
2个作用:
1. 存储着一个对象可用的所有属性和方法
2. 控制着成员的使用顺序: 先自有,再共有
vs 作用域链:
2个作用:
1. 存储着所有不用.就可访问的变量
2. 控制着变量的使用顺序,先局部,后全局
js内置类型: 11种:
Number String Boolean
Array Date RegExp Math
Error
Function Object
global(在浏览器中被更名为window)
自定义继承:
何时: 如果默认的爹不是想要的,可更改
如何: 2种:
1. 仅修改一个对象的父对象:
child.__proto__=father
设置child的爹为father
Object.setPrototypeOf(child, father)
2. 同时更换多个子对象的爹
更换妈妈的老公
Student.prototype=father
讲究时机: 必须在创建子对象之前换!
多态:
什么是: 一个函数在不同情况下表现出不同的状态
包括2种情况:
1. 重载
2. 重写(override):
什么是: 如果子对象觉得从父对象继承来的成员不好用,可在子对象本地创建同名成员,覆盖父对象中的成员。使用时,只要自己有,就先用自己的。
何时: 觉得从父对象继承来的成员不好用
如何: 只要在对象本地定义与父对象中同名的成员,即可。
2. ES5:
ECMAScript 第5个版本
1. 严格模式:
什么是: 比普通js运行机制,要求更严格的模式
为什么: js语言本身具有很多广受诟病的缺陷
何时: 今后所有的js程序,必须运行在严格模式下!
如何:
在当前作用域的顶部写:"use strict";——启用严格模式
规定:
1. 禁止给未声明变量赋值:
2. 静默失败升级为错误:
什么是静默失败: 执行不成功,但还不报错。
ES5中规定,所有静默失败,都升级为报错!
3. 匿名函数自调和普通函数调用中的this,不再指向window!而是this=undefined。
Day06 ES5 ES6
正课:
1. ES5
2. ES6
1. ES5:
Object.create() 没有构造函数,仅依靠父对象,就能创建子对象。
如何: var child=Object.create(father,{
//为child添加自有属性
//用defineProperties的语法
属性名:{
value:属性值,
writable:true,
enumerable:true,
configurable:false
}
})
1. 创建子对象child
2. 自动设置子对象继承父对象father
3. 为子对象child添加自有属性
// Object.create做的事情
// 01自动创建新的空对象hmm
// 02自动设置hmm继承father
// 03为hmm添加*属性
var father={
money:100000,
car:"benchi"
};
var hmm=Object.create(father,{
phone:{
value:"iphone",
Writable:true,
enumerable:true,
configurable:false
},
bao:{
value:"lv",
writable:true,
enumerable:true,
configurable:false
}
});
console.log(hmm)
console.log(hmm.money)
console.log(hmm.car)
call apply bind 换函数中的this
1. call apply 在本次调用时,临时替换函数中的this为指定的对象
calc.call(lilei,10000,1000,2000)
用lilei调用calc,并传入参数10000,1000,2000
//默认this->window
//call将this->lilei
apply只比call多一个功能: 打散数组类型的参数为单个值
2. bind: 永久绑定this和部分参数值:
何时: 只要希望永久绑定this,反复使用
今后,只要回调函数中的this,要更换,都用bind
因为回调函数被调用几次,不确定
如何:
1. 绑定:
var lcalc=calc.bind(lilei,10000);
基于原函数calc,创建一个一模一样的新函数,并永久替换函数中的this为lilei,永久替换函数的第一个参数base为10000,最后将新函数保存到变量lcalc中
2. 调用lcalc: 不用重复传入对象和已经绑定的参数值
lcalc(1000,2000) // Li Lei的总工资是 13000
数组API:
1. 查找元素的位置:
回顾: var i=str.indexOf("关键词",starti)
数组中: var i=arr.indexOf(元素值, starti)
在arr数组中,查找starti位置后的下一个"元素"出现的位置
返回值: 如果找到,返回元素的下标i
如果没找到,返回-1
2. 判断数组是否由规定的内容组成:
1. 判断是否所有元素都符合要求
var bool=arr.every(function(elem, i, arr){
//elem:当前元素值
//i : 当前位置
//arr : 当前数组对象
return 根据elem,i,和arr判断当前元素是否符合要求
})
2. 判断是否包含符合要求的元素
var bool=arr.some(function(elem, i, arr){
return 判断条件
}
只要包含符合条件的元素,就返回true
3. 遍历API: 依次取出数组中的每个元素值,执行相同的操作
1. forEach: 对原数组中每个元素执行相同的操作
arr.forEach(function(elem,i,arr){
//对当前元素执行相同操作
})
2. map: 依次取出原数组中每个元素值,执行相同操作后,放入新数组中返回
var evens=arr.map(
//newArr=[]
for( ... ... ){
function(elem,i,arr){
↓
return 新值
} ↓
//newArr[ 2 4 6 ]
}
//return newArr;
)
结果: evens=newArr=[2 , 4, 6]
遍历索引数组:for forEach
遍历类数组对象:for
遍历对象和关联数组: for in
保护原数组,并生成新数组: map——只有索引数组
4. 过滤和汇总:
过滤: 复制出原数组中符合条件的元素,组成新的子数组返回。原数组保持不变。
var subArr=arr.filter(funtion(elem,i,arr){
return 判断条件
})
结果: filter会拿着回调函数去每个元素上执行一次,只有符合判断条件的元素,才会被复制出来,放入新数组返回
汇总: 对数组中的所有元素进行统计和分析,得出最终结论
var result=arr.reduce(
function(prev, elem, i, arr){
//prev: 是截止目前的临时汇总值
return 截止目前元素的临时汇总值
},
起始值
)
补: 按值传递: 两个变量间赋值时,其实都是将原变量中的值复制一个副本给对方
1. 如果传递的是原始类型的值: number string bool null undefined
将原始值复制一个副本给对方,修改新变量的值,不影响原变量
2. 如果传递的是引用类型的值: 数组,日期,自定义对象
只是将地址值复制给新变量。形成两个变量用相同的地址指向同一个对象。任何一方修改对象,另一方都会受影响
2. ES6:
let 代替var,用于声明变量:
var的两个问题:
1. 声明提前
2. 没有块级作用域
let的优点:
1. 阻止声明提前
2. 添加块级作用域,让if else if else while for ...都变成了作用域
let的原理:
let a=100;
相当于:
(function(){
var _a=100;
...
})()
参数增强:
1. 默认值default:
何时: 只要一个形参,将来不传值,也希望有一个默认值作为备胎时
1. 定义函数时:
function calc(bonus1,bonus2,base=10000){
}
坑: 有默认值的形参必须放在参数列表末尾!
一般情况下只能有一个
2. 调用时:
calc(5000,6000,4000) base=4000
calc(5000,6000) base=10000
2. 剩余参数rest: 代替arguments
何时: 只要不确定参数的个数时,都用rest
arguments的问题:
1. 不是纯正的数组,无法使用数组家的API
2. 只能接收所有参数,无法有选择的接收参数
rest的优点:
1. 是纯正的数组,可使用数组家所有API
2. 可有选择的接收部分参数
如何:
1. 定义时:
function calc(ename, ...salary){
salary会接住除ename之外的所有剩余参数
且salary是纯正的数组
}
2. 调用时:
除ename外,再传多少个参数都会被salary数组接收
3. 打散spread: 将数组类型的参数,打散为多个值传入函数
何时: 函数希望多个值分别传入,但给定的多个值却放在数组中
如何:
var arr=[2,6,7,1];
Math.max(...arr) //7
在调用函数时...可将数组打散为多个参数值,分别传入
箭头函数: 对一切函数的简化!
如何:
1. 去掉function,变为=>
2. 如果形参列表只有一个形参,可省略()
3. 如果函数体只有一句话,可省略{}
但如果仅有的一句话还是return,则必须省略return
箭头函数的特点: 内外this通用!
如果希望内外this相同时,可改为箭头函数
如果不希望内外this相同时,就不能改箭头函数
比如: 对象的方法,事件处理函数
day 07
正课:
1. ES5
2. ES6
1. ES5
call/apply/bind
什么是: 替换函数中不想要的this为指定的对象
何时: 如果函数执行时,其中的this不是想要的,都要替换this为想要的对象
如何:
1. call/apply
在本次调用函数时,临时替换函数中的this为指定对象
本次调用后,替换失效。
call: 任意函数.call(任意对象, 实参值列表...)
让任何一个对象,可临时调用任何一个不相干的函数,并传入实参值列表。
比如: calc.call(lilei,10000,2000,3000);
用lilei调用calc函数,并传入10000,2000,3000三个参数值。
apply: 如果实参值列表是以数组形式给的,则必须将call
换成apply
如何: var arr=[10000,2000,3000] //实参值列表
calc.apply(lilei, arr)
用lilei调用calc,但是会打散数组参数为单个值
比如: arr=[10000,2000,3000]
calc.apply(lilei, arr )
打散数组 ↓ ↓ ↓
等效于: calc.call(lilei, 10000,2000,3000)
结果: this base bonus1 bonus2
2. bind:
什么是: 基于原函数,创建一个新函数,并永久绑定this
何时: 如果函数中的this,需要反复被替换,就用bind创建一个新的专属的函数。永久绑定this。
如何: var 新函数=原函数.bind(对象, 要绑死的实参值,...)
比如: var calc_l=calc.bind(lilei, 10000)
创建一个和calc一模一样的新函数calc_l,并永久替换calc_l中的this为lilei对象,并永久替换第一个参数base为10000。
好处: 今后反复使用calc_l不用再反复传入lilei和10000.
强调: bind仅创建新函数,不执行函数
要执行函数: calc_l(1000,2000)
//bonus1, bonus2
强调: 用bind创建的新函数中的this,不可能再被别人用call替换。因为bind后的函数中的this已经被替换成固定的对象了。所以再用call/apply已无this可换
总结:
当函数中的this不是想要的,想换成想要的
就用call/apply/bind
1. 当仅临时替换本次调用函数中的this时——call
当实参值列表是数组形式时,必须将call换成apply,自动打散数组为单个值
2. 如果一个函数需要反复替换this为一个指定的对象时,就用bind创建一个专属的新函数,永久绑定this为指定的对象,同时可绑定部分固定的参数值。
数组API:
ES5中为数组扩展了很多新的API
1. 数组中也有indexOf方法,查找一个指定元素的位置
用法同字符串.indexOf完全一样:
var i=arr.indexOf(要找的元素, [开始位置])
// 3 , 5
//从5位置开始找下一个3
在arr数组中,从starti位置开始,查找下一个指定元素的位置i
其中: starti可省略,默认从0位置开始找
如果找到匹配的,返回元素的下标位置
如果没找到,返回-1
比如:
var str="1234321";
// 0123456
console.log(
//在arr中找第一个3的位置
str.indexOf(3/*,0*/),//2
//在arr中从3位置开始找下一个3的位置
str.indexOf(3,3),//4
//在arr中从5位置开始找下一个3的位置
str.indexOf(3,5),//-1 //找不到了
//在arr中找第一个5的位置
str.indexOf(5) //-1 //找不到
);
var arr=[1,2,3,4,3,2,1]
// 0 1 2 3 4 5 6
console.log(
//在arr中找第一个3的位置
arr.indexOf(3/*,0*/),//2
//在arr中从3位置开始找下一个3的位置
arr.indexOf(3,3),//4
//在arr中从5位置开始找下一个3的位置
arr.indexOf(3,5),//-1 //找不到了
//在arr中找第一个5的位置
arr.indexOf(5) //-1 //找不到
);
2. 判断: 判断数组中的元素是否符合要求
arr.every(条件) 判断数组中是否所有元素都符合条件
每个
arr.some(条件) 判断数组中是否包含符合条件的元素
一些
如何: 仅以every为例
var bool=arr.every(function(elem, i, arr){//规定
//elem: 自动获得当前位置上的元素值
//i: 自动获得当前位置下标i
//arr: 自动获得.前的数组对象
return 判断条件
//如果当前元素值elem,符合判断条件要求,返回true
//如果当前元素值elem,不符合判断条件,返回false
})
执行原理: every会自动遍历arr中每个元素,每遍历一个元素,就用回调函数在当前元素上执行一次。每次调用是都会自动给回调函数传入当前元素值、当前位置和当前数组对象。中途every会记录每个元素判断后得到的结果。最后,只有所有元素判断的结果都为true,整体才返回true。只要有一个元素的判断结果返回false,整体就返回false
比如:
var arr1=[1,2,3,4,5];
var arr2=[2,4,6,4,2];
//判断哪个数组全是偶数
console.log(
arr1.every(function(elem){
return elem%2==0
}),//false
arr2.every(function(elem){
return elem%2==0
})//true
);
day 08
正课:
1. ES6
1.ES6:
ECMAScript的第6个版本: 在不改变原理的基础上,尽量简化了代码。
let:
什么是: 专门代替var,用于声明变量用的关键词
何时: 今后所有的var,都用let代替
为什么:
var的两个缺点:
1. 声明提前: 打乱了程序正常执行的顺序
2. 没有块级作用域: 块内的变量很有可能提前到块外部,影响原本正确的外部的程序。
块: if(){ ... }else if(){ ... }else{ ... }
for(){ ... }
while(){ ... } do{ ... }while();
都是块,但都不是作用域
其内部的变量,都会被提前到块外对外部造成不可预期的影响。
比如:
var t=0;
function fun(){
t+=10;//原本就是想对全局t+10
}
fun();
console.log(t); //10
过了一段时间/其它人给函数中添加了一段不会执行的代码:
var t=0;
function fun(){
var t//undefined;
t+=10;//原本就是想对全局t+10
//因为有了局部变量t,就无法修改全局了
var err=false;
if(err){ //if根本没执行
//if不是作用域,拦不住内部的t被提前到外部函数的顶部
var t=new Date();
... ...
}
}
fun();
console.log(t); //0
结论: 今后所有的var都用let代替
let的两个作用:
1. 阻止声明提前: 在let a之前,不允许使用变量a
在程序中,相同范围内,不允许重复声明两个let a;
2. 让if while for do while块都变成作用域,块内部的变量无法提前到外部,也就不会影响外部。
let的原理: 其实let底层就是一个匿名函数自调
let相当于做了两件事:
1. 用匿名函数自调包裹当前范围内的剩余代码
2. 将let后的变量a,更名为_a
比如:
再比如:
for+let: 会形成闭包
for(let i=0;i<3;i++){
arr[i]=function(){console.log(i)}
//(function(_i){
//arr[_i]=function(){console.log(_i)}
//})(i)
}
箭头函数: 对所有函数定义的简写:
function 函数名(形参列表){ 函数体; return 返回值 }
var 函数名= function (形参列表){ 函数体; return 返回值 }
3句话:
1. 去function,在()和{}之间加=>
(形参列表)=>{ 函数体; return 返回值 }
2. 如果形参列表中只有一个形参,可省略()
形参1=>{ 函数体; return 返回值 }
3. 如果函数体只有一句话,可省略{}
形参1=>一句话
如果仅剩的一句话,还是return,必须去return
省略{}后,结尾的分号,必须省略
箭头函数的双刃剑: 箭头函数中的this,是内外通用的
比如:
var lilei={
sname:"Li Lei",
friends:["tom","jerry","jack","rose"],
intr:function(){
//this->lilei
this.friends.forEach(
function(name){//回调函数
//不加bind,回调函数中的this->window
console.log(`${this.sname} 认识 ${name}`);
}.bind(this) //加上bind才能将函数内部错误的this换成外部正确的this
)
}
}
如果觉得bind不直观,可改为箭头函数:
var lilei={//对象的{不是作用域!}
sname:"Li Lei",
friends:["tom","jerry","jack","rose"],
intr:function(){//这里的function不能改箭头,一旦改为箭头,this->window
//this->lilei
this.friends.forEach(
//内部的function可改为箭头函数,因为希望和外部的this通用!this->lilei
name=>console.log(`${this.sname} 认识 ${name}`)
)
}
}
总结: 如果希望内外this一致时,就可改为箭头函数,代替bind
如果不希望内外this相同时,就不可改为箭头函数。比如: 对象中的方法不能改箭头;事件处理函数不能改箭头
for of: 快速遍历一个数组的内容的最简化写法
总结: 遍历一个数组:
1. for循环
for(var i=0;i<arr.length;i++){
arr[i] //获得当前数组元素
}
最灵活的遍历,即可控制遍历的顺序,又可控制遍历的步调
2. forEach简化:
arr.forEach((elem,i)=>{
elem //当前数组元素
})
问题: 只能从头到尾依次遍历每个元素,不能控制顺序(从后向前或从前向后)和步调(2,4,6,... 5,10,15,... )
何时: 如果既关系内容,又关心位置,但不会改变遍历的顺序或步调时
3. for of更简化:
for(var elem of arr){
//of会依次取出索引数组中的每个元素值
elem //当前数组元素
}
问题:只能获得元素内容,无法获得元素位置
所以: 仅关心元素内容时,才用for of
vs for in
1. 使用场合: for of专门遍历索引数组
for in专门遍历关联数组
2. of vs in:
of只取元素值
in 只取属性
比如: var names=["亮亮","然然","东东"]
for(var name of names){
//of依次取出names数组中每个人名保存到前边的变量name中
console.log(name + " - 到!");
}
参数增强:
1. 默认值:
ES6中可以对形参列表中的最后一个形参设置默认值
何时: 如果只有最后一个形参不确定时
如何:
//定义函数find,在arr中查找指定元素出现的位置
//如果不给第三个参数,则默认从0位置开始找
//如果给第三个参数,则从给定的位置向后找
function find(arr,elem,starti){
/*方法一: if判断
if(starti===undefined){
starti=0;
}*/
//方法二: 短路
//starti=starti||0;//0是starti的备胎
//||会自动将前后转为boolean
//如果starti转换后不是false,就首选starti使用。如果starti转换后为false,就用0代替starti;
console.log(`在arr中,从${starti}位置开始,找下一个${elem}出现的位置...`);
}
//方法三: ES6的默认值
function find(arr,elem,starti=0){
//如果没有给starti传参,则自动用0代替!
console.log(`在arr中,从${starti}位置开始,找下一个${elem}出现的位置...`);
}
var arr=[];
find(arr,3);//从0位置开始
find(arr,3,5);//从5位置开始找
2. 剩余参数: 代替arguments
什么是: 让函数可以自动收集结尾多个不确定的参数值
何时: 如果在函数形参的结尾,有不确定个数的参数值传入,则可用剩余参数方式收集
为什么:
arguments: 2大缺点:
1. 不是纯正的数组类型对象,数组家的API一个都不能用
2. 只能收集所有参数值,无法有选择的收集部分参数值
如何: 2步:
1. 在定义函数时,在可以确定的形参后添加"...数组名"
2. 在函数内,"数组名"数组中,就自动收集了除已经确定的形参之外的剩余实参值。
比如:
定义函数时:
function calc(ename,...arr){
调用时:
calc("Li lei",10000,2000,3000);
//...arr[10000,2000,3000]
calc("Han Meimei",5000,1000,2000,3000);
//...arr[5000,1000,2000,3000]
优点: 1. 可有选择的获得部分实参值
2. arr是纯正的数组,数组家的API可以随便用!
3. 打散数组: 代替apply,专门用于打散数组类型的参数
何时: 只要函数需要多个零散的参数值,但给定的参数值却是放在一个数组中传入的,发生不一致,就要打散数组
apply一定有问题:
apply的主要目的是替换this,顺便打散数组
如果只希望打散数组参数,和this无关时,用apply就会很别扭.
比如: Math.max(arr)不支持数组中查找最大的元素
传统: 可用: apply打散数组类型参数为单个值
console.log(Math.max.apply(null,nums));
console.log(Math.max.apply(Math,nums));
console.log(Math.max.apply(nums,nums));
apply的第一个参数即没用,又必须写
解决: 不用apply,用...
如何: console.log(Math.max(...nums))
// 拆
...先将nums数组打散为单个值,再陆续传给max
总结:
1. 如果在定义函数时,形参列表中...arr,是收集剩余参数保存到数组的意思
2. 如果在调用函数时,在实参列表中...arr,作用是相反的,是打散数组为单个值,再传入。
解构:
什么是: 仅提取出一个大对象中的部分成员单独使用
何时: 如果只使用一个大对象中的一小部分成员时
如何: 3种情况:
1. 数组解构: 下标对下标:
var date=[2019,5,5];
/*var y=data[0]
var m=data[1]
var d=data[2]*/
var [y,m,d]=date;
y m d
2. 对象解构: 属性对属性:
比如:
var user={
uid:1001,
uname:"dingding",
set:1,
signin:function(){
console.log("登录...");
},
signout:function(){
console.log("注销...");
},
signup:function(){
console.log("注册...");
}
}
//var {uid:uid,signup:signup}=user;
var {uid,signup}=user;
console.log(uid);
signup();
原理:
3. 参数解构:
什么是: 在向函数中传参时,将一个大的对象,打散后,传递给对应的形参变量.
何时: 多个形参不确定时,又要求按顺序传入时、
为什么:
1. 默认值: 只能应对结尾一个参数不确定时
2. 剩余参数: 虽然可应对多个参数不确定的情况
但无法规定传入参数的顺序
比如:
function calc(ename, base,饭补, 高温,房补)
calc(lilei, 10000, , 200, 600)
calc(hmm, 10000, , , 200)
calc(jack, 10000, , 300, 500)
总结: 当多个形参都不确定时,且每个实参值必须对位传给指定的形参变量时,单靠调整形参的个数和顺序,无法满足所有调用的情况
解决: 参数解构:
如何: 2步:
1. 定义形参时,所有的形参变量都要定义在一个对象结构中
比如:
//1. 定义形参列表时,就用对象结构定义
function ajax({
//与顺序无关
url:url,
type:type,
data:data,//不确定
dataType:dataType//不确定
}){
console.log(`向${url}发送${type}请求`);
if(data!=undefined&&type=="get"){
console.log(`在url结尾拼接参数?${data}`)
}
if(data!=undefined&&type=="post"){
console.log(`xhr.send(${data})`);
}
if(dataType=="json"){
console.log(`JSON.parse(返回结果)`);
}
}
2. 调用函数传参时,所有实参值,都要放在一个对象结构中整体传入。
比如:
ajax({
url:"http://localhost:3000/products/getProductsByKwords",
type:"get",
data:"kw=macbook i5",
dataType:"json"
});
总结: 参数解构,其实就是对象解构在传参时的应用而已
day 09
正课:
1. ES6
1. ES6
OOP:
1. 对对象直接量的简写: 2处:
1. 如果对象的成员值来自于外部的变量,且属性名和变量名相同时,可只写一个:
比如: user.js
var signin=function(){ 登录... }
var signup=function(){ 注册... }
var signout=function(){ 注销... }
var obj={ signin:signin, signup:signup, signout:signout };
{ signin, signup, signout };
//将三个函数放在一个对象中导出export
module.exports=obj
2. 对象直接量中方法的定义不需要加":function"
为什么: 对象中的方法,不能用箭头函数简写。一旦简写,方法中的this不再指向当前对象,很可能指向全局的window。
比如:
var lilei={
sname:"Li Lei",
intr:function(){//不能改成箭头函数
... this.sname ...
}
}
解决:
var lilei={
sname:"Li Lei",
intr (){//不要加箭头
//等效于intr:function(),可保持this不变!
... this.sname ...
}
}
2. class
什么是class:
用途: 描述一类事物统一属性结构和功能的程序结构
本质: 其实就是以前的构造函数+原型对象的整体
为什么: 因为构造函数和原型对象分开的写法不符合封装的含义。
如何: 3句口诀
//1. 用class{}包裹构造函数和原型对象方法
class Student{
//2. 构造函数名提升成类型名,所有构造函数更名为constructor
constructor(sname,sage){
this.sname=sname;
this.sage=sage;
}
//3. 所有方法不再需要prototype前缀,不再需要=function
intr(){
console.log(`I'm ${this.sname}, I'm ${this.sage}`);
}
}
class的用法和存储结构跟ES5中构造函数创建的对象用法和存储结构是完全相同的
3. class之间的继承:
问题: 两种类型之间存在部分相同的属性结构和方法定义,代码可能出现重复编写。
解决: 定义抽象父类型: 2步:
1. 定义抽象父类型集中定义多个子类型共有的属性和方法
1.1 在父类型的构造函数中仅定义相同部分的属性
1.2 在父类型原型对象中仅定义相同部分的方法
2. 让子类型继承父类型:
2.1 子类型使用extends继承父类型
2.2 子类型构造函数中先用super调用父类型构造函数
比如:
//定义敌机类型
//所有敌机都有名称,速度和分值三个属性
//所有敌机都可以飞行,击落敌机可以得分
//定义蜜蜂类型
//所有蜜蜂都有名称,速度和分值三个属性
//所有蜜蜂都可以飞行,击落蜜蜂可以的奖励
//但是,因为敌机和蜜蜂两种类型拥有部分相同的属性和方法,导致代码重复,不便于日后维护
//所以,应该先定义抽象父类型"敌人类型",集中保存两种子类型部分相同的属性和方法。
class Enemy{
//抽象父类型构造函数中集中保存所有子类型共有的属性部分
constructor(fname,speed){
this.fname=fname;
this.speed=speed;
}
//抽象父类型原型对象中集中保存所有子类型共有的方法
fly(){
console.log(`${this.fname}以时速${this.speed}飞行`);
}
}
//子类型必须继承(extends)父类型,才能获得父类型中的方法
class Plane extends Enemy{
//子类型构造函数中:
constructor(fname,speed,score){
//先借用父类型构造函数(super)帮忙添加共有的属性部分
super(fname,speed);//Enemy中的constructor()
//再自己添加本类型自有的独特的属性
this.score=score;
}
//Prototype中:只定义自己类型特有的方法即可,不必定义相同部分的方法。
getScore(){
console.log(`击落${this.fname}得${this.score}分`);
}
}
class Bee{
constructor(fname,speed,award){
this.award=award;
}
getAward(){
console.log(`击落${this.fname}获得${this.award}奖励`);
}
}
var f22=new Plane("F22",1000,5);
//表面上f22是Plane一个妈妈创建的,但是其实f22中三个属性:fname和speed是奶奶给的,只有score才是妈妈给的。是两个人合作创建的f22对象。
console.log(f22);
f22.fly();
f22.getScore();
var bee=new Bee("小蜜蜂",50,"1 life");
console.log(bee);
bee.fly();
bee.getAward();
Promise:
什么是: 专门实现异步函数,顺序执行的一种机制
为什么: 避免回调地狱
何时: 多个异步函数,必须顺序执行时
如何:
2步:
1. 定义异步函数内:
function liang(){
return new Promise(function(open){
亮要执行的所有代码(包含异步代码)
//当亮的任务执行完,自动打开open()
//当open(),自动执行下一个then中的函数
})
}
2. 多个支持promise的异步函数,用.then串联起来
liang().then(ran).then(dong).then(function(){结束})
用class对构造函数和原型对象的封
DOM&BOM
day 01
正课:
1. 什么是DOM:
2. DOM Tree:
3. 查找元素:
1. 什么是DOM: document object model
什么是: 专门操作网页内容的一套对象和函数的集合
DOM其实是一个标准: W3C制定的,规定了所有浏览器操作网页内容的API统一标准。
为什么: 1. DOM是操作网页内容的唯一办法!
2. DOM标准几乎所有浏览器100%兼容.
何时: 今后只要操作网页的内容,只能用DOM
包括:
查找元素,修改元素,添加元素,删除元素,事件绑定
2. DOM Tree:
什么是: 内存中保存网页中所有内容的树形结构
网页中的一切内容,在内存中,都是保存在一棵DOM树中
为什么: 网页中的内容是父子级嵌套的包含关系
树形结构是最直观的描述上下级包含关系。
如何:
1. 当浏览器读取到一个html内容时
先在内存中建立一个树根节点: document
document就代表整个网页
document.write("xxx") 向网页中写入一句话
2. 浏览器一边扫描HTML内容,一边在DOM树上创建节点对象
网页中每项内容都是DOM树上的一个节点对象
3. 查找元素: 4种:
1. 不需要查找,就可直接访问的元素:
document
document.documentElement -> <html>
document.head -> <head>
document.body -> <body>
提示: 在控制台中输出元素节点,仅输出DOM树结构,而不是输出节点对象
如果确实需要查看一个元素对象的属性: console.dir(元素)
2. 按节点间关系查找:
节点树: 包含所有网页内容的完整树结构
2大类关系:
1. 父子: 4种:
元素.parnetNode 获得元素的父节点
父元素.childNodes 获得父元素下的所有直接子节点的集合
返回: 多个平级子元素组成的类数组对象
父元素.firstChild 获得父元素下的直接子节点中第一个节点
父元素.lastChild 获得父元素下的直接子节点中的最后一个节点
2. 兄弟: 2种:
元素.previousSibling 获得元素的前一个平级的兄弟节点
前一个 兄弟
元素.nextSibling 获得元素的下一个平级的兄弟节点
下一个兄弟
问题: 网页中一切内容都是节点,包括看不见的空格,换行都是节点对象,极大的干扰查找!
解决: DOM出了一种新的树:
元素树: 仅包含元素节点的树结构
优点: 不会受看不见的空字符干扰查找!
2大类关系:
1. 父子: 4种:
元素.parentElement 获得元素的父元素
和parentNode几乎通用
因为能当爹的一定是元素
父元素.children 获得父元素下的所有直接子元素的集合
返回: 多个直接子元素组成的类数组对象
父元素.firstElementChild 获得父元素下的直接子元素中第一个元素
父元素.lastElementChild 获得父元素下的直接子元素中的最后一个元素
2. 兄弟: 2种:
元素.previousElementSibling 获得元素的前一个平级的兄弟元素
元素.nextElementSibling 获得元素的下一个平级的兄弟元素
何时使用按节点间关系查找:如果已经站在DOM树的某个节点上了,想找周围附近的节点时,首选按节点间关系查找,且必须用元素树。不要用节点树。
day 02
正课:
1. 查找
2. 修改
1. 查找: 4种:
1. 不需要查找就可直接获得的元素: 4个
document 根节点对象
document.documentElement 根元素对象<html>
document.head <head>元素对象
document.body <body>元素对象
2. 按节点间关系查找: 2大类关系,6个属性
何时: 已经站在树上的一个节点上了。
1. 父子关系:
元素.parentElement 获得元素的父元素
.parentNode
元素.children 获得元素的所有直接子元素
返回: 所有直接子元素对象组成的类数组对象
元素.firstElementChild 获得元素的第一个直接子元素
元素.lastElementChild 获得元素的最后一个直接子元素
2. 兄弟关系:
元素.previousElementSibling 获得元素的前一个相邻的平级兄弟元素
元素.nextElementSibling 获得元素的后一个相邻的平级兄弟元素
问题: 不可能所有的查找都从body为起点,一旦元素藏的很深,代码会很繁琐
3. 按HTML特征查找:
何时: 首次查找元素时
包括: 4个函数:
1. 按id查找:
var elem=document.getElementById("id")
获得 元素 按 id
强调: 1. .前的主语必须是document
2. 仅返回一个匹配的元素对象
如果找不到: 返回null
2. 按HTML标签名查找:
var elems=任意父元素.getElementsByTagName("标签名")
获得 元素们 按标签 名
<标签>
强调: 1. .前的主语可以是任意父元素
比如: table.getElementsByTagName("tr")
只查找当前table下的所有tr元素对象
ul.getElementsByTagName("li")
只查找当前ul下的所有li元素对象
2. 返回当前父元素下所有符合条件的元素的类数组对象。如果找不到,返回空的类数组对象([].length=0)
3. 不仅查找直接子元素,且在所有后代中查找
比如:
<ul> ul.getElementsByTagName("li") 8个
<li>
<ul> ul.getElementsByTagName("li") 3个
<li>
<li>
<li>
</ul>
</li>
<li>
<ul>
<li>
<li>
<li>
</ul>
</li>
3. 按name属性查找:
只有表单中要将值回发给服务器端的元素,才有name属性。name属性会成为回发服务端时的变量名
比如: <form>
<input type="text" name="uname"/>
<input type="password" name="upwd"/>
<input type="submit">
提交时: http://xxxx/接口?uname=xxx&upwd=xxx
何时: 几乎专门用于查找表单中的表单元素
如何:
var elems=document.getElementsByName("name");
强调: 1. .前的主语必须是document
2. 返回多个元素组成的类数组对象
如果找不到,返回[].length=0
比如:
<input type="radio" name="sex" value="1"/>男
<input type="radio" name="sex" value="0"/>女
var elems=document.getElementsByName("sex");
elems:[ <input> , <input> ]
坑:
<input type="text" name="uname"/>
<input type="password" name="upwd"/>
<input type="submit">
var txtName=document.getElementsByName("uname")
希望只获得<input>姓名文本框对象
但无论在任何情况getElementsByName都返回一个类数组对象,即使只找到一个元素对象,也必须放在类数组对象中返回。
var elems=document.getElementsByName("uname");
elems: 类数组对象 [ <input> ] != <input>对象
[0]
如果想获得input姓名文本框对象,需要再多写一步下标
var txtName=elems[0];
4. 按class属性查找:
var elems=任意父元素.getElementsByClassName("class名")
强调: 1. .前可以是任意父元素
2. 返回所有符合条件的后代元素的集合
如果找不到返回空集合:[].length=0
3. 不仅查找直接子元素,且在所有后代中查找符合条件的。
比如:
<ul> ul.getElementsByClassName("child") 6个
<li class="parent">
<ul> ul.getElementsByClassName("child") 3个
<li class="child">
<li class="child">
<li class="child">
</ul>
</li>
<li class="parent">
<ul>
<li class="child">
<li class="child">
<li class="child">
</ul>
</li>
4. 如果一个元素被多个class修饰,只使用其中一个class就可以找到元素
<div class="alert alert-danger">
var elems=父元素.getElementsByClassName("alert")
父元素.getElementsByClassName("alert-danger")
都返回: 类数组对象: [ <div>对象 ].length=1
[0]
如果只想获得唯一的div元素对象:
必须再多写一步下标:
var div=elems[0]
总结: 4种查找方式:
1. 按id查找:
var elem=document.getElementById("id")
2. 按标签名查找:
var elems=父元素.getElementsByTagName("标签名")
3. 按name属性查找:
var elems=document.getElementsByName("name")
4. 按class属性查找:
var elems=父元素.getElementsByClassName("class")
4. 其实js中也可以使用选择器查找元素: 2个函数:
1. 如果确定只找一个元素:
var elem=任意父元素.querySelector("任意复杂选择器")
2. 如果查找多个元素:
var elems=任意父元素.querySelectorAll("任意复杂选择器")
按选择器查找,效率不如按HTML特征查找
总结:
1. 如果仅靠一个条件就可查找到想要的元素:
首选按HTML查找——快
2. 如果查找条件复杂
首选按选择器查找——简单
2. 修改
内容:
1. 获取或修改元素开始标签到结束标签之间的原始HTML片段: 元素.innerHTML
2. 获取或修改元素开始标签到结束标签之间的纯文本内容: 元素.textContent
vs 元素.innerHTML 多干两件事:
1. 去掉所有内嵌标签
2. 将特殊符号翻译为正文
3. 所有表单元素的值,都必须用.value才能获得
样式:
1. 如果修改内联样式:
元素.style.css属性="属性值"
比如: div.style.display="none"; 隐藏
相当于: <div style="display:none">
div.style.display="block"; 显示
相当于:<div style="display:block">
div.style.width="400px" 必须加单位
相当于: <div style="width:400px">
特例: 如果css属性名包含-,则必须去横线,变驼峰
首字母小写,之后每个单词首字母大写
修改元素的背景图片:
div.style.backgroundImage="url(...)"
相当于: <div style="background-image:url(...)">
属性: 3种:
1. HTML标准属性: HTML标准中规定的,所有HTML元素都具有的属性: 比如: title, class, id, value, name ... ...
2种方式修改:
1. 最早的一批核心DOM函数: 4个
1. 获取一个元素指定属性的值:
元素.getAttribute("属性名")
比如: <a href="http://tmooc.cn" target="_blank">
a.getAttribute("href")
-> "http://tmooc.cn"
2. 修改一个元素指定属性的值:
元素.setAttribute("属性名","新值")
比如: a.setAttribute("target","_self")
结果: <a href="http://tmooc.cn" target="_self">
3. 判断是否包含指定属性:
var bool=元素.hasAttribute("属性名")
比如: a.hasAttribute("target") => true
a.hasAttribute("title") => false
4. 移除属性:
元素.removeAttribute("属性名")
比如: a.removeAttribute("target")
结果: <a href="http://tmooc.cn">
问题: 太长!
2. 使用HTML DOM提供的属性:
HTML DOM在核心DOM基础上,对常用的属性和元素对象提供了部分简写的代码
福利: HTML DOM已经将所有标准属性提前定义在了内存中的元素对象上!可直接用元素.属性名获取或修改。
比如: <a href="http://tmooc.cn" target="_blank">
其实: a在内存中:
a:{
id:"",
href:" http://tmooc.cn ",
target:" _blank ",
title:"",
name:""
}
所以: 获取a的href: a.href
修改a的target: a.target="_self"
判断a是否包含title: a.title!=""
移除a的target: a.target="";
特例: class属性
ECMAScript中规定: 所有js对象内部都有一个隐藏的class属性,记录当前对象的类型名: "[object Object]"
class
如果ECMAScript标准中已经提前规定过了class属性另有用途。则DOM标准中不能重复定义class属性
所以DOM标准规定class属性一律更名为className
访问元素的className属性,其实就是在访问<标签 class="">
/所有DOM效果的固定套路:
//1. 查找触发事件的元素
var d2=document.getElementById("d2");
//2. 为元素绑定事件处理函数
d2.onclick=function(){
//3. 查找要修改的元素
var d1=document.getElementById("d1");
var d2=this;
//4. 修改元素
//如果d2的内容是<<,就关闭
if(d2.innerHTML=="<<"){
//d1.style.display="none";
d1.style.width="0px";
d2.innerHTML=">>";
}else{//否则, 就打开
//d1.style.display="block";
d1.style.width="64px";
d2.innerHTML="<<";
}
}
2. 四大状态属性:
3. 自定义扩展属性:
day 03
正课:
1. 修改:
2. 添加/删除元素:
3. HTML DOM常用对象:
1. 修改:
内容: .innerHTML .textContent .value
属性:
1. 标准属性: 2种:
1. 核心DOM: 4个函数:
.getAttribute() .setAttribute() .hasAttribute()
.removeAttribute();
坑: 核心DOM 仅对字符串类型的属性起作用
2. HTML DOM: 元素.属性名
2. 三大状态属性: disabled selected checked
值都是bool类型,不能用核心DOM函数
只能用.操作:
比如: //想启用按钮
btn.setAttribute("disabled",false) 无效
应该: btn.disabled=false;
再比如: //想判断一个checkbox复选框是否选中:
应该: if(chb.checked==true) 可简写为 if(chb.checked)
补充: CSS中有三大状态伪类:
:checked :selected :disabled
专门选择处于某种状态的元素
3. 自定义扩展属性:
什么是: 开发人员自行添加在元素开始标签中的,HTML标准中没有的属性。
何时: 2个典型的场景
1. 代替id, class和元素选择器,用于选择触发事件的元素
2. 在网页中临时缓存业务数据
如何使用自定义扩展属性:
1. 在html开始标签中手动添加定义扩展属性:
<ANY data-属性名="属性值"
比如: <a href="#" data-trigger="tab"
2. 用js为元素添加自定义扩展属性:
不能用.添加: 因为自定义扩展属性不是标准属性,内存中的元素对象上没有!
只能用核心DOM函数添加
a.setAttribute("data-trigger","tab")
等效于: <a href="#" data-trigger="tab"
3. 读取自定义扩展属性的值:
不能用.来读取自定义扩展属性
因为自定义扩展属性不是标准属性,没有提前定义在内存中的元素对象上
只能用核心DOM的函数来获取自定义属性的值
a.getAttribute("data-自定义属性")
样式:
1. 修改内联样式: 元素.style.css属性名="属性值"
强调: 1. css属性名中如果包含-,必须去横线变驼峰
修改div的z-index为11
div.style.z-index=11;
应该: div.style.zIndex=11;
2. 如果css属性值包含单位,必须添加单位
修改: ul的高:
ul.style.height="106px"
问题: 如果同时修改一个元素的多个css样式属性,代码会很繁琐
解决: 如果批量修改一个元素的多个css样式时,都是先将样式定义在一个css的class中,再在js中只修改class属性即可.
总结:
内容: .innerHTML .textContent .value
属性:
1. 标准属性: 核心DOM四个函数 或 . 都行
2. 状态属性: disabled selected checked
只能用.改
3. 自定义扩展属性:
只能用.getAttribute("data-属性名")
.setAttribute("data-属性名",值)
样式:
1. 修改内联样式: 元素.style.css属性名="值"
2. 如果批量修改样式,最好用 .className="xxx"
2. 添加/删除
1. 添加新元素: 3步
1. 创建新的空元素:
var a=document.createElement("a")
结果: <a></a>
2. 为新元素添加必要的属性
a.innerHTML="go to tmooc";
a.href="http://tmooc.cn"
结果: <a href="http://tmooc.cn"> go to tmooc </a>
3. 将新元素挂载到DOM树的指定父元素下:
为什么: 浏览器显示网页内容是根据DOM树上的节点对象画出来的。如果DOM树上的节点不变化,则浏览器不回重绘页面。
要想让浏览器将新元素画出来,只能新元素添加到DOM树的指定位置,改变DOM树,才会触发浏览器的重绘操作。
如何: 3个函数:
1. 追加到指定父元素下的末尾
父元素.appendChild(a)
2. 插入到指定元素之前
父元素.insertBefore(a,child)
将a插入到父元素下的child元素之前
3. 替换现有元素
父元素.replaceChild(a, child)
用a替换父元素下的child元素
优化: 尽量减少操作DOM树的次数,避免重绘
为什么: 每修改一次DOM树,页面会重绘一次
解决: 2种情况:
1. 如果同时添加父元素和子元素到DOM树
应该先在内存中将子元素全部添加到父元素中
最后将整个父元素一次性添加到DOM树上
只会触发一次重绘!
打开新连接的方式
网页跳转
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>打开新链接方式总结</title>
<script>
/*打开新链接方式总结:
1. 在当前窗口打开,可后退
2. 在当前窗口打开,不可后退
3. 在新窗口打开,可打开多个
4. 在新窗口打开,只能打开一个
*/
function fn(){
open("http://www.baidu.com" ,"_self");
}
</script>
</head>
<body>
<a href="javascript:fn()">在当前窗口打开,可后退</a>
</body>
</html>
网页的跳转
Day 04
正课:
1. 添加/删除
2. HTML DOM常用对象
3. BOM
4. ***事件
1. 添加/删除:
优化: 尽量减少操作DOM树的次数
1. 如果同时添加父元素和子元素时
应先将子元素都添加到父元素中
最后,再一次性将整个父元素加入DOM树
结果: 浏览器只重绘一次
2. 如果父元素已经在页面上了,要添加多个平级子元素
应先将平级子元素添加到文档片段对象中
最后,再一次性将文档片段对象添加到DOM树
结果: 浏览器也只重绘一次
什么是文档片段: 内存中临时保存多个子元素的虚拟父元素对象
何时使用: 只要向页面中添加多个平级子元素时
如何: 3步:
1. 创建文档片段:
var frag=document.createDocumentFragment();
创建 文档 片段
2. 将子元素添加到文档片段中
frag.appendChild(child)
3. 将整个文档片段添加到DOM树
父元素.appendChild(frag)
删除元素: 父元素.removeChild(child)
2. HTML DOM常用对象
Image Select/Option Table/... Form/表单元素
Image对象: 就代表页面上一个<img>元素
唯一的简化:
创建一个<img>元素: var img=new Image();
等效于: var img=document.createElement("img")
结果: <img>
Select对象: 代表页面上一个<select>元素
属性:
select.selectedIndex : 获得当前选中项的下标
select.value: 获得select中当前选中项的内容/值
如果选中的option有value,则优先返回value,如果选中的option没有value,则返回innerHTML内容代替
select.options: 获得select下所有的option元素对象组成的集合。
select.options.length 获得select下所有option元素对象的个数
select.length: 等效于select.options.length
比如: 强行select.length=0; 会清空select
Option:代表select元素下的每个option元素对象
简化: 创建:
var opt=new Option(innerHTML, value)
Table对象: 代表页面上一个table元素
Table是个大家族,采用逐级管理的方式:
Table管着行分组:
Table可添加行分组: var thead=table.createTHead();
等效于: var thead=document.createElement("thead")
table.appendChild(thead);
var tbody=table.createTBody()
var tfoot=table.createTFoot();
删除行分组: table.deleteTHead();
table.deleteTFoot();
获取行分组: table.tHead
table.tFoot
table.tBodies[i]
行分组管着行:
行分组可添加行: var tr=行分组.insertRow(i)
在行分组内i位置,添加并插入一个新行
原位置的行不是替换,而是向后顺移一位
固定套路:
1. 末尾追加一个新行
var tr=行分组.insertRow()
2. 在开头插入一个新行:
var tr=行分组.insertRow(0)
行分组可删除行: 行分组.deleteRow(i)
坑: i要求是行在行分组内的相对下标位置
问题: 行在行分组内的相对下标位置无法自动获得
解决: 今后删除行不要用行分组
应该直接用table对象.deleteRow(i)
因为i要求是行在整个表中的下标位置
又因为行在整个表中的下标位置可用tr.rowIndex自动获得,所以,今后删除行的标准写法:
table.deleteRow(tr.rowIndex);
行分组可获取行: 行分组.rows[i]
行管着格:
行可以添加格: var td=tr.insertCell(i)
固定套路: 在行末尾追加新格:
var td=tr.insertCell()
问题: insertCell只能创建td,不能创建th
行可以删除格: tr.deleteCell(i)
行可以获取格: tr.cells[i]
补充: DOM中三大对话框:
alert confirm prompt
警告 确认 输入
Form对象: 代表页面上一个<form>元素
获取: 也不需要查找,就可直接获得:
浏览器已经将网页中所有form元素保存在了document对象的forms集合中: var form=document.forms[i]
如果网页中只有一个表单,则document.forms[0]
属性: form.elements 获得表单中所有表单元素的集合
form.elements.length 获得表单中表单元素的个数
form.length 等效于 form.elements.length
获得表单中倒数第二个表单元素——提交按钮:
var btnSubmit=form.elements[form.length-2]
表单元素对象: <input> <button> <select> <textarea>
获取: 如果要获取的表单元素有name属性
可用: form.name名
3. BOM: Browser Object Model
什么是: 专门操作浏览器窗口或软件的一套对象和函数
何时: 如果想操作浏览器窗口,或访问浏览器软件相关的配置信息
如何:
包括:
window: 2个角色:
1. 代替ES标准中的global充当全局作用域对象
2. 保存所有除ES外的DOM和BOM的对象和函数库
包括:
全局的BOM函数和属性:
alert() confirm() prompt() window.open() window.close() ... ...
掌控特定功能的对象:
location对象 专门掌控地址栏
history对象 掌控着前进/后退/刷新
navigator对象 掌控着浏览器的配置信息
document对象 掌控着网页的所有内容
screen 对象 掌控着和显示屏有关的信息
event对象 掌控着浏览器中发生的所有事件
window中常用的全局函数或属性:
1. 对话框: alert() confirm() prompt()
2. 窗口大小:
2组:
1. 完整窗口大小: window.outerWidth/outerHeight
2. 文档显示区: window.innerWidth/innerHeight
文档显示区: 浏览器窗口内专门用于显示网页内容有限的白色区域。
3. 打开和关闭窗口:
打开窗口: window.open() 和<a>的用法几乎完全一样
总结: 用程序打开新链接有几种效果:
1. 在当前窗口打开,可后退:
html: <a href="url" target="_self">
js: open("url" , "_self")
2. 在当前窗口打开,禁止后退:
js: location.replace("新url")
用新url代替history中当前旧的url,保持history中只有一条记录。从而禁止后退。
3. 在新窗口打开,可同时打开多个:
html: <a href="url" target="_blank">
js: open("url" , "_blank")
4. 在新窗口打开,只能打开一个:
html: <a href="url" target="自定义窗口名">
js: open("url" , "自定义窗口名")
在浏览器中,每个窗口都有内置的name属性来唯一标识一个窗口
浏览器规定,相同name名的窗口只能打开一个。
其实target属性,是在给新窗口起名
如果target的名字是自定义的名称,则新打开的窗口,只能开一个。不能重复开。
但是,target有两个内置的名称:
_self: 用当前窗口自己的名字,给新窗口,导致新窗口覆盖现有窗口
_blank: 不给新窗口指定任何名称,浏览器会自动随机分配新窗口的名称。导致新窗口的名称不会重复
关闭窗口: window.close()
history: 保存当前窗口打开后,成功访问过的url的历史记录的集合。
何时: 用程序执行前进,后退,刷新
如何: history.go(1) 前进一步
history.go(0) 刷新
history.go(-1) 后退一步
location:
什么是location: 专门保存当前正在打开的url的信息的对象
何时: 1. 获得url地址栏中各个部分的参数时
2. 通过操作地址栏中的地址实现跳转和刷新时
如何:
1. 获得url中的各个部分:
http://localhost:3000/public/products.html#top?kwords=macbook
协议 主机 端口 相对路径 锚点 查询字符串
location.href 完整url
location.protocol 协议部分
location.host 主机名+端口号: localhost:3000
location.hostname 主机名 localhost
location.port 端口号 3000
location.pathname 相对路径 public/products.html
location.hash 锚点地址 #top
location.search 查询字符串 ?kwords=macbook
想进一步获得变量值: location.search.split("=")[1]
2. 通过操作地址栏实现跳转和刷新:
1. 在当前窗口打开新链接,可后退:
location.href="新url" <==> open("新url","_self")
2. 在当前窗口打开新链接,禁止后退:
location.replace("新url")
3. 刷新当前页面:
location.reload(); <==> history.go(0)
navigator:
什么是: 保存浏览器配置信息的对象
何时: 判断浏览器的名称和版本号
如何:
1. navigator的userAgent属性包含了浏览器的名称和版本号——字符串——没有标准
测试: window 10的 Edge浏览器
Day 05
事件对象e:当事件发生时,浏览器自动创建的,封装事件信息和操作事件的API 的对象;
事件对象—— 01可以封装事件的信息 02操作事件的API的
正课:
1. 事件:
1. 事件:
什么是: 浏览器自动触发的或用户手动触发的,页面中元素状态的改变。
事件发生时如何执行一项任务: 绑定事件处理函数
什么是: 当事件发生时自动调用的一个函数
本质: 是元素对象上一个事件名属性
比如: btn.onclick sel.onchange txt.onfocus
何时: 只要希望发生事件时自动执行一项任务
如何:
在事件发生前就提前绑定事件处理函数到元素的事件属性上。
如何绑定: 3种:
1. 在html中绑定:
html中: <ANY onclick="fun()">
js中: function fun(){ ... }
问题: 不符合内容与行为分离的原则,不便于维护
2. 在js中用赋值方式绑定:
js中: 元素对象.onclick=function(){
this->当前触发事件的元素对象本身
}
问题: 一个事件属性,只能绑定一个处理函数
3. 在js中通过添加事件监听对象的方式: ——最灵活
元素对象.addEventListener("事件名",处理函数)
添加 事件 监听对象
强调: 事件名本来是没有on: click, change, focus
只不过在用.时,为了和其它普通属性区分,才加了on前缀。
原理:
什么是事件监听对象: 一个保存元素+事件名+处理函数一套组合的对象:
比如: btnShoot.addEventListener("click",fun1);
先创建一个事件监听对象:
{
元素: btnShoot,
事件: click,
处理函数: fun1
}
然后,addEventListener会将监听对象添加到浏览器中一个隐藏的事件队列中。
当事件发生时,浏览器会遍历事件队列中的每个监听对象,选择匹配的监听对象中的处理函数执行。
如何从元素上移除一个处理函数:
元素对象.removeEventListener("click",处理函数)
处理函数决不能用匿名函数
强调: 如果一个处理函数有可能被移除,则绑定时,就不能用匿名函数。必须用有名称的函数。移除时,必须使用函数名,找到原函数对象,才能移除。
事件模型: 从点击元素触发事件开始,到事件处理函数执行完,期间所发生的一切事情。
DOM标准规定: 从点击元素触发事件开始,到事件处理函数执行完,期间共经历三个阶段:
1. 捕获阶段: 由外向内,记录各级父元素上的处理函数
2. 目标触发: 先触发最初发生事件的元素上的处理函数
目标元素(target): 最初发生事件的实际想点击的元素
3. 冒泡阶段: 由内向外,依次执行捕获阶段记录的父元素上的时间处理函数。
事件对象:
什么是: 当事件发生时,浏览器自动创建的,封装事件信息和操作事件的API 的对象
何时: 1. 想改变事件默认的执行行为时
2. 获得事件信息时
如何:
创建: 不用自己创建,直接使用
在事件发生时,自动获取事件对象:
事件对象总是作为处理函数的第一个参数传入处理函数中。——信任
如何获取事件对象:
btn.onclick=function(e){ //event的缩写
//当事件发生时,会自动调用处理函数,并自动传入事件对象给形参e
}
事件对象能干什么?
1. 停止冒泡(Propagation): e.stopPropagation()
2. 利用冒泡(事件委托/事件代理)
优化: 尽量减少事件监听对象的个数
因为浏览器触发事件,是在监听队列中遍历查找符合条件的监听对象来触发。
所以,监听对象越多,事件响应就越慢
如何: 当多个平级子元素都需要绑定相同的事件时,只要在父元素上绑定一次事件处理函数。所有孩子就可冒泡共用。
2个难题:
1. this已经不指子元素了,而是指父元素:
因为处理函数是定义在父元素上,且是等到事件冒泡到父元素时才触发。
如何获得实际单击的子元素:
用e.target代替this
目标
e.target可自动获得实际点击的目标子元素
且不随冒泡而改变
总结: this->不求天长地久,只愿曾经拥有
e.target->一旦拥有别无所求
2. 有可能点在正确的子元素上,也有可能点偏,点在不想要的元素上。
解决: 在正式执行操作前,必须先验证e.target是不是想要的。
比如: 验证标签名, 验证class, ... ...
补: 如何获取元素的标签名: 元素.nodeName
但nodeName返回全大写的标签名:
BUTTON A IMG LI ... ...
v
阻止默认行为:
问题: 有些浏览器的某些元素拥有默认的行为,而默认行为不是我们想要的。
比如: <a href="#"> 默认行为会在url地址栏结尾添加#,擅自篡改地址栏。
如何: e.preventDefault();
阻止 默认
预告: HTML5拖拽API中,几乎所有函数:
一上来先是两句话:
e.stopPropagation()
e.preventDefault();
获得鼠标的坐标:
事件对象中包含3组坐标:
1. 相对于整个屏幕左上角的坐标:
e.screenX e.screenY
2. 相对于文档显示区左上角的坐标:
e.clientX e.clientY
3. 相对于当前所在元素左上角的坐标:
e.offsetX e.offsetY
Jquery
Day 01
正课:
1. 什么是jQuery
2. 如何使用jQuery
3. 查找元素
4. 修改元素
1. 什么是jQuery:
第三方开发的 执行DOM操作的 极简化的 函数库
第三方: 先下载,才能使用
执行DOM操作: 学jQuery还是在学DOM的增删改查+事件绑定。
极简化: jQuery是DOM操作的终极简化
函数库: jQuery中都是用函数解决一切问题,没有属性。
为什么: 2个原因:
1. 是DOM操作的终极简化: 4个方面
增删改查
事件绑定
动画
ajax
2. 解决了绝大部分兼容性问题:
凡是jQuery让用的,都没有兼容性问题
比如: IE8: 不支持:nth-child(i) 选择器
document.querySelector("xxxx:nth-child(i)")错误
如果使用jQuery: $("xxxx:nth-child(i)") 正确!
原理: jQuery先检查兼容性问题。
如果发现当前浏览器不兼容,会用js模拟出选择器的效果。
CSS选择器:nth-child(i) -> js中的children[i-1]
jQuery的问题:
1. 仅限于PC端
2. 仅仅是对DOM操作的每一步进行的简化。并没有彻底简化开发的步骤。
2. 如何使用jQuery:
下载: jquery.com
1.x: 兼容旧浏览器 1.11.3
未压缩版: 拥有完备的注释,代码格式和见名知义的变量名。——可读性好。问题: 体积大不便于下载和传输。
压缩版: 去掉注释,所有空格/换行等格式,最简化了变量名。——体积极小。问题: 可读性差。——上线后/生产环境中
Webpack工具: 将HTML,CSS,JS代码压缩打包为极简化的代码。
2.x: 不再兼容旧浏览器
3.x: 不兼容旧浏览器,增加了部分新特性
引入: 在需要使用jQuery的页面中先引入jquery.js文件
<script src="js/jquery-1.11.3.js"></script>
然后再编写自定义js程序
<script>自定义的js程序</script>
原理:
引入jquery-1.11.3.js后:
在内存中添加了一种新的类型jQuery,包括两大部分:
1. 构造函数: 创建该类型的子对象,并填充对象的内容
function jQuery(选择器){
//...
}
2. 原型对象: 保存该类型所有的孩子共用的函数
jQuery.prototype:{
//所有jQuery子对象可使用的公共的函数
}
只要想使用jQuery家的简化版API,必须先创建jQuery类型的子对象。又因为jQuery家的函数都是为了操作DOM元素的,所以创建jQuery对象时,都要找到DOM树上的原生DOM元素,保存到jQuery对象中。
比如: var btn1=new jQuery("#btn1")
先在原生DOM树上找到id为btn1的原生DOM按钮。
然后创建jQuery对象,保存找到的这个按钮对象。
但是new jQuery太麻烦,所以jQuery构造函数中,提前包含了return new jQuery,调用jQuery(),就等效于调用new jQuery了,以此省略new:
function jQuery(选择器){
return new jQuery(选择器)
}
所以: var btn1=jQuery("#btn1")
但是jQuery的名字还是长,于是作者: $=jQuery
所以,用$=用jQuery=new jQuery
所以: var btn1=$("#btn1");
因为jQuery对象是jQuery家的孩子,不是DOM家的孩子,所以jQuery对象不能使用原生DOM的API,同理原生DOM的按钮也不能使用jQuery的简化版API,所以变量名必须有所区分,所以习惯上所有jQuery对象的变量都以$开头,比如: var $btn1=$("#btn1")
对jQuery对象,调用简化版函数,jQuery对象会自动翻译为对应的原生函数,自动作用于内部保存的原生DOM对象上,比如: $btn1.click(function(){ ... })
就等效于: btn1.addEventListener("click",function(){ ... })
再比如: 调用$btn1.html(),会被自动翻译为btn1.innerHTML
本质: jQuery对象其实是一个保存多个找到的DOM元素的类数组对象
3. 查找: 2种:
1. 按选择器查找元素:
var $elems=$("任意选择器")
jQuery支持所有CSS3的选择器
同时还扩展了一批新的选择器:
回顾: 子元素过滤: 同CSS
在多个父元素内,选择处在指定位置的子元素
:first-child :last-child :nth-child(i) :only-child
新: 基本过滤/位置过滤: jQuery新增的
先将符合条件的所有元素取出来,放在一个大的集合中,再按元素在集合中的顺位编号选择指定的元素
:first :last :even :odd :eq(i) :gt(i) :lt(i)
偶数 奇数 等于 大于 小于
新: 内容过滤: 用元素的内容中的文本关键词作为查询条件:
1. :contains(关键词): 只要元素的内容中包含"关键词",就选中该元素
2. :has(选择器): 只要当前元素的内容中包含符合"选择器"条件的子元素,就选中
新: 可见性过滤: 选择那些可见的或不可见的元素
:hidden 匹配看不见的隐藏元素
只能匹配两种: display:none 和 input type="hidden"
不能匹配两种: visibility:false 和 opacity:0
:visible 匹配看的见的元素
新: 表单过滤: 专门查询表单中的表单元素的选择器
:input 选择所有表单元素: input select textarea button
vs input 仅选择input元素
每种type都对应一种选择器:
:text :password :checkbox :radio :file ... ...
2. 按节点间关系查找元素:
比如: $elem.next() 获得当前元素的下一个兄弟元素
$elem.nextAll() 获得当前元素之后所有的兄弟元素
4. 修改:
内容: 3种:
1. 原始的HTML片段: .innerHTML => .html()
2. 如果想去内嵌的标签或特殊符号: .textContent => .text()
3. 表单元素的值: .value => .val()
属性:
1. HTML标准属性:
2. 三大状态属性: checked selected disabled
$elem.prop("状态",bool)
3. 自定义扩展属性:
样式: .style.css属性=值 => $elem.css("css属性名","值")
福利: 不用写单位——仅jq有
问题: 一次只能改一个css属性:
解决: 同时修改多个css属性:
$elem.css({
"css属性1": 值1,
... : ... ,
})
jQuery函数的特点: 3个:
1. 自带遍历效果: 对jQuery对象整体调用函数,等效于自动对内部保存的多个原生DOM对象,分别调用函数。
比如: 页面上三个button,每个按钮都要绑定单击事件:
//用DOM做
var btns=document.getElementsByTagName("button");
for(var btn of btns){//只能遍历
btn.onclick=function(){ ... }
}
//用jQuery做,不用遍历,只要对整体调用一次click()
var $btns=$("button");
$btns.click(function(){ ... })
等效于自动: btns[0].onclick=function(){ ... }
btns[1].onclick=function(){ ... }
btns[2].onclick=function(){ ... }
2. 一个函数两用: 调用一个函数时,如果不给新值,自动执行获取值的操作。如果给了新值,自动切换为更新的操作。
比如: DOM获取或修改一个按钮的内容:
获取: btn.innerHTML
修改: btn.innerHTML=新值
jQuery中:
获取: btn.html()
修改: btn.html(新值)
3. 几乎所有函数都返回正在遍历的jQuery对象,便于重复使用
比如: $("ul>li:first").css(...) //return $("ul>li:first")
可继续对$("ul>li:first")继续执行操作
比如: 可直接跟.html(),继续访问第一个li的内容
链式操作: 将多个操作通过.连接起来连续调用,称为链式操作。
前提: 必须对每一步函数调用的返回值了如指掌
优点: 减少变量的使用,减少查找的次数,优化程序
补: var bool=$elem.is("选择器")
判断当前元素是否满足选择器的条件要求
返回bool值: 如果elem元素的特征满足选择器的要求,就返回true,否则返回false。
Day 02
正课:
1. 修改
2. 按节点间关系查找
3. 添加/删除/替换/克隆
4. 事件绑定
1. 修改:
内容:
1. 原始HTML片段内容:
.innerHTML -> .html([新内容]) 两用
2. 纯文本内容(去内嵌标签):
.textContent -> .text([新内容]) 两用
3. 表单元素的值:
.value -> .val([新值]) 两用
属性:
1. HTML标准属性: 2种:
1. 核心DOM:
元素.getAttribute()
元素.setAttribute()
↓
$元素.attr("属性名"[,新值]) 两用
2. HTML DOM:
元素.属性名=值
property
↓
$元素.prop("属性名"[,新值]) 两用
无论attr还是prop都可同时修改多个属性:
$元素.attr|prop({
属性名:值,
... : ... ,
})
2. 状态属性: disabled checked selected
不能用核心DOM的getAttribute()或setAttribute()访问
自然也就不能用$元素.attr()访问
只能用.访问: chb.checked=true;
而在jquery中只能用: $元素.prop()
3. 自定义扩展属性:
只能用核心DOM的getAttribute()和setAttribute()访问
自然也能用jQuery的$元素.attr()
但是,不能用.访问: ANY.data-trigger=值
自然也不能用jQuery的$元素.prop()访问
样式:
elem.style.css属性 -> $元素.css()
问题: 只能一个一个的修改css属性,无法快速简介的批量修改。
解决: 只要批量修改样式,都用class属性
jQuery: $元素.addClass("类名") 添加class
$元素.removeClass("类名") 移除class
$元素.hasClass("类名") 判断是否包含class
比DOM的 className="类名"是覆盖,无法只精确修改某一个class。
而addClass和removeClass(),可精确修改某一个class,而不影响其它class。
另外: $元素.toggleClass("类名")
自动判断是否包含指定"类名",自动在有和没有这个类名之间来回切换
比如一个按钮在有class down和没有class down之间来回切换:
//如果当前按钮没有class down,就添加down
if(!$(this).hasClass("down")){
$(this).addClass("down");
}else{//否则,就移除down
$(this).removeClass("down");
}
其实最简单的写法: $(this).toggleClass("down");
2. 查找:
1. 按选择器查找:
2. 按节点间关系查找:
两大类关系
1. 父子关系
元素.parentNode|parentElement 父元素
jq -> $元素.parent();
元素.children 所有直接子元素
jq -> $元素.children(["选择器"]);
如果没有选择器,就获得所有直接子元素
如果提供了选择器,就仅获得符合选择器要求的部分直接子元素
jq -> $元素.find("选择器")
在元素的所有后代中查找符合选择器要求的
强调: 必须写选择器
元素.firstElementChild 第一个直接子元素
jq-> $元素.children().first()
元素.lastElementChild 最后一个直接子元素
jq-> $元素.children().last()
2. 兄弟关系
元素.previousElementSibling 前一个兄弟
jq->$元素.prev()
扩展: jq -> $元素.prevAll(["选择器"])
选择当前元素之前所有兄弟元素(符合条件的)
元素.nextElementSibling 后一个兄弟
jq->$元素.next()
扩展: jq -> $元素.nextAll(["选择器"])
选择当前元素之后所有兄弟元素(符合条件的)
扩展:
jq->$元素.siblings(["选择器"])
选择除当前元素之外无论前后的所有兄弟元素(符合条件的)
3. 添加/删除/替换/克隆:
1. 添加元素:
jq: 2步:
1. 用html片段创建新元素:
var $elem=$(`html片段`)
2. 将新元素添加到DOM树
末尾追加: 父元素.appendChild(新元素)
jq -> $父元素.append($新元素)
扩展: 开头追加: $父元素.prepend($新元素)
中间插入: 父元素.insertBefore(新元素, child)
jq -> $child.before($新元素)
扩展: 在当前元素后插入新元素: $child.after($新元素)
问题: 要么返回父元素,要么返回旧的子元素,无法在调用后继续利用链式操作,对新元素做后续连续操作。
解决: 其实以上API都有一对儿:
比如: $父元素.append($新元素)
$新元素.appendTo($父元素)//return $新元素
.对新元素继续操作
再比如: $父元素.prepend($新元素)//return $父元素
$新元素.prependTo($父元素)//return $新元素
.对新元素继续操作
2. 删除: $元素.remove();
3. 替换:
父元素.replaceChild(新元素, 旧元素)
jq-> $旧元素.replaceWith($新元素)//return $旧元素
$新元素.replaceAll($旧元素)//return $新元素
.对新元素继续操作
4. 克隆: var $新元素=$元素.clone();
4. 事件绑定:
标准事件绑定:
DOM: 元素.addEventListener("事件名",处理函数)
元素.removeEventListener("事件名",处理函数)
jq: addEventListener->on
removeEventListener -> off
$元素.on("事件名",处理函数)
$元素.off("事件名",处理函数)
简写的事件绑定: 仅限于最常用的21种事件
$元素.事件名(function(e){
e.stopPropagation();
e.preventDefault();
var $this=$(this);
var $tar=$(e.target)
... ...
})
事件代理:
DOM:父元素.addEventListener("click",function(e){
var tar=e.target;
if(tar是xxxx){
正式的逻辑
}
})
jq: 2处简写:
1. this又回来了!
2. 不用写if了!
$父元素.on("click","选择器条件",function(e){
//自动if($tar.is("选择器条件"))
//自动保证所有进入function的元素都是符合选择器条件的。
var $tar=$(this);
... ...
})
什么是DOM对象:就是js对象,使用js的方式获取到的元素就是js对象,也就是dom对象;
Jq与js的联系:jq对象就是js对象的一个集合,伪数组,里面存放了一大堆的js对象
Day 03
正课:
1. 事件
2. 动画
3. 类数组对象操作
4. 添加自定义函数
5. 封装自定义插件
1. 事件:
页面加载后执行:
问题: 浏览器加载HTML和js是顺序加载
必须保证js在HTML加载后执行,才能保证所有的查找都能找到想要的元素。
但是<script>可能被放在开头,也可能被放在结尾
如何保证无论<script>放在网页开头和放在结尾,都能正常执行呢?
解决: 不要将js代码直接放在<script>内
window有一个事件: load,会在整个网页加载完成后,自动执行。所有js代码都应该放在window.onload=function(){}中,在页面加载后自动执行。
强调: window.onload=functio(){}无论写在哪儿,都只能在整个窗口内容加载完才自动执行
问题: window.onload有两个缺点:
1. =是赋值覆盖的意思,如果同时出现多个window.onload=function(){ ... },结果只有最后一个会覆盖之前所有。
解决: $(window).load(function(){ ... })
//addEventListener() 可反复加多个
2. window.onload需要等待所有页面内容(html,css,js,图片)加载完成才执行。——慢, 晚
其实大多数情况下,用户急于使用功能,而无所谓图片内容和网页美观。
解决: 其实在window.onload之前还有一个事件会提前触发: DOMContentLoad——只等待HTML和JS加载完,无需等待CSS和图片。——快,早!
但是DOMContentLoad事件有兼容性问题,只能用jQuery方式绑定: $(document).ready(function(){ ... })
当 网页 就绪 自动执行
所以,放在$(document).ready(function(){...})中的代码会在DOM内容加载后就提前触发。无需等待CSS和图片。
总结: jQuery中所有代码都要放在$(document).ready()中
简化: $(document).ready(function(){...})
||
$().ready(function(){ ... })
||
$(function(){ ... })
总结: jQuery中所有代码都要放在$(function(){ ... })中
除非必须依赖css和图片的jq代码才必须在window.load中执行。但是很少。
鼠标事件:
mouseover mouseout —— 即使父子元素也当做独立的元素看待,从父元素进入子元素,同样会触发父元素的mouseout事件,与现实不符。
解决: jQuery 用 mouseenter mouseleave 代替
优点: 认为进入子元素,并没有离开父元素
简写: 如果同时绑定mouseenter和mouseleave时
其实只要绑定一个hover函数即可:
$元素.mouseenter(function(){ ... })
.mouseleave(function(){ ... })
||
$元素.hover(
function(){ ... }, //-> mouseenter
function(){ ... } //-> mouseleave
)
模拟触发: 即使没有点击按钮,也可执行按钮的单击事件处理函数
如何: $元素.事件名() //手动调用指定元素上的事件处理函数
2. 动画:
1. 简单动画: 固定的三种动画效果
1. 显示隐藏: $元素.show() $元素.hide() $元素.toggle()
问题/优点: 本质其实是用display:block和display:none来实现的瞬间显示隐藏。
解决: 加参数: 动画持续时间
$元素.show(2000) $元素.hide(2000)
2. 上滑下滑: $元素.slideUp()
$元素.slideDown()
$元素.slideToggle() 切换
3. 淡入淡出: $元素.fadeIn()
$元素.fadeOut()
$元素.fadeToggle();
问题:
1. 效果固定的,无法修改
2. 都是用js程序和定时器模拟的动画效果——效率低
总结: 将来能用css做的动画,首选css——效率高,可维护
特别推荐: $元素.show() $元素.hide() $元素.toggle()
不包含动画效果,仅简化display操作
比如: $元素.css("display","block")
.show()
$元素.css("display","none")
.hide()
$元素.toggle() 自动在显示和隐藏之间来回切换
2. 万能动画: 对任意css属性应用动画效果
$元素.animate({
//目标样式
css属性:值,
... : ... ,
}, 动画持续时间ms)
让{}里的css属性,在规定的时间ms内,从当前值缓慢过渡到目标值
问题: 1. 也是用js和定时器模拟的,效率低
2. 功效类似于css的transition,还不如transition
相同: 凡是单个数值的属性: 都支持
width, height, left, top, padding, margin ...
不同: CSS中的transition支持颜色动画
也支持CSS3变换
jq中的animate不支持颜色动画
也不支持CSS3变换
排队和并发:
排队变化: 多个css属性,先后按顺序变化
如何: 对同一个元素反复调用多次动画函数,多个动画函数的效果是排队顺序执行的。
比如: $s2.animate({left:400},2000)
.animate({top:300},2000)
本质:
所有的元素都有一个动画队列:
调用动画函数,并不是立刻执行动画的意思,仅仅是将动画效果加入队列中等待顺序执行。
并发变化: 多个css属性,同时变化
如何: 放在一个animate中的多个css属性默认并发同时变化
动画结束后自动执行:
jQuery中所有动画函数都是定时器模拟的,所以都是异步的。主程序中其它函数是不会等动画执行完才执行的。
解决: 如果希望在动画接收后才自动执行一项任务,可用动画函数提供的回调函数参数
如何: 每个动画函数,都有最后一个参数,是一个回调函数。放在回调函数中的代码,一定会在动画结束后才自动执行
停止动画: $元素.stop()
坑: .stop()默认只停止队列中当前正在播放的动画,后续动画依然继续播放。
解决: .stop(true) 停止当前动画,并清空队列
选择器: :animated 匹配正在播放动画的元素
3. 类数组对象操作:
jQuery的$()查询后的结果就是一个类数组对象
但是在js中类数组对象很受歧视,数组家的函数,都用不了。
jQuery中为类数组对象提供了两个最常用的函数:
$(...).each() 类似于 js中的数组的forEach
遍历集合中的每个元素,执行相同的操作
如何: 遍历一个ul下的所有li
$("ul>li")//返回类数组对象
//.forEach(function(elem, i , arr){ ... })
.each(function(i, elem){
elem->每个li ...
$(elem)->jq的$li
})
$(...).index() 类似于js中的数组的indexOf
查找集合中是否包含指定的元素,以及在什么位置
如何: 在一批元素中查找一个指定元素的位置
比如: 查找一个$li在ul下所有li中是第几个
var i=$("ul>li").index($li)
可简写: 如果是在同一个父元素下找li的位置
var i=$li.index(); //自动就在当前里的父元素内查找
4. 添加自定义函数:
何时: 当jQuery中提供的函数不够用时
如何: 向jQuery的原型对象中添加新函数,所有jQuery对象都可以使用。
比如: 为所有jQuery对象添加一个函数: sum() 能对找到的所有元素的内容自动求和。
1. 先在jQuery原型对象中添加自定义的共有函数
//jQuery.prototype.sum=function(){
||
jQuery.fn.sum=function(){
//遍历将来调用sum()的点前的jQuery查找结果集合中的每个元素,并计算内容的和
var $elems=this; //直接拿到$("ul>li") jq对象,不需要$()
var total=0;
$elems.each(function(i, elem){//elem取出的是$elems中保存的一个一个的DOM对象
var $el=$(elem);
total+=parseInt($el.html())
})
//返回计算结果
return total;
}
2. 在任意jQuery对象上调用
var 内容的和=$("ul>li").sum()
5. 封装jQuery自定义组件:
官方组件库: jQuery UI
如何:
1. 引入jQuery UI的css
2. 按组件的要求编写HTML内容
3. 引入jQuery.js和jQuery UI.js
4. 编写自定义代码,找到组件的父元素,对父元素调用一次组件函数。
jQueryUI的原理: 侵入性: 在程序员不知情的情况下,自动添加样式和行为。
如果自己封装了插件,自己用,jQueryUI方式一定是简单
如果考虑可维护性和灵活性,jQueryUI封装的太死了,不便于维护。
jQuery组件是一套可重用的CSS样式和js功能的集合
为什么: 重用!
何时: 当发现很多网页中都需要一个小功能时,就要将这个功能的样式和行为封装为一个组件,将来反复使用
如何:
定义组件:
0. 前提: 已经用原始的CSS,DOM,jq实现了。只不过暂时没有分离出来。所以定义jQuery组件其实仅是一个提取的过程
1. 向jQuery的原型对象中添加自定义的组件函数
1.1 为组件的HTML元素添加样式
自动在各个元素上侵入class
1.2 为组件的HTML元素添加行为
2. 将原来写好的CSS代码提取到专门的css文件中独立存储
使用组件: 和使用jQuery UI组件的用法完全一样
Day 04
jQuery中的$()共可以做几件事?
$("选择器") 查找DOM元素,保存进jQuery对象中
$(this|e.target) 将DOM元素,封装为jQuery对象
$(`html片段`) 创建新元素
$(function(){ ... }) 绑定事件,DOM内容加载后就提前触发
鄙视: 如何避免组件间样式冲突
不好的做法: 改名
因为项目中要求描述一个事物或一种功能,必须用统一的名称。
好的做法: 在所有的样式类前加上统一的前缀
正课:
1. ajax
2. *****跨域
1. ajax
$.ajax({
url:"服务端接口地址", //http://localhost:3000/users/login
type:"get|post",
data: { uname: "dingding", upwd: "123456" },
//"uname=dingding&upwd=123456",
//如果返回json,需要自动JSON.parse()转为js对象
dataType:"json", //如果不写需要自己手动调用JSON.parse()
//onreadystatechange =function(res){ ... }//在响应回来后,处理响应结果
success: function(res){
//res是JSON.parse()已经翻译过的可直接使用的js对象/数组
}
})
2. *****跨域:
浏览器同源(origin)策略: 也称禁止跨不同源头访问资源
强调: 仅限于ajax
浏览器规定发送ajax请求时,只有相同域名的客户端和相同域名的服务端之间才能发送请求:
比如: 学子商城项目:
客户端:
http://localhost:3000/index.html
index.js
$.ajax()
请求↓ ↑响应 成功
服务端:
http://localhost:3000/index
跨域: 从一个域名下的网页,向另一个域名下的服务端发送ajax请求——受浏览器的同源策略控制,禁止发送的
比如:
1. 域名不同:
http://www.a.com/index.html -> http://www.b.com
2. 子级域名不同:
http://oa.tedu.cn/index.html -> http://hr.tedu.cn
3. 端口号:
http://localhost:5500/index.html -> http://localhost:3000
4. 协议不一样:
http://localhost/index.html -> https://localhost
:80 :443
5. 即使同一台机器,域名和IP之间互相访问
http://localhost/index.html -> http://127.0.0.1
域名 IP
以上5种情况,都会报ajax请求错误:
CORS...Access-Control-Allow-Origin
但是,现实中,随处可见跨域请求:
手机都能看天气和股票
淘宝可跟踪所有快递公司的物流信息
一定可以跨域请求: 如何跨域
1. CORS方式: 仅服务端改代码,就可跨域
同源策略的本质: 其实可以发送ajax请求
也可以正常执行服务端的程序
也可以顺利返回正确的结果
但是,浏览器经过检查数据的来源,发现和当前网页的来源不一致,所以,到手的数据不让用!
如何: 其实就是在服务器端返回响应的响应头中伪装成指定的源头
//res.send(result); //不要用res.send了
res.send其实是一种简写:
等效于:
res.writeHead()+res.write(JSON.stringify(result))+res.end()
想跨域,就不要用简写的res.send()
自己在服务端写三步:
res.writeHead(200,{
"Access-Control-Allow-Origin":"http://127.0.0.1:5500"
});
res.write(JSON.stringify(result));
res.end();
这样返回的数据,就被伪装成来自127.0.0.1:5500的,就可以通过浏览器的同源策略检查,可正常使用
2. JSONP方式: JSON with padding
填充式JSON
方案一: 用<script src="服务端接口地址"代替$.ajax发送请求。
服务端: 将要发送的数据填充在一条js语句中
res.write(`document.write("${weather}")`)
客户端: <script src="服务端接口地址"
<script 发送请求到服务端
并能够收到服务端返回的js语句字符串:
document.write("${weather}")
<script只要收到js语句,就立刻自动执行
问题: 要在客户端执行的js语句,在服务端写死了,众口难调。
方案二: 提前在客户端定义一个函数,用于处理服务端返回的请求,服务端仅使用函数名拼接一条函数调用的js语句
客户端: function show(weather){
任意js语句
}
服务端: res.write(`show("${weather}")`)
问题: 本该定义在客户端的函数名,在服务端是写死的,众口难调
方案三: 用请求参数,将函数名传递给服务器
客户端: <script src="http://localhost:3000?callback=show"
服务端: 接收客户端传来的名为callback的参数中保存的函数名
将callback函数名动态拼接到要返回的函数调用语句中
问题: <script是在页面中写死的,只能在页面加载过程中执行一次。无法按需反复执行,比如每次单击按钮时,随时发送请求。
方案四: 每次单击按钮时动态创建<script元素
客户端:
$("button").click(function(){
//不要用$("<script>")动态创建<script>元素
//浏览器会强行将<script>解析为标签
//退一步,用核心DOM
var script=document.createElement("script");
script.src=`http://localhost:3000?callback=doit`;
document.body.appendChild(script);
})
问题: 每次单击时都会创建<script,反复单击会导致<script堆积
解决: 在回调函数结尾:
删除body最后一个<script>
function doit(weather){
alert(weather);
//回调函数结尾: 删除用过的<script>
$("body>script:last").remove();
}
jQuery对jsonp方式跨域进行了终极的简化:
$.ajax({
url:
type:
data:
dataType:"jsonp"
success:function(){
... ...
}
})
VUE
安装服务器脚手架
npm i express-generator -g 安装服务器脚手架
express --no-view server 不带模板引擎
npm install 安装依赖
Day 01
正课:
1. 什么是Vue
2. 如何使用Vue
3. MVVM
4. 绑定语法
5. 指令
1. 什么是Vue:
渐进式的 基于MVVM的 执行数据操作的 纯前端js框架
渐进式: 可以逐步在项目中使用Vue框架
可以和现有传统技术很好的结合
全家桶: 如果要使用一种框架,就只能使用框架的所有技术。不能和其它技术混搭。
基于MVVM?
执行数据操作的: 终极简化对网页执行的数据操作: 增删改
纯前端js框架: 不要nodejs,仅靠浏览器就可运行项目
2. 如何使用:
官网: cn.vuejs.org
下载: 版本: 2.6
2种:
1. 下载vue.js文件,引入网页中——前三天
开发版: 体积大,可读性好,带错误提示
生产版: 体积小,可读性差,去掉了所有错误提示
2. 脚手架代码——最后一天做项目
如何引入:
<script src="js/vue.js">
<script>自定义代码</script>
如何使用:
3大步:
1. 定义页面的HTML内容:
要求: 必须包含在一个<div id="app"></div>内
必须用{{变量}}标记处,要使用数据的位置
如有事件处理函数,就用@click绑定事件处理函数
比如: <div id="app">
<button @click="add">click me({{n}})</button>
2. 在自定义程序中先定义页面所需的所有数据。
要求: 必须包含在一个data:{}对象中
比如: 页面上有一个{{n}},表示一处n需要发生变化,所以
var data={ n:0; }
3. 创建new Vue()对象示例,将数据和页面元素绑定起来
var vm=new Vue({
el:"#app",
data: data,
//结果: data中的变量是什么值,页面中就显示什么值
//data中的变量被改成什么值,页面中就自动变成什么值
//如果需要事件处理函数,都要定义在methods:{}中
methods:{
add:function(){//当单击按钮时,自动触发add函数
this.n++; //修改data中的n+1,页面上的n自动跟着变化
}
}
})
事件: 2步:
1. 在页面的html元素上用@click="add" 绑定事件处理函数
2. 事件处理函数,不要定义在new Vue的外边
应该定义在new Vue中专门的methods属性内:
new Vue({
el:"#app",
data: data,
methods:{
add:function(){
this.变量++
}
}
})
总结: 页面需要什么,Vue就定义什么
比如: <button @click="add">click me(0)</button>
new Vue({ ↑ ↑
add:function(){} {{n}}
<button @click="sub">- <span>1 <button @click="add">+
new Vue({ ↑ ↑ ↑
sub:function(){} {{n}} add:function(){}
3. MVVM模式:
传统的DOM:
HTML: 只负责静态内容,不会自动变化
CSS: 只负责静态样式,不会自动变化
JS: 即要负责内容的变化,又要负责样式的变化
问题: 1. 步骤繁琐且重复: 查找,绑定,遍历,替换,拼接字符串
2. 不便于维护:jQuery中,如果页面结构或内容发生变化,则js中选择器和HTML片段都要跟着修改
现代框架: MVVM模式
1. 界面/视图View: 包括静态的HTML+CSS
2. 数据模型Model: 页面中所需的所有数据的整体
3. 控制器/视图模型ViewModel: 自动将数据模型Model中的变量,填充到界面中所需的位置
总结: 什么是M V VM模式: 页面需要什么,模型就定义什么。
视图模型会自动将模型中的数据填充到页面中。且模型数据发生变化时,视图模型会自动更新页面。
优点: 1. 没有任何重复的代码
2. 界面和模型松耦合,界面变化,不需要修改模型,甚至不需要修改ViewModel控制器。——及其便于维护
ViewMode的原理:
当new Vue将模型对象和页面元素绑定在一起时,内部自动构建两大子系统:
1. 响应系统:
自动将data中的每个变量变成访问器属性
今后,所有对变量的读写,自动都被访问器接管,由访问器属性代为执行。
比如:修改变量的值时,自动调用变量的set方法,修改实际的变量值。
而每个变量的set方法,当变量发生改变时,都会自动发送通知:xxx变量的值变成xxx了
通知是交给另一子系统,虚拟DOM树的
2. 虚拟DOM树:
当new Vue()创建对象时,会扫描el:"#app"指向的父元素div,及其子元素。然后,仅找到可能发生变化的元素,保存在一个简化版的虚拟DOM树结构中:
比如:
var virtualDOM={
element: div, //<div id="#app"
id:"#app",
children:[
{
element: button, //<button>click me({{n}})
innerHTML: "click me {{n}}",
@click:"add"
},
//其它可能变化的元素
]
}
什么是虚拟DOM树: 仅保存可能变化的元素的简化版树结构对象,同时预先封装了要对元素执行的DOM操作。
当响应系统发来某变量被修改的通知后,虚拟DOM树先遍历自己内部的元素,找到受这个被修改变量影响的元素。然后自动调用预先定义好的DOM操作,更新实际DOM树上的元素。其余未受变量影响的元素,保持不变。
虚拟DOM树的优点:
1. 仅包含可能变化的元素,内容精简,便于快速遍历,查找变化的内容。
2. 封装了DOM操作,自动执行DOM操作,无需开发人员重复编码。
this: 凡是进入new Vue中的,无论是data中的变量,还是methods中的方法,都被打散,直接隶属于new Vue,变为相邻的平级成员。所以,在方法中想访问data中的数据,必须加this.
4. 绑定语法:
{{ }} 学名: 插值(Interpolation)语法
什么是: 专门用于将一个变量的值自动插入到页面的指定位置
何时: 凡是页面上可能发生变化的地方,都用{{}}
如何:
基本用法: {{变量名}}
结果: 运行时: 会被自动替换为变量的值
扩展: {{一切合法的有返回值的js表达式}}
比如: 算术计算、方法调用、对象属性、三目运算...
但是,不能写没有返回值的:
if else for while 程序结构
比如: <h1>空气质量: {{pm25<100?"好":
pm25<200?"中":
pm25<300?"差":
"活不了了!"}}
执行时,vue会拿着data中的数据变量pm25,到{{}}中执行js表达式,比较每个判断条件,选择一个符合条件的值返回,作为替换{{}}位置的值。
5. 指令:directive
什么是: 为HTML增加新功能的专门的属性
为什么: HTML本身不具备程序该有的功能
一个程序基本的功能:
变量:
判断:
循环:
何时: 只要想在html中使用类似变量,判断,循环等程序的功能时,就用指令:
Vue*定义了13种指令:
1. v-bind:
什么是: 专门用于绑定属性值的指令
何时: 只要一个属性值可能根据变量的值自动变化时
为什么: {{}}只能用于绑定元素内容(innerHTML)中的值
不能用于动态绑定属性值
如何:
<ANY v-bind:属性="任意合法的js表达式"
可省略v-bind
比如: <img :src="pm25<100?'img/1.png':
pm25<200?'img/2.png':
'img/3.png' "
执行时: Vue会拿着data中的pm25变量,到有:的属性中执行三目运算,选择其中一个符合条件的字符串,作为替换src属性值的路径。
2. v-if v-else-if v-else
多个元素,根据条件不同,选其一显示
只有符合条件的元素才显示
不符合条件的同组其他元素默认隐藏
如何:
//如果pm25<100
<img v-if="pm25<100" src="img/1.png"
<span></span>之间绝对不能插入其它无关元素
//否则 如果pm25<200
<img v-else-if="pm25<200" src="img/2.png"
//否则
<img v-else src="img/3.png"
原理: 其实所有带v-if v-else-if v-else的元素都没有在页面上。而是根据条件,动态决定临时添加哪个元素到页面
——靠添加删除DOM元素的方式控制元素的显示
强调: 之间不能插入其它无关的元素
3. v-show
根据条件决定当前一个元素是显示还是隐藏
如何: <ANY v-show="条件">
当条件满足时,当前元素就显示
当条件不满足时,当前元素就不显示
比如: <button v-show="i<count" @click="next">下一页</button>
问题: 如果用在多个元素控制显示隐藏,则必须把条件反复写在每个元素上
vs v-if:
v-show采用display:none/block方式控制显示隐藏,不修改DOM树上的节点——效率高
v-if 采用动态添加删除元素的方式控制显示隐藏——效率低
4. v-for:
遍历数组中每个元素
每遍历一个数组元素就自动创建一个HTML元素
并且在HTML元素中还可绑定遍历出的数组元素内容
何时: 根据数组反复生成多个相同结构的元素时
如何:
1. 只需要写一个要生成的元素作为模板
2. 在要重复生成的元素上加v-for
比如:
data中: tasks:["吃饭","睡觉","打亮亮","再吃饭"]
<ul>
<!--遍历tasks数组中的每个元素,将每个元素的值临时保存在变量task中,每遍历一个tasks数组中的元素,就创建一个相同结构的li,并动态绑定循环变量的值到元素内容中-->
<li v-for="(task,i) of tasks">{{i+1}} - {{task}}</li>
<!--结果-->
</ul>
5. 事件绑定:
v-on:click="处理函数"
@click="处理函数"
强调: 1. 处理函数必须写在new Vue中的methods中
2. 处理函数中的this不再指向当前按钮对象,而是指整个vue对象
3. 处理函数中要操作data中的变量必须加this.
6. v-html v-text:
代替{{}}绑定元素的内容
{{}}的问题: 2个
1. 始终保持变量中的字符串原始样子输出
即使绑定HTML片段,也只能原样显示
解决: 用v-html代替{{}}
2. 如果new Vue加载慢时,客户会短暂看到{{}}
解决: 用v-text代替{{}}
因为v-text是属性,即使慢,暂时绑定不出来,页面上也不会出现绑定语法。
缺点: 对字符串拼接和过滤器支持不好
7. v-cloak:
专门用于在new Vue加载慢时,暂时隐藏元素
如何: 2步:
1. 在要隐藏的元素上添加v-cloak属性,不用给值
2. 手动在网页顶部提前定义[v-cloak]{display:none}
原理: 当new Vue加载完之后,自动查找所有v-cloak属性,并移除。
8. v-once:
仅在页面加载时绑定一次变量值。之后,即使变量发生变化,也不更新页面
如何: <ANY v-once>
原理: 所有要更新的元素都保存在虚拟DOM树中
标有v-once的元素,在首次绑定后,就从虚拟DOM树中移除。下次即使变量再变化,扫描虚拟DOM树,找不到标有v-once的元素了。
9. v-pre:
万一内容中包含{{}},但不想被vue编译时,可用v-pre阻止编译内容:
如何: <ANY v-pre>
<body>
<div id="app">
<!-- <input type="button" value="toggle" @click="toggle"> -->
<input type="button" value="toggle" @click="flag=!flag">
<!-- v-if 的特点:每次都会重新删除或创建元素 -->
<!-- v-show 的特点: 每次不会重新进行DOM的删除和创建操作,只是切换了元素的 display:none 样式 -->
<!-- v-if 有较高的切换性能消耗 -->
<!-- v-show 有较高的初始渲染消耗 -->
<!-- 如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show -->
<!-- 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if -->
<h3 v-if="flag">这是用v-if控制的元素</h3>
<h3 v-show="flag">这是用v-show控制的元素</h3>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {
/* toggle() {
this.flag = !this.flag
} */
}
});
</script>
</body>
<body>
<div id="app">
<!-- <input type="button" value="toggle" @click="toggle"> -->
<input type="button" value="toggle" @click="flag=!flag">
<!-- v-if 的特点:每次都会重新删除或创建元素 -->
<!-- v-show 的特点: 每次不会重新进行DOM的删除和创建操作,只是切换了元素的 display:none 样式 -->
<!-- v-if 有较高的切换性能消耗 -->
<!-- v-show 有较高的初始渲染消耗 -->
<!-- 如果元素涉及到频繁的切换,最好不要使用 v-if, 而是推荐使用 v-show -->
<!-- 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if -->
<h3 v-if="flag">这是用v-if控制的元素</h3>
<h3 v-show="flag">这是用v-show控制的元素</h3>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {
/* toggle() {
this.flag = !this.flag
} */
}
});
</script>
</body>
总结:
1. 元素内容随变量自动变化: {{}}
2. 元素的属性值随变量自动变化: :属性="变量/js表达式"
3. 多个元素,多选一显示时: v-if v-else-if v-else
4. 只有一个元素控制显示隐藏时: v-show
5. 反复生成多个相同结构的元素时: v-for
6. 只要绑定事件: @事件名="处理函数"
7. 只要绑定的内容是HTML片段时: v-html
8. 代替{{}}绑定普通元素内容时: v-text ——避免短暂看到{{}}
9. 希望所有{{}}的元素,在new Vue加载完之前暂时隐藏: v-cloak
10. 希望仅在首次加载时,绑定一次变量值,之后页面不随变量改变而改变: v-once
Day 02
正课:
1. ***双向绑定
2. 绑定样式
3. 计算属性
4. 自定义指令
5. 过滤器
1. 双向绑定:
问题: 用: 只能进行单向绑定(Model(data)->View(html))
如果用:绑定表单元素的值,则用户修改表单元素的内容,无法自动修改data中的模型变量。意味着vue中永远拿不到用户在界面中修改的新值。
解决: 今后凡是绑定(可输入,可选择的)表单元素,必须用双向绑定,才能在界面修改时,自动更新data中的数据
双向绑定: 既能Model(data)->View(html)
data中变化,页面自动跟随变化
又能View(html) -> Model(data)
页面中变化,data中的变量自动跟随变化
如何: v-model:value="变量"
简写: 因为几乎所有表单元素都用value属性控制元素的内容或值,所以,几乎所有v-model都绑定value属性,所以可简写为: v-model="变量"
其它表单元素的双向绑定:
1. radio:
特殊在: value任何情况下是固定的
变的是checked属性,也就是选中与不选中状态
比如: 性别:
<input type="radio" name="sex" v-model="sex" value="1" checked >男
<input type="radio" name="sex" v-model="sex" value="0" checked >女
data:{
sex:1 0
}
是v-model="sex"将data中的sex和页面中的radio元素绑定
绑定时: 用data中sex的值和每个radio的提前写死的value做比较。如果那个radio的value值刚好等于data中sex的值就选中
其余不选中
修改时: 用当前选中的radio的写死的value,反向赋值回data中的sex上
2. select:
特殊: 每个option的value都是提前写死的
变得只是option的selected属性,变的只是选中的option是哪个。
比如:
<select v-model="city">
<option value="bj.png">北京</option>
<option value="hz.png">杭州</option>
<option value="sh.png">上海</option>
</select>
data:{
city:"bj.png"
}
其实: v-model="city" 其实仅仅起到一个绑定连接的作用
不具体绑定某一个属性
绑定时: 用data中city变量的值和每个option中的写死的value做比较。如果data中city变量的值等于option中写死的value的值,则当前option就选中。其余option就不选中
修改时: 用当前选中项的写死的value,反向更新会data中的city变量
原理: v-model="city"其实,不具体绑定修改元素某个属性的值。而是为元素添加修改事件,比如onchange, oninput等。在事件处理函数中修改new Vue对象中的模型变量的值。进一步触发模型变量的set方法,触发通知,引起其他使用该变量的元素的状态的改变。
3. checkbox:
单选时,变化的只是checked属性
何时: 如果希望用checkbox控制一个bool类型的变量值时
如何: <input type="checkbox" v-model="isAgree">同意
data: { isAgree:false }
绑定时: 根据isAgree的值,决定checkbox的checked状态
修改时: onchange=function(){ vm.isAgree=this.checked}
用当前checkbox的checked状态,更新data中的isAgree
双向绑定中可用watch机制,实时获得修改的新变量值:
何时: 只要希望边修改边实时执行操作时
如何:
data: { kwords:"" }
watch:{
kwords:function(){
//执行操作
}
}
只要通过任何手段修改一次kwords变量的值,都会立刻触发一次kwords()函数,执行一次操作。
2. 绑定样式:
绑定style内联样式: 2种:
1. 将整个style属性值当做一个大的字符串去绑定
问题: 如果使用style绑定样式,说明经常会单独修改一个样css属性值。而如果style是一个字符串,非常不便于程序仅修改其中一个css属性。
解决: style支持对象形式绑定
2. 以对象形式绑定style
2步:
1. 在data中定义一个内嵌对象结构,保存style中每个css属性
比如: 希望div#pop的位置上下左右变化,可定义对象:
data:{
popStyle:{
left:"100px",//必须带单位
top:"50px"
}
}
2. 在HTML元素的style上,用冒号绑定data中的样式对象,比如:
<div id="pop" :style="popStyle"></div>
运行时: new Vue()会自动将
popStyle:{
left:"100px",//必须带单位
top:"50px"
}
转化为字符串: "left:100px; top:50px"
结果还是: style="left:100px; top:50px"
说明: 如果div中还有部分固定的内联样式,可将普通style和:style同时使用。比如:
<div id="pop" style="width:100px; height:100px;" :style="popStyle"></div>
运行时: 先将:style中的对象编译为字符串,再和固定不变的普通style内容合并到一个style中。
结果: <div id="pop" style="width: 100px; height: 100px; left: 100px; top: 50px;"></div>
绑定class: 2种方式:
1. 以字符串绑定class——不好
2. 以对象方式绑定class
2步:
1. data中定义个对象,包含所有要显示的class作为属性名。用true/false控制哪个class应用,哪个class不用。
比如: data:{
phoneClass:{
vali_info:true,//默认启用
vali_success:false,//验证通过启用
vali_fail:false//验证失败才启用
}
},
2. html中用:class,绑定data中的对象
比如: <span :class="phoneClass">1[3-9]\d{9}</span>
结果: new Vue()自动将phoneClass中,所有标记为true的class名,拼接为字符串,替换元素中class的内容,应用指定的class。比如
phoneClass:{
vali_info:true,
vali_success:true,
vali_fail:false
}
会被翻译为"vali_info vali_success"
最终: <span class="vali_info vali_success"
其实: :class="对象"中变化的类名,也可以和其他固定不变的类名同时存在:
比如: <span class="vali" :class="phoneClass">
结果: 先翻译: phoneClass为:
"vali_info vali_success"
再和class="vali"组合形成一个class
最终: <span class="vali vali_info vali_success"
3. 计算属性:
什么是: 属性的值不是实际存在的,每次加载时都需要动态计算出来
何时: 只要想使用的值,不是现成的,需要动态计算才能获得
如何: 2步:
1. 在new Vue中定义计算属性的逻辑
new Vue({
el:"#app",
data:{ 变量1, 变量2, ... },
computed:{
汇总的属性名(){
return 汇总结果
}
}
})
比如: 定义计算属性,动态计算购物车中商品的总价:
data:{
cart:[
{pname:"iphonex",price:5566,count:2},
{pname:"iphonexs",price:8888,count:3},
{pname:"iphonexs max",price:9999,count:1}
]
},
computed:{
total(){
console.log("计算了一次总价");
//先定义变量
var sum=0;
//遍历cart中每个商品
for(var p of this.cart){
//每遍历一个商品,就就计算小计,并汇总到结果中
sum+=p.price*p.count;
}
return sum;
}
}
2. 在页面元素中,使用绑定语法,直接绑定计算属性的函数名:
<ANY>{{汇总的属性名}}</ANY>
不要加()
比如: <td>总价:¥{{total.toFixed(2)}}</td>
原理: 当在绑定语法中发现模型变量时,先在data中找。如果data中没有,就会进入computed中查找。如果找到computed中的计算属性,就调用计算函数,然后将返回的结果,替换回页面中需要绑定的位置。
vs 普通函数:
1. 用法: 绑定函数的返回值: {{函数名()}}
绑定计算属性: {{属性名}} //不用加()
2. 重复计算:
如果多次绑定函数的返回值,绑定几次,就重复调用函数执行几次。效率低。
如果多次绑定计算属性,无论绑定多少次,只在第一次绑定时执行一次计算,然后,将计算结果立刻缓存在vue中。当下次再绑定时,直接取出缓存的值使用。避免重复计算——效率高。
3. 使用场景:
如果更关心函数的返回值用于显示时,首选计算属性
如果不关系返回值,而是更关系执行过程时,首选普通函数
4. 自定义指令:
如果希望给HTML元素添加13种指令之外的新功能,就可自定义指令。
如何:
1. 创建: 一个名为v-focus的指令
Vue.directive("focus",{//强调: 不要加v-前缀
inserted(dom_elem){
dom_elem.DOM函数()
}
})
2. 使用:<ANY v-focus></ANY>
原理:
当new Vue()时,Vue框架会扫描原始DOM中的元素
只要发现带自定义指令的元素,就触发自定义的inserted()函数,对当前DOM元素,执行预先定义好的DOM操作。
5. 过滤器:
什么是: 对data中原始值进行再加工,然后再显示的一种特殊的函数。
何时: 只要data中的值不能直接显示给人看时
比如: 性别:0,1 时间/日期的毫秒数
如何:
1. 创建过滤器函数:比如,创建将性别0和1转为女和男的过滤器
Vue.filter(
"sexFilter", //过滤器函数名
function(oldValue){//过滤器函数本身
//至少有一个形参接收来自data中变量的原始值
//对原始值加工后返回新值
return oldValue==1?"男":"女";
//必须有返回值
}
)
2. 在绑定语法中使用过滤器
<h1>性别:{{sex|sexFilter}}</h1>
其中: 使用|将过滤器函数连接到sex原始变量的后边。
执行时,sex的值,自动传给过滤器sexFilter的函数的形参oldValue,经过过滤加工,将返回的新值显示到绑定位置。
其实,过滤器可以带参数,来选择不同的返回值样式:
比如:定义可根据语言选择返回不同语言性别的过滤器
Vue.filter(
"sexFilter",
function(oldValue,lang="cn"){//en cn
if(lang=="cn"){//如果传入cn或不传入,则默认都返回中文的男女
return oldValue==1?"男":"女"
}else{//否则,返回英文的男女。
return oldValue==1?"Male":"Female"
}
}
)
使用带参数的过滤器:
<h1>性别:{{sex|sexFilter("en")}}</h1>
<h1>性别:{{sex|sexFilter("cn")}}</h1>
<h1>性别:{{sex|sexFilter}}</h1>
强调: 虽然定义形参lang时,lang处于第二个形参,但是使用过滤器时,因为原始值自动占了第一个形参oldValue,所以,自定义传入的实参值cn或en,就可直接作为第一个实参传入。实际给的确实第二个形参lang。
总结:
var vm=new Vue({
el:"#app",//引入html元素,形成虚拟DOM树
data:{ //保存页面需要的所有模型变量
//页面中有几处变化,data中就要有几个变量支持
uname:,
sex:,
popStyle:{
css属性: 属性值,
... : ...
}
phoneClass:{
样式类: true,
... : ...
}
},
methods:{ //所有函数
处理函数(){
this->new Vue()
this.变量
},
自定义函数(){ ... }
},
watch:{ //所有对data中变量的监听函数
变量名(){ //变量名要和data中的某个变量同名
}
},
computed:{//计算属性
total(){
return
}
}
})
Day 03
正课:
1. Axios
2. 组件
3. 组件化开发
4. SPA
1. Axios:
什么是: 基于promise的专门发送ajax请求的函数库
为什么: 在vue中发送ajax请求
1. 自己写ajax四步/五步: 代码重复严重
2. jQuery中$.ajax(): 大材小用,得不偿失。
jQuery不是专门执行ajax请求的。而是执行所有DOM操作的函数库。包含大量的DOM操作的函数。而在vue中其实只需要$.ajax(),其余函数根本用不上。
3. Vue框架自带ajax请求的模块: vue-resource: 只能在vue中使用。
4. Vue官方推荐: axios
可在任何位置发送ajax请求
index.html ->
new Vue() ->
node.js index.js ->
何时: 今后,只要在vue中发送ajax请求,都用axios
如何:
1. 引入axios.js
2. 发送请求:
get方式:
axios.get("url",{
params:{
请求参数: 参数值
}
}).then(function(返回结果result){
result.data 才是服务器返回的结果
})
比如: 用id查询一个商品
axios.get("/products/getById",{
params:{
lid:5
}
})
//http://localhost:3000/products/getById?lid=5 ->
// { lid:5, title: macbook, subtitle: 优惠酬宾, ... } <-
.then(function(result){
var product=result.data;
})
2. 组件:Component
什么是: 拥有专属的HTML,CSS,JS和数据的可重用的页面独立区域。
为什么: 可重用
何时: 只要发现页面中一个独立的功能/区域反复被使用,都要封装为组件。
如何:
1. 封装组件:
Vue.component("组件名",{
template:`HTML片段`, //代替了以前的el
//<button>-</button><span>{{n}}</span><button>+<bu
data:function(){
return {//相当于以前的data
n:1
}
},
其余成员和new Vue中完全一样
methods:{
事件处理函数
},
watch:{
对变量实时监控
},
computed:{
计算属性
}
})
比如: //创建一个名为my-counter的组件
//将来反复在主页面中使用
Vue.component("my-counter",{
template:`<div>
<button @click="sub">-</button>
<span>{{n}}</span>
<button @click="add">+</button>
</div>`,
data:function(){
return { n:1 }
},
methods:{
sub(){ this.n--; },
add(){ this.n++; }
}
})
2. 反复使用组件: 组件其实就是一个可重用的自定义HTML标签而已。
<组件名></组件名>
比如: <my-counter></my-counter>
原理:
Vue.component()将组件模板添加到Vue大家庭中备用。
new Vue()扫描DOM树时,发现自定义标签,就在Vue家里找到同名组件,用template替换页面的自定义标签。
同时调用组件的data()函数,为此处的一个组件示例下一个专属的蛋(数据data对象{n:1})
将来,每替换一个自定义标签,说明组件被使用了一次,就会自动调用一次data()函数,返回一个专属的数据对象给当前组件专门使用。
3. 组件化开发:
什么是: 将来所有的网页都是由组件组成的。拿到网页后先划分组件。再分别编写每个组件的HTML,CSS和Vue代码。最后再拼接到一起
为什么: 可多人团队协作开发
调试方便,组件之间互不影响
何时: 今后所有网页必须都用组件化开发。
如何:
1. 拿到页面后,先划分组件
2. 创建组件: Vue.component() 同上
3. 在主页面中引入组件: <todo>同上
4. new Vue()
问题: 用Vue.component()创建的组件可以出现在页面的任何位置,不受限制
解决: 限制子组件必须出现在规定的父组件内才有意义
如何: 3种组件:
1. new Vue({ el:"#app" }) —— 根组件
通常只有在项目唯一的首页上才只有一个new Vue()
2. Vue.component() —— 全局组件
可出现在页面的任何位置
3. 子组件: 被限制在一个固定父组件内使用的组件
何时: 今后只要一个组件,有明确的使用范围,不能乱放时,都要定义成子组件
如何: 2步:
1. 创建子组件: 与创建全局组件内容相同,但降级为普通对象定义格式:
比如: todo-item必须属于todo-list下才有意义:
var todoItem={
template:`<li>
1 - 吃饭 <button>x</button>
</li>`
};
强调: 子组件名必须用驼峰命名!因为之后会被自动翻译为-分隔,比如: todoItem -> Vue -> todo-item
2. 在父组件中添加components属性,包含子组件对象
比如: var todoList={
template:`<ul>
<todo-item></todo-item>
<todo-item></todo-item>
<todo-item></todo-item>
</ul>`,
components:{ todoItem } //强调,这里必须和上一步定义子组件时的变量名保持一致。
}
结果: <todo-item>就只能在<todo-list>下使用
组件间传递数据:
父->子:
1. 子: 为组件定义自定义属性,将来用于从父对象中绑定获得父对象中的变量。
var 子={
template:`... `,
data(){
//仅限于子组件自己使用的内部变量
},
//定义 自定义属性
props:[ "tasks" ]
}
2. 父: 通过绑定子组件的自定义属性,将自己的变量交给子组件
<子 :tasks="tasks"></子>
孩子的兜 <-- 爹的变量
4. SPA: Single Page Application
单 页面 应用
什么是: 一个应用程序虽然有很多界面,但是只有一个完整的物理页面.html文件。
我们看到的“界面”,其实都是一些较大的组件
通过对地址栏中的相对路径判断,动态决定替换成哪种组件。
为什么:
多页面 |
单页面 |
一个应用中包含多个.html |
一个应用中只有一个.html |
每切换一次页面,都会重新发送请求——请求次数多 |
所有组件都是在首页第一次加载时,已经全部加载过来了。每切换一次页面,不需要向服务器重新发起页面请求。只是在客户端本地挑选匹配的组件替换页面内容而已。——请求次数少 |
每次切换页面时,都要重建整棵DOM树——效率低 |
每次切换界面时,不需要整棵重建DOM树,只要替换局部的节点对象即可。——效率高 |
对于共用的资源,每次切换页面,都要重复请求。 |
每次切换界面时,因为<head>中的引用没变,所以不会重复请求共享的资源。 |
如何实现单页面应用:
1. 划分"页面"组件: —— 组件结构图
2. 创建组件: 同创建普通组件
3. 定义唯一的完整的.html页面
引入公共的资源:
<link rel="stylesheet" href="css/bootstrap.css">
...
引入vue.js和vue-router.js
引入所有组件对象的所在的js文件备用
<body>中
<div id="app">
<my-header/>页头组件,所有页面共用
<router-view/>临时占位,将来会根据路由地址不同,动态选择不同的组件template替换<router-view>所在位置。
4. 定义路由字典:
路由字典是保存所有相对地址和对应组件配对儿信息的数组。
var routes=[
{path:"/",component:index},
{path:"/details/:lid",component:details,props:true},
{path:"/products",component:products},
{path:"*",component:{
template:`<div><h2 style="color:red">404:Not found——东哥写的,不是报错</h2></div>`
}},
];
5. 将路由字典加入路由器中
var router=new VueRouter({routes})
6. 将路由器放入new Vue()中
var vm=new Vue({
el:"#app",
data:{},
router
})
运行时:
http://127.0.0.1:5500#/
http://127.0.0.1:5500#/details
http://127.0.0.1:5500#/products
强调: vue路由才用锚点地址#/xxx来识别不同路径。必须加#
跳转:
2种:
1. 写死的链接: 所有a都换成<router-link
<router-link :to="/details"></router-link>
最终会被翻译回: <a href="#/details"></a>
2. 用程序跳转: 登录成功后跳转回首页
this.$router.push("/地址")
url地址传参:
1. 路由字典中:
var routes=[
{path:"/details/:lid", component: details, props:true}
] //让lid自动传给props中同名的变量
强调:
1. 凡是带参数的地址,访问时必须带参数才能进入。如果不带参数,会跳转到404
2. 在目标组件对象中定义同名props属性
var details={
...
props:[ "lid" ]
}
3. 在跳转时传参:
/details/5 //没有: ,没有?, 没有变量名=
Day 04
正课:
1. 脚手架
2. ***VUE/组件的生命周期
1. 脚手架:
什么是: 已经具有核心功能的半成品项目代码
我们只要在规定位置填入个性化定制的功能即可
为什么: 简化开发
如何:
1. 安装脚手架的工具命令:
npm i -g @vue/cli 电脑安装完命令后 : 直接创建 vue create 文件夹名字
2. 用命令反复创建脚手架:
cd 要保存项目的文件夹完整路径
比如: cd C:\xampp\htdocs\dd\6_VUE\day04
用vue命令工具,创建一个项目的脚手架代码
1. Your connection to the default npm registry seems to be slow.
Use https://registry.npm.taobao.org for faster installatio
n? (Y/n) n
2. ? Please pick a preset: (Use arrow keys)
default (babel, eslint)
> Manually select features
3. ? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Babel 将脚手架中浏览器不认识的一切东西翻译为浏览器认识的。 必选 相当于 翻译官
( ) TypeScript 更严格的javascript,ng框架使用
( ) Progressive Web App (PWA) Support
(*) Router 必选
(* ) Vuex 为下一阶段做登录/购物车做准备
( ) CSS Pre-processors
( ) Linter / Formatter 代码格式检查工具,要求过于变态
( ) Unit Testing
( ) E2E Testing
4. Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) n
history模式可去掉地址栏中的#
但需要服务端同步配置重定向,才能让客户端支持
所以,学习时,不用启用history
5. Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? (Use arrow keys)
In dedicated config files
> In package.json //在package.json一个文件中,保存所有配置信息
6. Save this as a preset for future projects? (y/N) N
是否保存以上配置步骤的选项为今后所有项目的默认配置。不保存。因为不同项目需要的组件可能不一样。
3. 运行脚手架项目: npm run serve
临时启动一个简易版的调试服务器来宿主html,css,js
将脚手架中浏览器不认识的代码编译为浏览器认识的代码
在默认: http://localhost:8080/
打开浏览器在地址栏中: http://localhost:8080/
问题: npm run serve仅临时编译代码,并运行,不产生最终编译结果。就不能部署上线。
解决: npm run build
将脚手架中浏览器不认识的代码编译为浏览器认识的代码
将编译后的代码压缩为统一的文件。
将来: 往新浪云上拷贝时,只拷贝dist/中的内容即可。
4. 服务端项目配置:
1. cors:
origin: 以前是http://127.0.0.1:5500
现在要改为http://localhost:8080
credentials:true 允许接收客户端带来的身份信息
5. 客户端vue项目配置:
1. axios:
问题: 默认不带axios
解决: 安装: 在xz_vue/内,运行npm i -s axios 或者 npm install axios -S
问题: 将来我们希望在所有Vue组件内,使用axios
this.axios.get("url",{params:{参数:值}})
解决: 在main.js中,将axios对象添加到Vue的原型对象中。
在mian.js中配置axios
//mian.js是根组件 new Vue,所有所需的模块和对象都要在new Vue之前配置好
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
//手动引入-------这个是需要亲自手动添加的,其他代码,脚手架自带
import axios from 'axios' //引入axios文件
Vue.prototype.axios=axios //所有组件都是Vue.prototype的孩子
axios.defaults.withCredentials=true //让axios的请求携带验证信息到服务端(钥匙)
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
正课:
1. 脚手架
2. 组件的生命周期
1. 脚手架:
什么是: 前人总结的包含优秀开发经验的半成品项目
为什么: 避免重复劳动
何时: 今后只要使用框架开发,都用脚手架代码
如何: 2步:
1. 安装命令行工具——用于生成脚手架代码的工具
npm i -g @vue/cli
2. 用命令行工具生成脚手架代码——创建项目
vue create 项目名
babel: js代码翻译工具
将浏览器不认识的新标准的js代码,翻译为浏览器认识的ES5的等效代码,比如
ES6中也定义了模块:
抛出模块: export default { ... }
等效于node中的module.exports={ ... }
引入模块: import from "模块名"
等效于node中的require("模块名")
浏览器不认识,只能请babel翻译为ES5的等效代码。
结果: 在当前运行命令的目录创建了一个项目文件夹,其中包含了脚手架代码
测试: cd 项目名 进入项目文件夹
npm run serve
1. 启动临时开发服务器(development Server),宿主编译后的静态页面
2. 编译(compile / build)脚手架代码中浏览器不认识的内容为认识的内容
3. 在脚手架代码中填写个性化的内容
问题: 脚手架代码不包含axios
解决: 安装和配置axios
1. 在项目本地安装axios: npm i -save axios
2. 将axios对象放入vue的原型对象中:
main.js是整个vue项目的唯一根组件new Vue
所有需要的模块或对象,都要在new Vue之前配置好
坑: axios默认不带钥匙到服务器,也就无法打开自己的柜子,访问自己的信息。
解决: 在main.js中要求axios必须携带钥匙
axios.defaults.withCredentials=true;
2. 组件的生命周期:
什么是: 一个组件的加载过程
包括: 4个阶段:
1. 创建: create 创建组件对象和模型数据对象data:
相当于: Vue.component("",{
data(){ return { ... } }
})
2. 挂载: mount 扫描页面构建虚拟DOM树,并首次绑定数据到页面指定位置。
相当于: Vue.component("",{
data(){ return { ... } },
template:"#tplXXX" //虚拟dom树
})
3. 更新: update 当模型变量被更改时,自动触发
4. 销毁: destroy 当主动调用销毁方法销毁组件时自动触发
如果希望在生命周期的不同阶段自动执行一项任务,就要绑定生命周期钩子函数:
包括: 4个阶段,包括8个钩子函数
1. create:前 beforeCreate(){ ... }
后 created(){ //有data,没有虚拟DOM树
//ajax请求为了初始化data,此时已经有data对象了,所以已经可以发送ajax请求
this.axios.get("url",{
params:{ 参数 }
}).then(res=>{
this.模型变量=res.data.属性名
this.products=res.data;
})
//暂时不能执行DOM操作,比如让元素获得焦点
}
2. mount: 前 beforeMount(){ ... }
后 mounted(){//即有data,又有DOM树
//也可以写ajax请求
//可以执行DOM操作
}
了解:
3. update: 前 beforeUpdate(){ ... }
后 updated(){ ... }
4. destroy: 前 beforeDestroy(){ ... }
后 destroyed(){ ... }
<template><template>标签,html5中专门用于为框架/组件保存一段影藏的模板片段,相当于<div style=”display:none”></div>
第四阶段
Day 01
今天学习的内容
程涛 taonetwork2018
1:第四阶段课程简介
vue移动端组件库和项目 6day
html5新特性(视频/绘图) 7day
微信公众平台 --小程序 6day
混编 1day
2:vue UI 组件库
vue 当前很火前端框架,用户数众多
vue 开始针对pc端用户而不是针对移动设备开发
国内团队:饿了么[MintUI/ElementUI],滴滴打车,MUI...
MintUI 针对移动端开发组件库
ElementUI 针对PC端用户开发组件库
2.1:补充知识点:PC端项目和移动端项目
-区别:屏幕宽度
PC端: w > 992px
移动端: w < 992px
-区别:操作方式
PC端: 鼠标和键盘
移动端: 手指
-区别:事件
PC端: keyup/keydown/click/blur/..
移动端: touchstart/touchmove/touchend/tap/longtap
2.2:vue ui mint-ui组件使用
下载安装提供二种方式
(1)方式一:(学习)
mint-ui官方网站下载 css/js/fonts 加载当前html文件中
(2)方式二:
vue cli 脚手架工具当下载配置使用[录像]
下载指令 npm i mint-ui -S
2.3:vue cli 脚手架
-vue cli 如何生成
1:vue cli 创建项目 (?)
2:vue cli 开发自动化工具生成 webpack (?)
-vue cli 目录结构
package.json 配置信息
-vue cli 启动项目
npm run serve
#注意启动目录
..vue_app_00/npm run serve
2.4:将mint-ui引入脚手架 main.js
(1)按需引入
(2)完成引入
import Vue from 'vue'
import MintUI from 'mint-ui' #完整引入mint-ui库组件
import 'mint-ui/lib/style.css' #单独引入样式文件
import App from './App.vue'
Vue.use(MintUI) #将mint-ui库所有组件注册
#vue实例对象中
new Vue({
el: '#app',
components: { App }
})
2.5:第一个mint-ui组件 Toast
简短消息提供框
示例:1:创建组件 src/components/Exam01.vue 空
2:指定路径 src/router.js /Exam01
3:执行组件在浏览器地址栏输入
http://127.0.0.1:8080/#/Exam01
-基本用法
this.$toast({})
参数:
message:提示消息文本的内容
position:位置 top;bottom;middle
duration:持续时间(单位毫秒) 3000 ; -1不关闭
className:类名为其添加样式
.mytip{ background:#fff !important; color:red !important; font-size:12px !important; } |
iconClass:图标类名
示例:Exam01.vue
2.6:提示框中可以显示图标
https://www.iconfont.cn/ 阿里妈妈专业图标网站
(1)下载图标
-将图标加入购物车
-点击购物车,下载代码
(2)将图标应用当前项目
-在src创建目录font 上目录用于保存字体图标文件
-main.js 引入字体图标文件css文件
import "./font/iconfont.css"
-应用方法
<i class="iconfont icon-gao"></i>
-iconClass:"iconfont icon-gao"
#注意:字体图标可以修改大小
#修改 src/font/iconfont.css
# .iconfont {
font-family: "iconfont" !important;
font-size: 16px;
}
2.6:弹出式交互提示框
标准语法: this.$messagebox({})
title 提示框的标题 String
message 提示框的内容 String
showConfirmButton 是否显示确认按钮 boolean
showCancelButton 是否显示取消按钮 boolean
示例:创建
组件: src/components/ExamMessageBox02.vue
路径: /ExamMessageBox02
2.7:表单输入域:表单编辑器
<mt-field label="用户名" placehodler="请输入用户"
v-model="uname"></mt-field>
type 输入框类型 text/number/url/date/password...
label 标签
placeholder 占位符
readonly 只读
attr: 设置原生属性
state 校验状态 error;success;warning
示例:创建
组件: src/components/ExamField03.vue
路径: /ExamField03
2.8:使用mint-ui 完成淘宝登录
练习:分析功能
1:第一个输入域
[请输入手机号码]
[手机号/邮箱/会员名]
2:[帐户密登录]
-创建组件 Login.vue /Login
作业1:完成Login04.vue 登录组件
-用户名和短信切换
-密码框显示与隐藏
-按钮提示文字切换
Day 02
今天学习内容
1:复习昨天重点知识
2:作业 仿淘宝登录
3:今天的目标
mint-ui组件库官方网站:
http://mint-ui.github.io/#!/zh-cn
3.1:mint-ui 组件库-表单
-开关组件
<mt-switch v-model="val1">开关</mt-switch>
val1:true
-单选框列表
<mt-radio
title="单选框列表"
v-model="val2"
:options="['选项a','选项b','选项c']">
</mt-radio>
-复选框列表
<mt-checklist
title="复选框表"
v-model="val3"
:options="['选项A','选项B','选项C']">
</mt-checklist>
3.2:mint-ui 组件库-面板--(重点)
面板,可切换显示子页面
<mt-tab-container v-model="active"> 父元素(面板)
<mt-tab-container-item id="tab1"> 子面板1
<mt-cell v-for=""></mt-cell> 单元格
</mt-tab-container-item>
<mt-tab-container-item id="tab2"> 子面板2
<mt-cell v-for=""></mt-cell> 单元格
</mt-tab-container-item>
<mt-tab-container-item id="tab3"> 子面板3
<mt-cell v-for=""></mt-cell> 单元格
</mt-tab-container-item>
</mt-tab-container>
注意:改变active值与子面板id一致即显示对应子面板
练习: 在data中保存数组件,
(1)list["美食","购物","休闲"]
(2)依据数组值创建三个mt-button
(3)点击按钮完成子面板切换
(4)当前被点击文字高亮
3.4:mint-ui 组件库-面板--(重点)
底部选项卡,点击tab会切换显示页面,
<mt-tabbar v-model="selected" fixed>
<mt-tab-item id="外卖">
<img slot="icon" src="../asserts/100*100.png" />
外卖
</mt-tab-item>
<mt-tab-item id="订单">
<img slot="icon" src="../asserts/100*100.png" />
外卖
</mt-tab-item>
</mt-tabbar>
- fixed 固定在页面底部
-value 返回当前选中tab-item的id
3.5:微信
(1)创建components/weixin/Home.vue 全局组件
(2)从上到下设计每一个组件
(3)最上面子组件 components/weixin/common/TitleBar.vue
(4)简洁示例 F.vue父 S.vue子元素
Day 03
今天学习的内容
1:复习上周重点
2:今天的目标
2.1:mint-ui组件库;综合应用 微信
2.2:网页结构分析
2.3:创建项目目录
weixin 项目目录
common 子组件
json 数据文件
Home.vue 入口组件
2.4:顶部标题栏
-将标题栏创建成一个子组件作为Home.vue一部分
-分析分为二个部分左侧文字右侧两张图片
-使用弹布局由于标题栏固定,定位方式 fixed
-common/TitileBar.vue
注意:左侧文字 右侧图片 两张点击事件由父元素
2.5:消息面板创建
-Message.vue 消息子组件
负责消息外观设计:
左侧:图片
左侧:标题和子标题
右侧:时间
-MessageList.vue 消息列表子组件
负责加载数据 weixin/json/messagelist.json
创建循环
并且在循环调用Message.vue 子组
-Home.vue 调用MessaeList.vue 子组件
2.6:底部导航栏 tabbar
-图片 ic_weixin_normal.png/ic_weixin_selected.png
-tabbar中图片创建单独组件
-子件组TabBarIcon.vue 图片显示与切换样式
-在Home.vue 创建 tabbar中间图片TabBarIcon.vue
3:项目阶段:学子商城
-用户登录(**)
-商品列表
-商品详情
-购物车(*****)
作业:
(1)复习weixin 项目(重点)
(2)用户登录组件 Login.vue
(3)session 百度搜索
(4)mysql 查询SQL SELECT
Day 04
今天学习的内容
1:复习昨天的重点
2:今天的目标
2.1:weixin完成--(重点)
2.2:学子商城--登录
用户输入用户名和密码点击提交按钮,
如果格式出错 提示:用户名格式不正确 密码格式不正确
用户不存在 提示:用户名或密码不正确
正确 跳转商品主页
2.3:学子商城--数据库-加密
t_login[id/uname/upass]
id INT PRIMARY KEY AUTO_INCREMENT,
uname VARCHAR(255)
upass VARCHAR(32)
2.3:学子商城--数据库
由于用户登录密码要求安全度比较高,习惯加密保存
示例:
tom/123
t_login
id uname upwd
1 tom 123 #错误保存方式
解决思路:
将密码:123 原先密码 -> 加密技术 ->x93k3s82820sk202jd98i
id uname upwd
1 tom 202cb962ac59075b964b07152d234b70 #正确
解决办法: md5(); 加密函数 32位
md5(123) => 202cb962ac59075b964b07152d234b70
常规安全思路:
(1)用户密码8位以上:数字/小写字母/大写字母/特殊字符
(2)多次加密
如何登陆:
(1)用户输入用户名和密码 tom/123
(2)node.js 接收用户 tom/123
(3)将用户输入123加密 #判断方式密码比较密码 52
md5(123) =>202cb962ac59075b964b07152d234b70
(4)sql语句完成登录验证
SELECT id FROM t_login WHERE uname = ? AND upwd = md5(?)
(5)数据库表
id uname upwd
1 tom 202cb962ac59075b964b07152d234b70 #正确
2.4:项目目录结构
2.5:学子商城--cors 跨域
vue-cli 脚手架 8080 Login.vue
vue-server-app node.js服务器 3000
#以上程序在执行由于8080访问另一个程序3000
#跨域访问
解决方案:
(1)jsonp
(2)cors 第三方模块安装配置node.js即可
-下载cors
-在node.js 服务器配置:哪个程序可以跨域访问当前node.js
const cors = require("cors");
server.use(cors({
origin:[允许跨域请求程序地址],
credentials:true # 是否验证
}));
示例:允许脚手架8080跨域访问 node.js
const cors = require("cors");
server.use(cors({
origin:["http://127.0.0.1:8080","http://localhost:8080"],
credentials:true # 是否验证
}));
2.6:学子商城--session-cookie
session对象:原理
在服务端保存用户专有数据对象.[uid]
由于session对象保存服务器端安全性高
-session对象:当用户访问网站第一个网页,就创建session
对象(session开始)中间用户可以打开多个网页(会话中),
当用户关闭浏览器(会话结束)一旦会话结束,会话对象中保存
数据也就丢失.
session对象作用:用于保存用户登录凭证,通常凭证用户编号
-在项目添加 session 功能
(1)将数据保存session对象中
req.session.uid = 1;
(2)从session对象中获取数据
var uid = req.session.uid;
2.7:在项目如何添加session功能
(1)引入模块
const session = require("express-session");
(2)配置模块
server.use(session({
secret:"128位字符串", #128位字符串
resave:true, #每次请求是否更新数据
saveUninitialized:true #保存初始化数据
}));
(3)当用户登录成功,将用户uid 保存session对象
req.session.uid = 1;
(4)其它模块读取session中uid [购物车/订单]
var uid = req.session.uid;
常见概念上错误
哪个是服务器/哪个是脚手架/node_modeuls在哪里
每个程序有自己独立node_modeuls 相互没关系
2.8:学子商城--用户登录
src/components/xz/Login.vue 登录组件[参考淘宝登录]
1:用户名输入框/密码输入框/登录按钮
2:占位符
3:外观样式参考淘宝登录
4:用户名和密码必须通过正则表达式验证 messagebox
5:发送ajax请求 axios 验证
src/components/xz/Home.vue 商城首页
2.9:ajax 库axios
#兼容性不错
(1)设置请求服务器原始路径(基础路径)
http://127.0.0.1:3000/login
http://127.0.0.1:3000/cartlist
http://127.0.0.1:3000/cartRemove
...
axios.defaults.baseURL = "http://127.0.0.1:3000/";
.get("login");
.get("carlist");
.get("cartRemove");
(2)设置跨域请求保存session值
axios.defaults.withCredentials=true
作业:学子商城 用户登录组件Login.vue
404 错误 发送的请求地址 服务器没有 地址错误
{path:'/',redirect:"/XZHome"}, //redirect 重定向
Day 05
今天学习的内容
1:复习昨天的内容
2:今天的目标
2.1:session
2.2:session:会话
会话指操作过程:
-会话开始:当用户打开网站一个网页
-会话中:中间用户可以打开此网站多个网页
-会话结束:当用户关闭浏览器
2.3:session对象 [会话对象]
session对象是在当前会话保存数据专用对象
在当前会话中所有网页*享此数据
当会话结束结束:session 对象保存数据也丢失
2.4:session对象工作原理
-当会话开始在服务器端创建session对象
-为了保存数据安全性,服务器会将session对象中数据加密保存
-将session id值发送客户端浏览器cookie保存
-cookie保存session id 做为用户凭证
-如果会话结束 session对象失效/对应cookie失效
2.5:node.js在程序如何启session
-引入模块
const session = require("express-session")
-配置模块
server.use(session({
secret:"128位字符串", #自定义字符串
resave:true, #每次请求更新数据
saveUninitialized:true #保存初始化数据
}));
-在项目登录时将用户id 保存session
req.session.uid = 2; #正确
req.session.id = 2; #错误
-其它的功能直接读取id 即可作为用户登录成功凭证
示例:显示购物车,谁购物车 var uid = req.session.uid;
#注意:将数据保存至session坑名称
保存数据名称不要叫id原因 session对象有一个属性id
2.6:脚手架配置
axios 默认情况下发送ajax跨域请求丢失session
axios.defaults.withCredentials=true
发送ajax请求基础路径
axios.defaults.baseURL="http://127.0.0.1:3000/"
示例:登录
this.axios.get("login");
2.7:出错调试
1:F12->查看控制台->如果有错读错误理解问题原因
2:F12->NETWORK->
Header
Response
3:一行一行调试
handler for "click": "ReferenceError: n is not defined"
原因:n没有定义
net::ERR_CONNECTION_RESET
原因: node.js 服务器出错停止工作
解决:查看node.js 控制台窗口读取出错信息
Error: connect ECONNREFUSED 127.0.0.1:3306
原因:mysql停止工作没有启动或者出错
2.8:完成学子商城--用户登录-组件跳转
this.$router.push("组件路径")
示例:
登录成功/Home
this.$router.push("/Home");
2.9:完成学子商城--商品列表-分页
-数据库
xz_laptop[lid/title/price]
-app.js
/product
参数: pno页码=1 ;pageSize页大小=4
sql: SELECT lid,title,price FROM xz_laptop LIMIT ?,?
第一问号:查询起始行数 (pno-1)*pageSize; 页码减一乘以页大小
第二问题:一次查询几行 pageSize
json: {code:1,msg:"查询成功",data:result}
-xz/product.vue
2.10:完成学子商城--商品列表-分页
-当组件创建成功后加载第一页数据
created()
(1)发送ajax请求服务器 /product?pno=1
(2)服务器返回第一页数据{code:1,msg:"成功",data:[]}
(3)获取数据并且创建循环显示内容
-当用户点击"加载更多" 加载下一页数据
click
(1)加载更多:数据追加
0
2.11:创建xz/Home.vue 组件
-子标题组件
-分隔块
-面板
-tabbar
作业:学子商城tabbar完成
今天学习的内容
1:复习昨天的重点
2:今天的目标
2.1:完成weixin--面板
<mt-tab-container v-model="active">
<mt-tab-container-item id="message">
<messagelist></messagelist>
</mt-tab-container-item>
</mt-tab-container>
2.2:完成weixin--底部导航条
<mt-tabbar v-model="active" fixed>
<mt-tab-item id="message">
图片:子组件
文字
</mt-tab-item>
</mt-tabbar>
2.3:完成weixin--底部导航条--按钮上显示图片子组件
TabBarIcon.vue
-focused:false 当前按钮是否是焦点
-selectedImage: 选中显示图片
-normalImage: 默认显示图片
2.4:修改tabbar默认样式
/*修改tabbar 默认文字颜色*/ .mint-tabbar>.mint-tab-item{ color:#999999; } /*修改tabbar 选中文字颜色*/ .mint-tabbar>.mint-tab-item.is-selected{ color:#45c018; } |
#注意:vue事件有一些修饰符 native:原生事件
如果自定义属性直使用事件绑定即可,如果调用组件库中组件
直接绑定失败情况,清加修饰符 native 启动原生事件绑定
父元素给子元素绑定事件 native
#注意:去除默认边框
-App.vue 根组件它的内补丁影响我们组件
-normalize.css->n.css 通用样式文件
public/index.html
2.4:学子商城--登录--分析
用户打开登录网页输入用户名和密码点击提交按钮
-格式出错 提示:用户名格式不正确
-用户不存在 提示:用户名或密码不正确
-正确 跳转商品主页
2.5:学子商城--登录--[后端程序]服务器-数据库
-进入xz库 USE xz;
-创建表用户登录表
xz_login [id 编号/uname 用户名/upwd 密码]
id INT PRIMARY KEY AUTO_INCRMENET
uname VARCHAR(50),
upwd VARCHAR(32),
通用功能:密码内容需要加密后保存不是原文件保存
1 tom 123 原文
1 tom sd09234ksd90239epsd093kds0923 密文
为什么密码需要加密保存防止工作人员泄密
解决思路:将密码加密处理
解决方法:md5() 单向加密算法 加密结果32位密码
"123" => 202cb962ac59075b964b07152d234b70
常规问题:
-md5单向加密没有解密算法
-md5多次加密 md5(md5('123'))
-更有效方法强化用户密码难:
8位以上/数字/大写/小写/特殊符号
如何登录流程
(1)用户输入用户名和密码 tom/123将数据发app.js
(2)app.js 接收用户输入 tom/123
(3)app.js 将用户输入123加密与数据密码比较
SELECT id FROM xz_login WHERE name = ?
AND upwd = md5(?);
数据库 xz_login
1 tom 202cb962ac59075b964b07152d234b70
(4)pool.query(sql,[uname,upwd],(err,result)=>{
if(err)throw err;
if(result.length==0){
res.send({code:-1,msg:"用户名或密码错误"});
}else{
res.send({code:1,msg:"登录成功"});
}
})
-添加测试数据
2.6:学子商城--登录--[后端程序]服务器-app.js
(1)加载第三方模式
express web服务器
mysql mysql驱动模块
cors 跨域 脚手架8080 app.js 3000
express-session session
#下载 npm i mysql express express-session cors
#必须联网完成以上操作
(2)配置第三方模式
-mysql 创建连接池 [必须条件]
-配置跨域 cors 指定哪个程序可以跨域访问服务器
origin:["http://127.0.0.1:8080","http://localhost:8080"]
-配置session
secret:"安全字符串", #加密字符串
resave:true, #每次请求保存session数据
saveUninitialized:true #保存初始化数据
(3)处理用户登录任务
server.get("/login",(req,res)=>{
-参数 uname/upwd
-sql SELECT id FROM xz_login WHERE uname = ?
AND upwd = md5(?)
-json {code:1,msg:"登录成功"}
});
测试:
(1)启动node app.js
(2)打开浏览器在地址栏输入
http://127.0.0.1:3000/login?uname=tom&upwd=123
按回车
http://127.0.0.1:3000/login?uname=tom&upwd=122
按回车
2.7:学子商城--登录--[前端程序]脚手架
-src/components/xz/Login.vue
-创建输入框 用户名 密码 提交按钮 (mint-ui)
-为提交按钮绑定点击事件
(1)获取用户名和密码
(2)正则表达式验证是否有误 显示短消息
(3)发送ajax请求
2.8:session-会话-(前端后端程序)
(1)session一个用户操作过程
-会话开始:当用户打开某个网站第一个网页
-会话中:中间用户可以打开此网站多个网页
-会话结束:当用户关闭浏览器
(2)session对象(在服务器为了保存此次会话专有数据对象)
session对象是保存当前会话中使用数据,在当前会话
中所有网页可以共享此数据,但是当会话结束session数据
失效
为什么使用session 对象,项目中有一些数据必须保存
session对象比如:当前登录用户编号 uid
解决问题:
作业1:完成学子商城用户登录组件
HTML5
Day01
今天学习的内容
1:复习上周重点
2:今天的目标
2.1:html5新特性--视频音频
-常见属性
controls 是否显示播放控件 <video controls >
autoplay 是否自动播放 <video autoplay> 兼容性太差
loop 是否循环播放
muted 是否静态播放
poster 在播放视频之前是否显示广告图片
preload 预加载方式(策略)
none:不预加载任何数据
metadata:仅预加载元数据
(视频时长;视频第一个画面;视频高度宽度)
auto:预加载元数据,还加载一定时长视频
2.3:html5新特性--视频高级特性--事件
-canplaythrough 当前视频加载结束可以播放事件
duration 获取视频时长
-ended 视频播放结束触发事件
-timeupdate 视频正在播放
currentTime 当前播放时间点
2.4:html5新特性--视频高级特性--样式
video 样式 object-fit
fill: 默认 "填充" 将视频拉伸操作填满父元素(变形)
contain: "包含" 保持原有视频尺寸,父元素留有空白区域
conver: "覆盖" 保持原有视频尺寸, 宽度或高度至少有一
个与父元素一致(裁切)
2.5:html5新特性--音频
基础知识: x.mp3 x.wav ...
<audio src="x.mp3" id="a3"></audio>
特性1:默认audio不可见,如果添加controls属性可见
特性2:属性方法事件大多数与视频相同
练习:创建复选框实现控制背景音乐播放练习
当选中复选框播放背景音乐 a3.play()
当清空复选框暂停播放 a3.pause()
cb.change = function(){this.checked==true}
2.6:html5新特性--在网页上绘图--(重点)
-网页绘制三种技术
(1)svg: 2D矢量图 用线段组成图形
特点:可以无限放大或缩小不会失真,颜色不够丰富
(2)canvas:2D位图 用像素点组成图形
特点:不可以放大或缩小,颜色细腻
(3)webgl:3D位图
尚未纳入 H5标准
2.7:html5新特性--在网页上绘图--canvas
(重点-工作流程-坐标系-单词多)
-坐标系
-工作流程
(1)通过标签创建画布
<canvas id="c3" width="500" height="400"></canvas>
注意事项:画布宽度和高度只能通过js 或者标签属性来赋值
但是不能使用css赋值(出现变形)
(2)通过js程序获取画布
var c3 = document.getElementById("c3");
(3)通过画布元素获取画布中指定画笔对象[上下文对象]
var ctx = c3.getContext("2d");
#2d平面图形
-绘制矩形
ctx.strokeRect(x,y,w,h); 绘制空心矩形
x,y 矩形左上角位置
w,h 短形宽度和高度
ctx.strokeStyle = "#fff"; 设置空心边框样式
ctx.lineWidth = 1; 设置空心边框宽度
ctx.fillRect(x,y,w,h); 绘制实心矩形
ctx.fillStyle = "#fff"; 设置实心填充样式
*ctx.clearRect(x,y,w,h); 清除一个矩形范围内所有元素
练习1:绘制左右移动空心矩形
06_rect_exam.html
练习2:绘制柱状销售统计图
07_rect_exam.html
-绘制文字(字符串)
var str = "石家庄"
ctx.font = "19px SimHei"; 字体与大小
ctx.fillText(str,x,y); 绘制文本
ctx.textBaseline = ""; 指定文本基线
["alphabetic","top","bottom"]
str:绘制文本
x,y:文本左上角位置
作业1:薪水统计图[柱状统计图]
var sales = [
{m:"一月",s:3000},
{m:"二月",s:3200},
{m:"三月",s:3400},
...
{m:"十二月",s:5400}
];
|| &&