JDBC
- JDBC是Java提供的连接数据库的一套接口。
使用JDBC访问数据库的过程
-
将数据库的驱动文件导入到项目中
- JavaSE项目:将jar文件复制到项目的包中-->jar右键-->Build Path-->Add to Build Path
-
加载数据库驱动
-
Class.forName("包名.类名"):创建类的对象,并将对象加载到内存中。
try { Class.forName("com.mysql.cj.jdbc.Driver"); System.out.println("数据库驱动加载成功!!!"); } catch (ClassNotFoundException e) { System.out.println("数据库驱动加载失败!!!"); }
-
DriverManager.registerDriver(new 数据库驱动()):注册数据库驱动。
try { DriverManager.registerDriver(new Driver()); } catch (SQLException e) { System.out.println("数据库异常!!!"); }
-
-
创建java.sql.Connection接口的实例,连接数据库。
// 连接对象 Connection conn = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // DriverManager.getConnection("url","用户名","密码") conn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true", "root", "123456"); } catch (ClassNotFoundException e) { System.out.println("数据库驱动加载失败!!!"); } catch (SQLException e) { System.out.println("数据库异常,请稍候再试!!!"); }
-
创建java.sql.Statement或java.sql.PreparedStatement接口的实例。将Java的字符串编译为数据库可以解析的SQL语句。
- 当执行SELECT语句时,需要使用语句对象的executeQuery()方法,此方法的返回类型为java.sql.ResultSet接口类型的实例,用于保存查询的结果。
// 连接对象 Connection conn = null; // 语句对象 Statement stat = null; // 结果集 ResultSet rs = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // DriverManager.getConnection("url","用户名","密码") conn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true", "root", "123456"); String sql = "select user_id,user_name,user_password,user_salary,user_birthday from user_message"; // 使用连接对象,创建语句对象 stat = conn.createStatement(); // 使用语句对象执行SELECT语句,并将查询的结果存入到结果集中 rs = stat.executeQuery(sql); } catch (ClassNotFoundException e) { System.out.println("数据库驱动加载失败!!!"); } catch (SQLException e) { System.out.println("数据库异常,请稍候再试!!!"); e.printStackTrace(); }
- 当执行INSERT/DELETE/UPDATE语句时,需要使用语句对象的executeUpdate()方法,此方法返回类型为int类型,表示INSERT/DELETE/UPDATE语句执行后,影响表中数据的行数。
-
处理结果
-
ResultSet的next()方法:将结果集的游标向下移动一行,游标移动后找到了数据返回true,否则返回false。
// 连接对象 Connection conn = null; // 语句对象 Statement stat = null; // 结果集 ResultSet rs = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // DriverManager.getConnection("url","用户名","密码") conn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true", "root", "123456"); String sql = "select user_id,user_name,user_password,user_salary,user_birthday from user_message"; // 使用连接对象,创建语句对象 stat = conn.createStatement(); // 使用语句对象执行SELECT语句,并将查询的结果存入到结果集中 rs = stat.executeQuery(sql); // 使用循环遍历结果集 while(rs.next()) { System.out.print(rs.getInt("user_id") + "\t"); System.out.print(rs.getString("user_name") + "\t"); System.out.print(rs.getString("user_password") + "\t"); System.out.print(rs.getDouble("user_salary") + "\t"); System.out.println(rs.getDate("user_birthday")); } } catch (ClassNotFoundException e) { System.out.println("数据库驱动加载失败!!!"); } catch (SQLException e) { System.out.println("数据库异常,请稍候再试!!!"); e.printStackTrace(); }
-
ResultSet的getXXXX(参数):获得结果集当前行指定列的数据。参数的类型可以为String,也可以是int类型。
-
-
关闭与数据库相关的对象,否则垃圾回收器不会释放相关的内存。
// 连接对象 Connection conn = null; // 语句对象 Statement stat = null; // 结果集 ResultSet rs = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); // DriverManager.getConnection("url","用户名","密码") conn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true", "root", "123456"); String sql = "select user_id,user_name,user_password,user_salary,user_birthday from user_message"; // 使用连接对象,创建语句对象 stat = conn.createStatement(); // 使用语句对象执行SELECT语句,并将查询的结果存入到结果集中 rs = stat.executeQuery(sql); // 使用循环遍历结果集 while(rs.next()) { System.out.print(rs.getInt("user_id") + "\t"); System.out.print(rs.getString("user_name") + "\t"); System.out.print(rs.getString("user_password") + "\t"); System.out.print(rs.getDouble("user_salary") + "\t"); System.out.println(rs.getDate(0)); } } catch (ClassNotFoundException e) { System.out.println("数据库驱动加载失败!!!"); } catch (SQLException e) { System.out.println("数据库异常,请稍候再试!!!"); e.printStackTrace(); } finally { if(rs != null) { try { rs.close(); } catch (SQLException e) { } } if(stat != null) { try { stat.close(); } catch (SQLException e) { } } if(conn != null) { try { conn.close(); } catch (SQLException e) { } } }
-
java.sql.Statement接口与java.sql.PreparedStatement接口的关系与区别?
- 关系:PreparedStatement是Statement的子接口。
- 区别:
- 安全性:
- Statement无法防止SQL注入,安全性低。
- PreparedStaterment可以防止SQL注入,安全性高。
- 效率:当需要批量执行同一条SQL语句时。
- Statement每次执行语句时,都需要先编译语句,再执行语句,效率低。
- PreparedStatement只在第一次执行语句时编译语句,再执行。从第二次执行开始,不再编译语句,而直接执行,效率高。
- 安全性:
添加数据
/**
* 向USER_MESSAGE表中添加新的用户信息
*
* @param userName 用户名
* @param userPassword 用户密码
* @param userSalary 用户工资
* @param userBirthday 出生日期
* @return 添加成功返回大于0的整数,否则返回0
*/
public int save(String userName, String userPassword, Double userSalary, Date userBirthday) {
Connection conn = null;
PreparedStatement ps = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true",
"root", "123456");
String sql = "insert into user_message(user_name,user_password,user_salary,user_birthday) values(?,?,?,?)";
// 关闭数据库自动提交功能,只有insert/delete/update语句需要,select语句不需要
conn.setAutoCommit(false);
// 创建准备语句对象,并设置准备语句对象将要执行的insert语句
ps = conn.prepareStatement(sql);
// 替换准备语句对象中的问号
ps.setString(1, userName);
ps.setString(2, userPassword);
ps.setDouble(3, userSalary);
// 将java.util.Date转换为java.sql.Date
ps.setDate(4, new java.sql.Date(userBirthday.getTime()));
// 使用准备语句对象执行insert语句,并获得insert语句执行后影响表中数据的行数
int rows = ps.executeUpdate();
if (rows > 0) {
// 添加成功,提交事务
conn.commit();
return rows;
}
// 添加失败,回退事务
conn.rollback();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
return 0;
}
修改数据
/**
* 修改USER_MESSAGE表中指定用户的USER_PASSWORD
*
* @param userId 用户编号
* @param userPassword 新密码
* @return 修改成功返回大于0的整数,否则返回0
*/
public int updateUserPasswordByUserId(Integer userId, String userPassword) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 创建连接对象,连接数据库
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true","root","123456");
// 创建UPDATE语句
String sql = "update user_message set user_password=? where user_id=?";
// 关闭数据库自动提交的功能
conn.setAutoCommit(false);
// 创建准备语句对象,并设置准备语句对象将要执行的UPDATE语句
ps = conn.prepareStatement(sql);
// 替换准备语句对象中的问号
ps.setString(1, userPassword);
ps.setInt(2, userId);
// 使用准备语句对象执行UPDATE语句,并获得UPDATE语句执行后影响表中数据的行数
int rows = ps.executeUpdate();
// 如果修改成功,提交事务,返回UPDATE影响数据的行数
if(rows > 0) {
conn.commit();
return rows;
}
// 如果修改失败,回退事务
conn.rollback();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭与数据库相关的对象
if(ps != null) {
try {
ps.close();
} catch (SQLException e) {
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
return 0;
}
封装查询结果
-
创建实体类:实体类的对象可以封装表中的一行数据。
package com.test.po; import java.util.Date; /** * 实体类:当前类的“一个”对象可以封装USER_MESSAGE表中的“一行”用户信息 * * @author M S I * */ public class UserMessage { private Integer userId; private String userName; private String userPassword; private Double userSalary; private Date userBirthday; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPassword() { return userPassword; } public void setUserPassword(String userPassword) { this.userPassword = userPassword; } public Double getUserSalary() { return userSalary; } public void setUserSalary(Double userSalary) { this.userSalary = userSalary; } public Date getUserBirthday() { return userBirthday; } public void setUserBirthday(Date userBirthday) { this.userBirthday = userBirthday; } @Override public String toString() { return "UserMessage [userId=" + userId + ", userName=" + userName + ", userPassword=" + userPassword + ", userSalary=" + userSalary + ", userBirthday=" + userBirthday + "]"; } }
-
封装查询的结果
package com.test.dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.test.po.UserMessage; /** * 实现对USER_MESSAGE表进行操作的方法 * * @author M S I * */ public class UserMessageDao { /** * 查询USER_MESSAGE表中所有的用户信息 * * @return 查询成功返回java.util.List类型的实例,否则返回null */ public List<UserMessage> getAll() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true", "root", "123456"); String sql = "select user_id,user_name,user_password,user_salary,user_birthday from user_message"; ps = conn.prepareStatement(sql); rs = ps.executeQuery(); // 在关闭结果集之前将结果集中的数据备份到List集合中 // 1.创建List集合,用于保存结果集中所有的数据 List<UserMessage> list = new ArrayList<>(); // 2.声明实体类的变量,用于保存结果集中的一行数据 UserMessage user = null; // 3.使用循环遍历结果集,将结果集中数据封装到List集合中 while(rs.next()) { // 4.创建实体类的对象,可以保存结果集中的一行数据 user = new UserMessage(); // 5.将结果集当前行指定列的数据,添加到实体类对象对应的属性中 user.setUserId(rs.getInt("user_id")); user.setUserName(rs.getString("user_name")); user.setUserPassword(rs.getString("user_password")); user.setUserSalary(rs.getDouble("user_salary")); user.setUserBirthday(rs.getDate("user_birthday")); // 6.将实体类的对象添加到List集合中 list.add(user); } // 7.循环结束后,返回List集合 return list; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(rs != null) { try { rs.close(); } catch (SQLException e) { } } if(ps != null) { try { ps.close(); } catch (SQLException e) { } } if(conn != null) { try { conn.close(); } catch (SQLException e) { } } } return null; } }
获得自增长主键
@Override
public int saveBusiness(String businessName) {
try {
// 获得数据库连接对象
conn = DbUtil.getConnection();
// 创建INSERT语句
String sql = "insert into business(businessName,password) values(?,'123')";
// 创建准备语句对象,并设置准备语句对象将要执行的INSERT语句,同时设置准备语句对象可以获得自增长主键的值
ps = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
// 替换准备语句对象中的问号
ps.setString(1, businessName);
// 使用准备语句对象执行INSERT语句,并获得INSERT语句执行后向表中添加数据的行数
int rows = ps.executeUpdate();
// 如果添加成功,提交事务
if (rows > 0) {
conn.commit();
// 并通过准备语句对象获得自增长的主键,将主键存入结果集中(一行一列)
rs = ps.getGeneratedKeys();
// 从结果集中获得主键,并返回
if (rs.next()) {
return rs.getInt(1);
}
}
// 如果添加失败,回退事务
conn.rollback();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭与数据库相关的对象
try {
DbUtil.close(rs, ps, conn);
} catch (SQLException e) {
}
}
return 0;
}
动态拼接SQL语句
@Override
public List<Business> listBusiness(String businessName, String businessAddress) {
try {
// 获得数据库连接对象
conn = DbUtil.getConnection();
// 创建基本的SELECT语句
StringBuilder sql = new StringBuilder(
"select businessId,password,businessName,businessAddress,businessExplain,starPrice,deliveryPrice "
+ " from business where 1=1 ");
// 根据用户输入的查询条件,拼接SELECT语句
int num = 0;
if (businessName != null && !businessName.trim().equals("")) {
sql.append("and businessName like ? ");
num = num + 1;
}
if (businessAddress != null && !businessAddress.trim().equals("")) {
sql.append("and businessAddress like ?");
num = num + 2;
}
// 创建准备语句对象,并设置准备语句对象将要执行的SELECT语句
ps = conn.prepareStatement(sql.toString());
// 根据用户输入的查询条件替换准备语句对象中的问号
if (num == 1) {
ps.setString(1, "%" + businessName + "%");
} else if (num == 2) {
ps.setString(1, "%" + businessAddress + "%");
} else if (num == 3) {
ps.setString(1, "%" + businessName + "%");
ps.setString(2, "%" + businessAddress + "%");
}
// 使用准备语句对象执行SELECT语句,并将查询的结果存入到结果集中
rs = ps.executeQuery();
// 在关闭结果集之前,将结果集中的数据备份到List集合中
// 创建List集合,用于保存结果集中的多行数据
List<Business> list = new ArrayList<>();
// 声明领域对象变量,用于保存结果集中的一行数据
Business business = null;
// 使用循环遍历结果集,将结果集的数据封装到List集合中
while(rs.next()) {
// 创建领域对象,可以保存结果集中的一行数据
business = new Business();
// 获得结果集当前行指定列的数据,并将数据存入领域对象对应的属性中
business.setBusinessId(rs.getInt("businessId"));
business.setBusinessAddress(rs.getString("businessAddress"));
business.setBusinessExplain(rs.getString("businessExplain"));
business.setBusinessName(rs.getString("businessName"));
business.setDeliveryPrice(rs.getDouble("deliveryPrice"));
business.setPassword(rs.getString("password"));
business.setStarPrice(rs.getDouble("starPrice"));
// 将封装数据后的领域对象添加到List中
list.add(business);
}
// 循环结束后返回List集合
return list;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭与数据库相关的对象
try {
DbUtil.close(rs, ps, conn);
} catch (SQLException e) {
}
}
return null;
}
HTML
-
HTML(超文本标记语言)
-
HTML文件扩展名:.html/.htm
-
HTML文件的基本结构
<html> <head> <!-- 通常用于放置页面的配置,引入的文件,大部分内容为用户不可见的元素 --> </head> <body> <!-- 通常用于存放用户可见的元素 --> </body> </html>
-
HTML标签:
- <标签>....</标签>
- <标签/>
-
HTML标签不区分大小写,建议小写。
-
HTML中常用的标签或属性:
- <meta charset='字符集'>:设置当前页面的字符集。
- <title>:设置页面的标题。
- <link href='文件名路径' rel='文件类型'/>:将指定类型的文件导入到当前页面中。
- bgcolor属性:设置元素的背景颜色。
- background属性:设置元素的背景图片。背景图片会覆盖背景颜色。
- <br>:换行。
- <h1>-<h6>:标题,默认为左对齐。
- align属性:设置水平对齐方式。left/center/reight
- <p>:段落,段落不能嵌套段落。
- :空格
- <strong>:粗体
- <em>:斜体
- <a href='url'>文本</a>:超链接
- title属性:当鼠标悬停在元素上时,显示的提示文本。
- <img src="图片路径">:将指定的图片加载到页面中。
- width属性:宽度。
- height属性:高度。
- border属性:设置元素的边框,默认为0.
- <ol>:有序列表
- <ul>:无序列表
- <li>:列表项
- <table>:表格
- <thead>:用于存放表格中的第一行,列标题。
- <tbody>:用于存放表格中的数据。
- <tr>:表格中的行。
- <th>:列标题,默认为居中对齐,默认为粗体。
- <td>:表格中的数据,默认为左对齐。
- valign属性:设置垂直对齐方式。
- colspan属性:跨列。
- 块级元素:独占一行。可以设置宽度与高度。可以包含其它的块级元素与行级元素。
- 行级元素(行内元素,内联元素):不独占一行,从左到右依次排列,当页面宽度不足时自动换行。不能设置宽度与高度,不能包含其它的块级与行级元素。
- 块级行内元素(块级内联元素):不独占一行,但可以设置宽度与高度。
- hidden属性:HTML5新出现,隐藏元素。
-
表单与表单中的控件
-
<form>:不可见,可以收集用户输入的数据。
-
action属性:设置表单收集数据后,提交给资源的名称。
-
method属性:设置表单提交数据的方式。只有get/post,默认为get。
-
get模式与post模式的区别?
- get模式:get模式提交的数据在浏览器地址栏中可以看到,get模式不能提交大数据。
- post模式:post模式提交的数据在浏览器地址栏中看不到,post模式可以提交大数据。
-
<input>:根据type属性的值,呈现出不同的控件。
-
name属性:设置控件的名字,默认情况下如果控件没有设置name属性,表单收集数据时会忽略这些控件中的数据。
-
value属性:通常情况下用于设置控件的默认值。
-
placeholder属性:用于设置控件默认显示的提示信息。HTML5中出现。
-
autofocus属性:控件自动获得焦点。HTML5中出现。
-
maxlength属性:设置控件最多输入的字符数。
-
size属性:设置控件的宽度。
-
readonly属性:设置控件为只读的状态。
-
disabled属性:设置控件为不可用的状态,控件呈现灰色。
-
required属性:表单提交时,验证数据是否为空。如果数据为空,则阻止表单提交。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <form action="http://www.baidu.com" method="get"> <!-- 隐藏表单域 --> <input type="hidden" name="userId" value="100"/> <table> <tr> <td>用户名:</td> <td> <!-- 单行文本框 --> <input type="text" name="userName" autofocus="autofocus"/> </td> </tr> <tr> <td>用户密码:</td> <td> <!-- 密码框 --> <input type="password" name="userPassword1" maxlength="20"/> </td> </tr> <tr> <td>确认密码:</td> <td> <input type="password" name="userPassword2" maxlength="20"/> </td> </tr> <tr> <td>用户性别:</td> <td> <!-- 单选按钮,name属性一致的为一组单选按钮,同组的单选按钮互斥的 --> <input type="radio" name="userSex" value="0" checked="checked"/>男 <input type="radio" name="userSex" value="1"/>女 </td> </tr> <tr> <td>城市:</td> <td> <!-- 复选按钮,name属性一致的为一组复选按钮 --> <input type="checkbox" name="userCity" value="1"/>北京 <input type="checkbox" name="userCity" value="2"/>上海 <input type="checkbox" name="userCity" value="3" checked="checked"/>大连 </td> </tr> <tr> <td>用户学历:</td> <td> <!-- 下拉列表/列表框:默认为下拉列表控件。添加了size属性时,控件会变为列表控件。 --> <select name="userDegree"> <option value="1">小学</option> <option value="2">中学</option> <option value="3" selected="selected">大学</option> </select> </td> </tr> <tr> <td>上传文件:</td> <td> <!-- 上传文件控件 --> <input type="file"/> </td> </tr> <tr> <td>教育经历:</td> <td> <textarea rows="10" cols="20" placeholder="可以省略……" name="userEdu">abc</textarea> </td> </tr> <tr> <td colspan="2"> <!-- 点击提交按钮时,按钮所在的表单会收集用户在控件中输入的数据,并将数据提交到action属性指定的资源 --> <button type="submit">提交按钮</button> <!-- 将所有表单中控件的值还原为默认值 --> <button type="reset">重置按钮</button> <!-- 通常与JS代码配合使用 --> <button type="button">普通按钮</button> </td> </tr> </table> </form> </body> </html>
-
HTML5中新出现的控件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <form action="html1.html" method="post"> <table> <tr> <td>非空验证:</td> <td> <input type="text" name="notNull" required="required"/> </td> </tr> <tr> <td>输入数字:</td> <td> <input type="number" min="1" max="100" step="10" value="1" required="required" /> </td> </tr> <tr> <td>输入邮箱:</td> <td> <input type="email" required="required"/> </td> </tr> <tr> <td>输入日期:</td> <td> <input type="date" required="required"/> </td> </tr> <tr> <td>输入时间:</td> <td> <input type="time" required="required"/> </td> </tr> <tr> <td>输入日期时间:</td> <td> <input type="datetime-local" required="required"/> </td> </tr> <tr> <td>输入周:</td> <td> <input type="week" required="required"/> </td> </tr> <tr> <td>查询条件:</td> <td> <input type="search" /> </td> </tr> <tr> <td>DataList:</td> <td> <!-- 当下拉列表中数据多时,建议使用 --> <!-- list属性设置DataList控件的id属性的值 --> <input type="text" list="myDataList"/> <!-- id属性在页面中是唯一的 --> <datalist id="myDataList"> <option>AAA</option> <option>AAB</option> <option>AAC</option> <option>BAA</option> <option>BAB</option> <option>BAC</option> <option>CAA</option> <option>CAB</option> <option>CAC</option> <option>DAA</option> </datalist> </td> </tr> <tr> <td colspan="2"> <button type="submit">提交</button> </td> </tr> </table> </form> </body> </html>
-
CSS
- CSS 指层叠样式表 (Cascading Style Sheets)
CSS的三种使用方式
-
行内样式(内联样式):在标签中使用style属性设置当前标签的样式。此方式优先级最高。
-
格式:<标签 style="属性=值;属性=值;……">
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p style="color: red;"> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p style="color: red;"> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p style="color: red;"> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p style="color: red;"> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p style="color: red;"> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> </body> </html>
-
-
内部样式:在HTML页面中使用style标签设置页面中指定元素的样式。
-
格式:
元素名{
属性:值;
属性:值;
……
}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> /* CSS中的注释 */ p{ color:#0000AA; font-size: 25px; } </style> </head> <body> <p> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> <p style="color: #F00;"> 这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落,这是一个段落。 </p> </body> </html>
-
-
外部样式:使用link标签导入外部的CSS文件。
CSS常用的选择器
-
元素选择器(HTML选择器、标签选择器):设置指定元素(标签)的样式。
<style> input{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } </style>
-
属性选择器:设置当前页面中指定属性元素的样式。
- 格式:元素[属性=‘值’]
- *:表示模糊查询。
- ^:表示以指定的值开头。
- $:表示以指定的值结尾。
<style> input[type$='xt']{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } </style>
-
ID选择器:使用#表示ID选择器。设置指定ID元素的样式。
-
在HTML页面中id属性的值是唯一的。
-
ID选择器的效率最高的。
<style> #t1{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } #t2{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } #t3{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } </style>
-
-
群组选择器:同时设置多个元素的样式。
-
语法:元素1,元素2,……
<style> #t1,#t2,#t3{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } </style>
-
-
类选择器(Class选择器):元素中class的值可以重复的,并且class属性中可以同时出现多个值,值之间使用空格分隔。使用“.”表示类选择器。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .t{ border-top: none; border-right: none; border-left: none; border-bottom-color: black; } .t1{ color: red; } </style> </head> <body> 面向对象的特征:<input class="t" type="text"/>,<input class="t" type="text"/>,<input class="t t1" type="text"/>。 <br> <input type="button" value="交卷"> </body> </html>
-
后代选择器:设置元素中的另一个元素的样式。
-
语法:元素 元素
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div a{ text-decoration: none; } </style> </head> <body> <div> <ul> <li><a href="#">国内</a></li> <li><a href="#">国际</a></li> <li><a href="#">军事</a></li> <li><a href="#">体育</a></li> </ul> </div> <a href="">游戏</a> </body> </html>
-
-
子选择器:设置元素中指定第一级子元素的样式。
-
语法:元素 > 子元素
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div > a{ color: red; text-decoration: none; } </style> </head> <body> <div> <a href="">新闻</a> <ul> <li><a href="#">国内</a></li> <li><a href="#">国际</a></li> <li><a href="#">军事</a></li> <li><a href="#">体育</a></li> </ul> <a href="">游戏</a> </div> </body> </html>
-
CSS常用样式
背景样式
-
body{ /* 背景颜色 */ background-color: bisque; /* 背景图片 */ background-image: url('images/2.png'); /* 背景图片重复方式 */ background-repeat: no-repeat; /* 背景出现的位置 */ background-position:center; }
文本样式
-
div { width: 600px; height: 600px; background-color: aliceblue; background-image: url('./images/qq.ico'); background-repeat: no-repeat; background-position: center; /* 设置水平对齐方式 */ text-align: center; } div a { /* 设置超链接没有下划线 */ text-decoration: none; /* 设置垂直对齐方式 */ vertical-align: -30px; } div p { /* 为文本添加删除线 */ text-decoration: line-through; } div li { /* 设置行高 */ line-height: 50px; } p{ /* 首行缩进 */ text-indent: 25px; }
字体样式
<style>
p{
/* 设置字体 */
font-family: '华文彩云1','楷体','宋体';
/* 字体风格 */
font-style: italic;
/* 字体粗细 */
font-weight: bolder;
/* 字体大小 */
font-size: small;
}
</style>
尺寸样式
-
只有块级元素才可以设置宽度与高度。
<style> html,body{ height: 100%; } table{ width: 50%; height: 30%; } a{ /* 因为超链接是行级元素(内联元素),所以不能设置宽度与高度 */ width:500px; height: 500px; } </style>
边框样式
-
table{ width: 50%; height: 30%; /* 边框宽度 */ /* border-width: 10px; */ /* 边框风格 */ /* border-style: solid; */ /* 边框颜色 */ /* border-color: blue; */ /* 设置边框 */ border: #000000 solid 2px; }
伪类样式
-
元素名:样式
tr:nth-child(odd){ /* 设置奇数行背景颜色 */ background-color: bisque; } tr:nth-child(even){ /* 设置偶数行背景颜色 */ background-color: azure; } tr:hover{ /* 设置当鼠标经过元素时 */ background-color: aquamarine; }
鼠标样式
-
cursor:值。
table{ width: 50%; height: 30%; /* 设置边框 */ border: #000000 solid 2px; /* 设置鼠标样式 */ cursor: pointer; }
列表样式
-
<style> ul{ /* 取消列表默认的样式 */ list-style: none; } </style>
透明度样式
-
p{ background-color: red; /* 设置透明度:可以使用百分比,也可以使用0-1之间的值 */ opacity: 0.7; }
圆角样式
-
div{ width: 600px; height: 600px; background-color: #5b5bc8; /* 圆角样式 */ border-radius: 100px; }
盒子模型
外边框(margin)
-
设置元素与其它元素之间的距离。
div{ width: 300px; height: 200px; background-color: red; border-width: 5px; border-style: solid; /* 4个值:根据顺时针设置外边框的大小 */ /* 3个值:上,左右,下外边框的大小 */ /* 2个值:上下,左右外边框的大小 */ /* 1个值:设置所有外边框的大小 */ /* margin: 10px; */ /* 设置居中 */ margin: 0 auto; }
内边框(padding)
-
padding的用法与margin是一致的。
-
用于设置内容与边框之间的距离。
<style> div{ width: 300px; height: 200px; background-color: red; border-width: 5px; border-style: solid; /* 4个值:根据顺时针设置外边框的大小 */ /* 3个值:上,左右,下外边框的大小 */ /* 2个值:上下,左右外边框的大小 */ /* 1个值:设置所有外边框的大小 */ /* margin: 10px; */ /* 设置居中 */ margin: 0 auto; padding-top: 10px; padding-left: 50px; } </style>
-
盒子模型中元素尺寸的大小:内容 + 内边距 + 边框
-
盒子模型中元素占用空间:外边框 + 元素尺寸
元素默认的样式与CSS重置
-
/************************ css 重置 ************************/ html,body,div,span,h1,h2,h3,h4,h5,h6,ul,li,p{ margin: 0; padding: 0; } html,body{ width: 100%; font-family: Helvetica Neue,Helvetica,Arial,Microsoft Yahei,Hiragino Sans GB,Heiti SC,WenQuanYi Micro Hei,sans-serif; } ul{ list-style: none; } a{ text-decoration: none; }
显示与隐藏
-
display样式
-
<style> div{ border: 1px #000 solid; width: 100px; height: 100px; /* 将元素转换为行级元素 */ display: inline; } span{ /* 将元素转换为块级元素 */ display: block; } .testSpan{ /* 隐藏元素并回收占用空间 */ display: none; } </style>
-
overflow样式:当块级元素中的内容超过指定的宽度或高度时,如何处理溢出的内容。
<style> div{ width: 200px; height: 100px; border: 1px #000 solid; /* 默认值,不处理超出的内容 */ /* overflow: visible; */ /* 超出的内容隐藏 */ /* overflow: hidden; */ /* 超出的内容不可见,但会添加滚动条 */ overflow: auto; } </style>
新盒子模型
-
从CSS3开始出现了新盒子模型。新盒子模型以边框作为元素的大小,此时再设置内边框时,会向内扩展而不会影响元素的大小。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 200px; height: 100px; border: 1px #000 solid; padding: 20px; /* 设置使用新盒子模型 */ box-sizing: border-box; } </style> </head> <body> <div></div> </body> </html>
元素定位
- 使用position样式设置元素的位置。
静态定位
- position:static
- 静态定位为默认的定位方式,也称为文档流定位。
- 以页面左上角为基准,元素在页面中以从上到下,从左到右的方式进行排列。块级元素换行,行级元素不换行。
相对定位
-
position:rebative
-
不会脱离文档流,以自身在文档流中的位置为基准。
-
不回收元素占用的空间。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 200px; height: 100px; border: 1px #000 solid; padding: 20px; /* 设置使用新盒子模型 */ box-sizing: border-box; /* 相对定位 */ position: relative; left: 50px; top: 50px; } a{ display: block; text-decoration: none; color: #333; position: relative; } a:hover{ color: #999; left: 1px; top: 1px; } </style> </head> <body> <p>这是一个段落</p> <p>这是一个段落</p> <div></div> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <hr> <a href="">测试超链接</a> <a href="">测试超链接</a> <a href="">测试超链接</a> <a href="">测试超链接</a> <a href="">测试超链接</a> </body> </html>
绝对定位
-
position:absolute
-
脱离文档流,不受其它元素的影响。
-
定位后之前占用的空间会被回收。
-
如果父元素不是rebative或absolute时,以body作为基准。
-
如果父元素是rebative或absolute时时,以父元素为基准。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .d1{ /* 当父元素不是relative或absolute时,以body作为基准 */ width: 600px; height: 600px; background-color: chocolate; position: relative; } .d2{ width: 100px; height: 100px; background-color: red; position: absolute; left: 0px; top: 0px; } </style> </head> <body> <p>这是一个段落</p> <p>这是一个段落</p> <div class="d1"> <div class="d2"></div> </div> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> </body> </html>
固定定位
-
position:fixed
-
以浏览器窗口作为基准。
-
脱离文档流,不受其它元素的影响。
<head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 100%; height: 80px; position: fixed; left: 0px; top: 0px; background-color: black; opacity: 0.5; } </style> </head> <body> <div></div> <p>这是一个段落</p> <p>这是一个段落</p> <!-- 省略N个段落--> </body> </html>
使用定位进行布局的示例
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link href="./css/reset.css" rel="stylesheet"/> <style> .header{ width: 100%; height: 80px; background-color: red; } .main{ width: 100%; min-height: 300px; background-color: green; } .footer{ width: 100%; height: 50px; background-color: blue; } </style> </head> <body> <div class="header"></div> <div class="main"> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> <p>这是一个段落</p> </div> <div class="footer"></div> </body> </html>
z-index样式
-
当元素的定位方式为绝对定位或固定定位时,这些元素都会脱离文档流。如果有多个元素都是此种定位方式,可能会出现相互覆盖的效果。可以使用z-index样式设置元素的等级,等级高的元素会覆盖等级低的元素。
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .one{ width: 200px; height: 200px; background-color: red; position: absolute; left: 50px; top: 50px; z-index: 2; } .two{ width: 200px; height: 200px; background-color: blue; position: absolute; left: 100px; top: 100px; z-index: 1; } </style> </head> <body> <div class="one"></div> <div class="two"></div> </body> </html>
弹性布局
- display设置为flex,元素变为弹性布局。
- 当元素变为弹性布局后,元素中的子元素会根据弹性布局的规则自动进行排序,块级与行级的特性将失效。
弹性布局的主轴与侧轴
-
主轴:水平方向的轴。
-
侧轴:垂直方向的轴。
-
默认情况下,子元素根据主轴方向进行排列。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ /* 设置为弹性布局 */ display: flex; } .item{ width: 100px; height: 100px; box-sizing: border-box; background-color: orange; border: solid 1px black; } </style> </head> <body> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> </body> </html>
flex-direction样式
-
可以通过flex-direction样式修改弹性布局中子元素排列的方向。
-
row:水平方向排列,默认。
-
column:垂直方向排列。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ /* 设置为弹性布局 */ display: flex; flex-direction: column; } .item{ width: 100px; height: 100px; box-sizing: border-box; background-color: orange; border: solid 1px black; } </style> </head> <body> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> </body> </html>
flex-wrap样式
-
默认情况下,弹性布局中的子元素不会自动换行。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ /* 设置为弹性布局 */ display: flex; /* 设置父元素宽度不足时,子元素自动换行 */ flex-wrap: wrap; } .item{ width: 100px; height: 100px; box-sizing: border-box; background-color: orange; border: solid 1px black; } </style> </head> <body> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> </body> </html>
justify-content样式
-
设置弹性布局中主轴方向对齐方式。
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ /* 设置为弹性布局 */ display: flex; /* 默认值,左对象 */ /* justify-content: flex-start; */ /* 右对齐 */ /* justify-content: flex-end; */ /* 居中对齐 */ /* justify-content: center; */ /* 两端对齐,最左与右的元素在父容器的边缘,其它子元素平均分布 */ /* justify-content: space-between; */ /* 平均分布,所以子元素两端的距离相等 */ justify-content: space-around; } .item{ width: 100px; height: 100px; box-sizing: border-box; background-color: orange; border: solid 1px black; } </style> </head> <body> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> </body> </html>
align-items样式
-
设置弹性布局中侧轴方向对齐的方式(单行)。
body{ /* 设置为弹性布局 */ display: flex; /* 设置垂直对齐方式 */ /* flex-start: 上对齐 center:居中对齐 flex-end:下对齐 */ align-items:center; flex-wrap: wrap; }
align-content样式
- 设置弹性布局中侧轴方向对齐的方式(多行)。
flex样式
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ /* 设置为弹性布局 */ display: flex; } .item{ width: 100px; height: 100px; box-sizing: border-box; background-color: orange; border: solid 1px black; } </style> </head> <body> <!-- 将父元素分为3份,每个子元素各占1份 --> <div class="item" style="flex:1;">1</div> <div class="item" style="flex:1;">2</div> <div class="item" style="flex:1;">3</div> </body> </html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body{ /* 设置为弹性布局 */ display: flex; } .item{ width: 100px; height: 100px; box-sizing: border-box; background-color: orange; border: solid 1px black; } </style> </head> <body> <!-- 将父元素分为6份,每个子元素各占N份 --> <div class="item" style="flex:1;">1</div> <div class="item" style="flex:2;">2</div> <div class="item" style="flex:3;">3</div> </body> </html>
经典1-3-1布局 (HTML)
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 总容器 --> <div class="container"> <!-- 头部 --> <header></header> <!-- 导航 --> <nav></nav> <!-- 主体 --> <div class="main"> <!-- 左侧边框 --> <aside></aside> <!-- 内容 --> <section></section> <!-- 右侧边框 --> <article></article> </div> <!-- 页脚 --> <footer></footer> </div> </body> </html>
经典1-3-1布局 (CSS)
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> header,nav,aside,section,article,footer{ background-color: #666; } /* 总容器,设置宽度但不设置高度 */ .container{ width: 1200px; margin: 0 auto; } /* 设置头部 */ .container header{ width: 100%; height: 60px; margin-bottom: 10px; } /* 设置导航 */ .container nav{ width: 100%; height: 60px; margin-bottom: 10px; } /* 设置主体样式 */ .container .main{ width: 100%; margin-bottom: 10px; display: flex; } .container .main aside,.container .main article { flex: 0 0 200px; } .container .main section{ flex: 1; margin: 0 10px; } /* 设置页脚 */ .container footer{ width: 100%; height: 60px; margin-bottom: 10px; } </style> </head> <body> <!-- 总容器 --> <div class="container"> <!-- 头部 --> <header></header> <!-- 导航 --> <nav></nav> <!-- 主体 --> <div class="main"> <!-- 左侧边框 --> <aside> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> </aside> <!-- 内容 --> <section> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> <p>BBBBBBBBBBBBBBBBBBB</p> </section> <!-- 右侧边框 --> <article> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> <p>AAAAA AAAA AAAA AAA AAA</p> </article> </div> <!-- 页脚 --> <footer></footer> </div> </body> </html>
自适应高度的后台管理布局(HTML)
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 总容器 --> <div class="container"> <!-- 头部 --> <header></header> <!-- 中部 --> <div class="main"> <!-- 左侧侧边框 --> <aside></aside> <!-- 主体 --> <section></section> </div> <!-- 底部 --> <footer></footer> </div> </body> </html>
自适应高度的后台管理布局(CSS)
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> html,body, .container{ width: 100%; height: 100%; margin: 0px; padding: 0px; } /* 将总容器设置为弹性布局,将主轴设置为垂直方向 */ .container{ display: flex; flex-direction: column; } /* 设置头部 */ .container header{ flex: 0 0 60px; background-color: #B3C0DB; } /* 设置中部 */ .container .main{ flex: 1; display: flex; } /* 设置中部侧边框 */ .container .main aside{ flex: 0 0 200px; background-color: #D3DCE6; } /* 设置中部主体内容 */ .container .main section{ flex: 1; background-color: #E9EFF3; } /* 设置底部 */ .container footer{ flex: 0 0 60px; background-color: #B3C0DB; } </style> </head> <body> <!-- 总容器 --> <div class="container"> <!-- 头部 --> <header></header> <!-- 中部 --> <div class="main"> <!-- 左侧侧边框 --> <aside></aside> <!-- 主体 --> <section></section> </div> <!-- 底部 --> <footer></footer> </div> </body> </html>
JavaScript
- JS是基于对象的语言。
- JS可以使用对象,可以使用现有的对象。
- JS在浏览器中解释运行。
引用JS的两种方式
-
方式一:在HTML页面中使用script标签,在HTML页面中插入一段JS代码。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script> document.write('<div style="color:red">这是一段测试的文本</div>'); </script> </head> <body> </body> </html>
-
方法二:使用script标签导入外部的.js文件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="./js/common.js"></script> </head> <body> </body> </html>
JS中的数据类型
- undefined:未定义类型。当声明变量但没有赋值时,返回此值。
- boolean:只有true/false。
- number:数字类型。
- string:字符串类型,值必须放在一对引号中。
- object:对象类型。null,数组,Date()
- function:函数类型。
- 前4种类型也称为JS中的原始数据类型。
NaN与Infinity
-
NaN:表示非数值。
-
NaN是number类型的值。
console.log(typeof parseInt('123')); console.log(parseInt('abc')); // 判断是否为非数字的数据 console.log(isNaN(parseInt('abc')));
-
Infinity:表示除数为0,也是number类型的。
运算符
算术运算符:+,-,*,/,%,++,--
-
console.log(5 / 2); // 结果为2.5
比较运算符:<,<=,>,>=,== ,!= ,=,!
-
// 判断数据的内容是否相等 console.log(1 == '1'); // 判断数据与类型是否相等 console.log(1 === '1');
逻辑运算符:&& ,|| ,!
赋值运算符:=,+=,-=,*=,/=,%=
类型转换
-
parseInt():转换为整数
-
parseFloat():转换为浮点数
console.log(parseInt('100.25')); console.log(parseFloat('100.25')); console.log(1 + '2'); // 结果为12 console.log(1 + parseInt('2'));
变量与常量
-
使用var关键字声明变量。
-
JavaScript是弱类型的语言。
-
新声明变量关键字:let
-
一个变量可以接收不同类型的数据。
let num; console.log(num); num = 100; console.log(num); console.log(typeof num); num = 'abc'; console.log(num); console.log(typeof num); num = new Date(); console.log(num); console.log(typeof num); num = false; console.log(num); console.log(typeof num);
-
声明常量:const关键字。
const num1 = 100; console.log(num1); num1 = 200; // 不能重新为常量赋值 console.log(num1);
函数
-
创建函数有两种方式。
-
方式一:
function 函数名([参数列表]){
函数体;
}
- 在函数声明时,不需要设置函数返回数据的类型。
- 函数中如果出现return语句,则函数会返回数据。反之函数不能返回数据。
- 一个函数可以返回类型不同的数据。
-
方法二:
let 变量名 = function(){
函数体;
}
<script> function f1(){ console.log('调用了名为f1()的方法!!!'); } function f2(num){ console.log(num * 100); } function f3(num1,num2){ return num1 + num2; } function f4(num1,num2){ if(num1 < 100){ return num1 + num2; } } let f5 = function(){ console.log('调用了f5()的方法'); } f1(); f2('1000'); console.log(f3(100,25)); console.log(f4(1000,20)); f5(); console.log(typeof f5); </script>
JS的作用域
-
JS中只有函数作用域,没有块(if,for,while)作用域。
-
var声明的变量,在块的外面也可以直接使用。
var num1 = 100; if(num1 < 200){ // 在if的外面可以使用 var num2 = 200; } function f1(){ // 在函数的外面不能使用 var num3 = 300; } for(var i = 0 ; i < 10 ; i++){ // 变量i在循环的外面可以使用 console.log(i); } f1(); console.log(num1); console.log(num2); console.log(i); console.log(num3);
-
为了解决var声明变量没有块作用域的问题,所以建议声明变量时尽量使用let关键字。
-
使用let关键字声明的变量,有函数作用域,也有块作用域。
数组
-
// 声明没有长度的数组 let arr = new Array(); // 当数组长度不足时,数组会自动扩展长度 arr[0] = 100; arr[1] = 200; arr[2] = 300; console.log(arr.length); for(let i = 0 ; i < arr.length ; i++){ console.log(arr[i]); }
-
// 创建指定长度的数组 let arr = new Array(10); // 当数组长度不足时,数组会自动扩展长度 arr[0] = 100; arr[1] = 200; arr[2] = 300; arr[19] = 10000; console.log(arr.length); for(let i = 0 ; i < arr.length ; i++){ console.log(arr[i]); }
-
let arr = new Array(); // JS的数组中可以存放不同类型的数据 arr[0] = 100; arr[1] = 'abc'; arr[2] = true; arr[9] = new Date(); console.log(arr.length); for(let i = 0 ; i < arr.length ; i++){ console.log(arr[i]); }
-
let arr = new Array(10,20,30,'abc'); console.log(arr.length); for(let i = 0 ; i < arr.length ; i++){ console.log(arr[i]); }
-
let arr = [100,200,300,'abc','def']; console.log(arr.length); for(let i = 0 ; i < arr.length ; i++){ console.log(arr[i]); }
常用内置对象的API
数组
-
let array = []; for(let i = 0 ; i < 10 ; i++){ // 向数组的末尾追加数据 array.push(i); } console.log(array);
-
let array = []; for(let i = 0 ; i < 10 ; i++){ // 向数组的头部添加数据 array.unshift(i); } console.log(array); // 移除并返回数组中最后一个值 console.log(array.pop()); // 移除并返回数组中的第一个值 console.log(array.shift()); console.log(array);
-
let array = [45,78,12,36,57,8]; console.log(array); // 排序,根据字典顺序进行排序 array.sort(); console.log(array); // 自定义排序规则 let order = function(num1,num2){ return num1 - num2; } array.sort(order); console.log(array); // 自定义降序排序 array.sort(function(num1,num2){ return num2 - num1; }); console.log(array);
-
let array = [45,78,12,36,57,8]; // 倒置数组 array.reverse(); console.log(array); let array1 = [10,20,30,40]; let array2 = ['abc','def']; let array3 = [true,false]; // 连接数组 let array4 = array1.concat(array2,array3); console.log(array4) let array5 = ['2022','07','27']; // 根据指定的标记,将数组拼接成一个字体串,并返回。 console.log(array5.join('-')); let date = '2000-10-20'; // 切割字符串,并返回字符串数组 let array6 = date.split('-'); console.log(array6);
字符串
-
let str = 'abcdef1234567890abc一二三'; // 返回字符数 console.log(str.length); // 返回指定位置的字符 console.log(str.charAt(4)); // 查找字符串首次出现的位置,没找到返回-1 console.log(str.indexOf('c')); // 查找字符串最后出现的位置,没找到返回-1 console.log(str.lastIndexOf('c')); // 从下标为2的位置开始截取字符串,直到下标为6的位置之前,第二个参数可以省略 console.log(str.substring(2,6)); // 截取后字符串的内容不变 console.log(str); // 从指定的位置开始截取指定长度的字符串,第二个参数可以省略 console.log(str.substr(2,5)); // 大写 console.log(str.toUpperCase()); // 小写 console.log(str.toLowerCase());
日期
-
let date = new Date(); console.log(date); // 获得日 console.log(date.getDate()); // 返回0-11的月份 console.log(date.getMonth() + 1); // 返回4位的年 console.log(date.getFullYear()); // 返回从1970-1-1到创建Date对象之间的毫秒数 console.log(date.getTime()); // 获得星期,0-6 console.log(date.getDay()); console.log(date.getHours()); console.log(date.getMinutes()); console.log(date.getSeconds());
数学
-
// 向上取整 console.log(Math.ceil(12.1)); // 向下取整 console.log(Math.floor(12.9)); // 四舍五入,只能返回整数 console.log(Math.round(12.25)); // 返回大于等于0一定小于1的随机数 console.log(Math.random()); console.log(Math.PI);
BOM模型与DOM模型
- BOM:Browser Object Model,以浏览器中window对象作为根节点的模型。
- DOM:Document Object Model,以document作为根节点的模型。
- BOM包含了DOM。
BOM模型
window对象
-
// 弹出带一个确定按钮的对话框 alert('测试alert()方法!!!'); // 弹出带两个按钮的对话框,点击确定返回true,点击取消返回false。 confirm('确定要删除数据吗?'); // 弹出可以接收用户输入信息的对话框 let input = prompt(); console.log(input);
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button onclick="funOpen()">打开百度</button> <button onclick="funClose()">关闭百度</button> <script> let win = null; function funOpen(){ win = open('https://www.baidu.com'); } function funClose(){ if(win != null){ win.close(); } } </script> </body> </html>
-
// 定时器,只能调用一次 setTimeout(function(){ // 设置跳转的url window.location.href = "http://www.baidu.com"; },5000); // 另一种写法 let f1 = function(){ window.location.href = 'http://www.baidu.com'; } setTimeout(f1,1000);
-
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="./js/common.js"></script> </head> <body> <button onclick="stop()">停止</button> <script> // 定时器,可以多次调用 // setInterval(function(){ // console.log(formatTime(new Date())); // },1000); let f1 = function(){ console.log(formatTime(new Date)); } let timer = setInterval(f1,1000); function stop(){ if(timer != null){ // 关闭定时器 clearInterval(timer); } } </script> </body> </html>
history对象
-
back():后退,加载历史中上一个url。
-
forward():前进,加载历史中下一个url。
-
go():值为-1相当于back(),值为1相当于forward()。
<a href="javascript:history.go(-1);">后退</a> <a href="http://www.baidu.com">百度</a> <a href="javascript:history.go(1)">前进</a>
DOM模型
获得DOM对象的方法
-
getElementsByTagName("标签名"):根据标签的名字,获得页面中指定标签的元素,返回类型为数组类型。
-
getElementById("ID"):获得页面中指定ID的元素,因为页面中ID是唯一的,所以此方法返回一个数据。
-
getElementsByClassName("class"):获得页面中指定class属性的元素。因为页面中class属性的值可以重复,所以此方法返回类型为数组。
-
getElementsByName("name"):获得页面中指定name属性的元素。因为页面中元素name属性的值可以重复,所以此方法返回类型为数组。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 400px; height: 400px; border: solid 1px black; margin-bottom: 10px; } </style> </head> <body> <div></div> <button id="btn1">红色</button> <button class="btn2">绿色</button> <button name="btn3">蓝色</button> <script> // 根据标签的名字,获得页面中指定标签的元素,返回类型为数组类型 let divObj = document.getElementsByTagName("div")[0]; // 获得id属性为btn1的元素 let btn1 = document.getElementById("btn1"); // 设置红色按钮单击事件 btn1.onclick = function(){ divObj.style.backgroundColor = '#FF0000'; } // 获得class属性为btn2的元素 let btn2 = document.getElementsByClassName("btn2")[0]; btn2.onclick = function(){ divObj.style.backgroundColor = '#00FF00'; } // 获得name属性为btn3的元素 let btn3 = document.getElementsByName("btn3")[0]; btn3.onclick = function(){ divObj.style.backgroundColor = '#0000FF'; } </script> </body> </html>
-
querySelector("选择器"):获得页面中指定选择器的元素,此方法只能返回一个数据。
-
querySelectorAll("选择器"):获得页面中指定选择器的一组元素,返回类型为数组类型。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 400px; height: 400px; border: solid 1px black; margin-bottom: 10px; } </style> </head> <body> <div></div> <button id="btn1">红色</button> <button class="btn2">绿色</button> <button name="btn3">蓝色</button> <script> // 使用元素选择器,获得页面中唯一一个DIV let divObj = document.querySelector('div'); // 获得id属性为btn1的元素 let btn1 = document.querySelector("#btn1"); // 设置红色按钮单击事件 btn1.onclick = function(){ divObj.style.backgroundColor = '#FF0000'; } // 获得class属性为btn2的元素 let btn2 = document.querySelectorAll('.btn2')[0]; btn2.onclick = function(){ divObj.style.backgroundColor = '#00FF00'; } // 获得name属性为btn3的元素 let btn3 = document.querySelector('button[name="btn3"]'); btn3.onclick = function(){ divObj.style.backgroundColor = '#0000FF'; } </script> </body> </html>
操作元素属性
-
方法一:静态调用。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="text"/> <script> let txt = document.querySelector("input"); // 设置元素属性 txt.value = parseInt(Math.random() * 100); // 获得元素属性 console.log(txt.value); </script> </body> </html>
-
方法二:
- setAttribute('属性名','值'):设置元素属性的值。
- getAttribute('属性名'):获得元素属性的值。
- removeAtrribute('属性名'):移除元素中的属性。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="text" disabled/> <script> let txt = document.querySelector("input"); let attributeName = "value"; txt.setAttribute(attributeName,Math.random()); attributeName = "title"; txt.setAttribute(attributeName,"这是一个单行文本框"); console.log(txt.getAttribute('value')); txt.removeAttribute('disabled'); </script> </body> </html>
操作DOM对象
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p> 行:<input type="number" id="rows" min="1" max="9999"/> </p> <p> 列:<input type="number" id="cols" min="1" max="9999"/> </p> <p> <button id="btn1">画表格</button> <button id="btn2">重置</button> </p> <hr> <table border="1" hidden="hidden"></table> <script> // 获得画表格的按钮 let btn1 = document.getElementById("btn1"); // 设置画表格按钮的单击事件 btn1.onclick = function(){ // 获得用户输入的行与列的值 let rows = document.getElementById("rows").value; let cols = document.querySelector("#cols").value; // 获得页面中的table let table = document.querySelector("table"); // 在table中找到所有的tr对象 let trArray = table.getElementsByTagName("tr"); // 如果获得到了tr对象 if(trArray != null && trArray.length > 0){ // 在table中移除找到的tr for(let i = trArray.length - 1 ; i >= 0 ; i--){ // 移除DOM对象 table.removeChild(trArray[i]); } } // 根据用户输入的行与列在页面中画表格 // 行 for(let i = 1 ; i <= rows ; i++){ // 创建DOM对象 let tr = document.createElement('tr'); // 列 for(let j = 1 ; j <= cols ; j++){ let td = document.createElement('td'); td.innerHTML = " "; // 将创建td对象添加到tr中 tr.appendChild(td); } // 将创建tr对象添加到table中 table.appendChild(tr); } // 移除table中hidden属性 table.removeAttribute('hidden'); }; // 获得id属性为btn2的按钮 let btn2 = document.querySelector('#btn2'); // 设置btn2按钮的单击事件 btn2.onclick = function(){ document.getElementById("rows").value = ""; document.getElementById("cols").value = ""; // 向页面中table元素添加hidden属性 document.querySelector('table').setAttribute('hidden','hidden'); } </script> </body> </html>
事件处理
-
方法一
<a href="http://www.baidu.com" onclick="return f1()">跳转到百度</a> <script> function f1(){ alert("程序出错!!!"); return false; } </script>
-
方法二:HTML标签与JS代码完全分离。
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <a href="http://www.baidu.com" onclick="return f1()">跳转到百度</a> <button class="btn">确定</button> <script> // 方法一 function f1(){ alert("程序出错!!!"); return false; } // 方法二 let btn = document.querySelector('.btn'); btn.onclick = function(){ alert('点击了按钮'); } </script> </body> </html>
-
方法三
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <a href="http://www.baidu.com" onclick="return f1()">跳转到百度</a> <button class="btn">确定</button> <button class="btn1">按钮</button> <script> // 方法一 function f1(){ alert("程序出错!!!"); return false; } // 方法二 let btn = document.querySelector('.btn'); btn.onclick = function(){ alert('点击了按钮'); } // 方法三 let btn1 = document.querySelector('.btn1'); btn1.addEventListener('click',function(){ alert('又点击了按钮'); }); </script> </body> </html>
JS加载的时机
-
window.onload():文档就绪函数。当HTML文档所有的资源全部加载完毕之后,才开始调用。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> span[class$='Error'] { color: #FF0000; } </style> <script> window.onload = function () { let loginBtn = document.getElementById("loginBtn"); let error1 = document.querySelector('.userNameError'); let error2 = document.querySelector('.userPasswordError'); loginBtn.onclick = function () { error1.innerHTML = '*'; error2.innerHTML = '*'; let userName = document.querySelector('.userName'); if (userName.value === "") { //alert('用户名不能为空!!!'); error1.innerHTML = '用户名不能为空!!!'; // 使控件自动获得焦点 userName.focus(); return; } let userPassword = document.getElementsByClassName('userPassword')[0]; if (userPassword.value === '') { // alert('用户密码不能为空!!!'); error2.innerHTML = '用户密码不能为空!!!'; userPassword.focus(); return; } if (userPassword.value.length < 6 || userPassword.value.length > 20) { // alert('用户密码在6-20位之间!!!'); error2.innerHTML = '用户密码在6-20位之间!!!'; // 选中控件中的文本 userPassword.select(); return; } } } </script> </head> <body> <table> <tr> <td>用户姓名:</td> <td> <input type="text" class="userName" autofocus="autofocus" /> </td> <td> <span class="userNameError">*</span> </td> </tr> <tr> <td>用户密码:</td> <td> <input type="password" class="userPassword" /> </td> <td> <span class="userPasswordError">*</span> </td> </tr> <tr> <td colspan="2"> <button id="loginBtn">登录</button> <button id="resetBtn">重置</button> </td> </tr> </table> </body> </html>
事件对象-event
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> img{ width: 100px; height: 100px; position: absolute; cursor: none; } html,body{ cursor: none; } </style> </head> <body> <img src="./img/2.png"> <script> window.onload = function(){ // 获得图片 let img = document.getElementsByTagName('img')[0]; document.onmousemove = function(event){ img.style.left = event.pageX + 'px'; img.style.top = event.pageY + 'px'; } } </script> </body> </html>
事件的冒泡与事件的捕获
-
事件冒泡:事件从子元素传递到父元素的过程,称为事件冒泡。
-
事件捕获:事件从父元素传递到子元素的过程,称为事件捕获。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .div1{ width: 400px; height: 400px; background-color: #F00; } .div2{ width: 200px; height: 200px; background-color: #00F; } </style> </head> <body> <div class="div1"> <div class="div2"></div> </div> <script> window.onload = function(){ let div1 = document.querySelector('.div1'); let div2 = document.querySelector('.div2'); div1.onclick = function(){ alert('父元素的单击事件'); } div2.onclick = function(event){ alert('子元素的单击事件'); // 阻止事件冒泡 event.cancelBubble = true; } }; </script> </body> </html>
阻止浏览器默认行为
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> window.onload = function(){ // 右键事件 document.oncontextmenu = function(e){ // 阻止浏览器默认的行为 e.preventDefault(); } } </script> </body> </html>
示例
时钟
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- 导入自定义的JS文件 --> <script src="./js/common.js"></script> <style> div { width: 150px; height: 50px; border: solid 1px #00F; margin-bottom: 10px; font-size: 35px; text-align: center; line-height: 50px; } </style> </head> <body> <div></div> <button class="start">开始</button> <button class="stop">停止</button> <script> window.onload = function () { let clock = document.querySelector('div'); let start = document.querySelector('.start'); let stop = document.querySelector('.stop'); // 创建定时器,显示当前的时间 let showTime = function () { clock.innerHTML = formatTime(new Date()); } showTime(); let timer = setInterval(showTime, 1000); // 开始按钮的单击事件 start.onclick = function(){ if(timer == 0){ // setInterval()方法返回类型为number,表示第N个定时器 timer = setInterval(showTime, 1000); } } // 停止按钮的单击事件 stop.onclick = function () { if(timer !== 0){ clearInterval(timer); timer = 0; } } } </script> </body> </html>
全选
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <table> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第一集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第二集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第三集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第四集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第五集</td> </tr> <tr> <td colspan="2"> <button class="selectAll">全部选中</button> <button class="unSelectAll">全部取消</button> </td> </tr> </table> <script> window.onload = function(){ let selectAll = document.querySelector('.selectAll'); let selectArray = document.getElementsByClassName('isSelect'); // 设置全选按钮的单击事件 selectAll.onclick = function(){ for(let i = 0 ; i < selectArray.length ; i++){ selectArray[i].checked = true; } } let unSelectAll = document.querySelector('.unSelectAll'); unSelectAll.onclick = function(){ for(let i = 0 ; i < selectArray.length ; i++){ selectArray[i].checked = false; } } } </script> </body> </html>
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <table> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第一集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第二集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第三集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第四集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第五集</td> </tr> <tr> <td colspan="2"> <button class="selectAll" onclick="fun(true)">全部选中</button> <button class="unSelectAll" onclick="fun(false)">全部取消</button> </td> </tr> </table> <script> let selectArray = document.getElementsByClassName('isSelect'); function fun(val){ for(let i = 0 ; i < selectArray.length ; i++){ selectArray[i].checked = val; } } </script> </body> </html>
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <table> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第一集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第二集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第三集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第四集</td> </tr> <tr> <td><input type="checkbox" class="isSelect"/></td> <td>XXXXXXXXXXXXX 第五集</td> </tr> <tr> <td><input type="checkbox" id="selectAll"/></td> <td>全选</td> </tr> </table> <script> let selectArray = document.getElementsByClassName('isSelect'); let selectAll = document.getElementById('selectAll'); selectAll.onclick = function(){ for(let i = 0 ; i < selectArray.length ; i++){ selectArray[i].checked = this.checked; } } // 设置除全选复选按钮外,其它所有复选按钮的单击事件 for(let i = 0 ; i < selectArray.length ; i++){ selectArray[i].addEventListener('click',function(){ // 找到所有选中的并且class属性为isSelect的元素 let selectCount = document.querySelectorAll('.isSelect:checked').length; selectAll.checked = (selectArray.length == selectCount); }); } </script> </body> </html>
轮播
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .lunbo { width: 1226px; height: 460px; margin: 0 auto; position: relative; } .lunbo img { position: absolute; width: 100%; height: 100%; left: 0; top: 0; display: none; } </style> </head> <body> <div class="lunbo"> <img src="./img/lunbo1.jpg" alt=""> <img src="./img/lunbo2.jpg" alt=""> <img src="./img/lunbo3.jpg" alt=""> <img src="./img/lunbo4.jpg" alt=""> <img src="./img/lunbo5.jpg" alt=""> </div> <script> window.onload = function () { // 获得轮播DIV中所有的图片 let imgArray = document.querySelectorAll('.lunbo img'); // 获得轮播图片的总数 let imgCount = imgArray.length; // 设置当前轮播图片的位置 let index = 0; // 显示当前的轮播图片 imgArray[index].style.display = 'block'; // 使用定时器,实现轮播效果 setInterval(function () { // 重新设置当前轮播图片的位置 index++; // 如果超出了轮播图片的范围,将当前轮播图片的位置重置为0 if (index > imgCount - 1) { index = 0; } // 无条件隐藏图片 for (let i = 0; i < imgArray.length; i++) { imgArray[i].style.display = 'none'; } // 显示当前轮播图片 imgArray[index].style.display = 'block'; }, 2000); } </script> </body> </html>
轮播2
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .lunbo { width: 1226px; height: 460px; margin: 0 auto; position: relative; } .lunbo img { position: absolute; width: 100%; height: 100%; left: 0; top: 0; opacity: 0; } </style> </head> <body> <div class="lunbo"> <img src="./img/lunbo1.jpg" alt=""> <img src="./img/lunbo2.jpg" alt=""> <img src="./img/lunbo3.jpg" alt=""> <img src="./img/lunbo4.jpg" alt=""> <img src="./img/lunbo5.jpg" alt=""> </div> <script> window.onload = function () { // 获得轮播DIV中所有的图片 let imgArray = document.querySelectorAll('.lunbo img'); // 获得轮播图片的总数 let imgCount = imgArray.length; // 获得当前图片的位置 let curIndex = 0; // 获得上一张图片的位置 let preIndex = imgCount - 1; // 设置当前图片的透明度为透明状态 let curOpacity = 0; // 设置上一张图片的透明度为不透明状态 let preOpacity = 1; // 设置上一张图片的透明度 imgArray[preIndex].style.opacity = preOpacity; // 在页面打开时,先执行一次淡入淡出的操作 showImage(); hideImage(); // 使用定时器,实现轮播图片淡入淡出的效果 setInterval(function(){ // 淡出上一张图片 showImage(); // 淡入当前图片 hideImage(); // 保存上一张图片的位置 preIndex = curIndex; // 重新设置当前图片的位置 curIndex++; // 判断当前图片的位置是否越界 if(curIndex > imgCount - 1){ curIndex = 0; } },3000); // 淡入图片 function showImage(){ // 重新设置当前图片的透明度为0 curOpacity = 0; let timer = setInterval(function(){ // 增加当前图片的透明度 curOpacity += 0.03; // 判断透明度增加后是否大于1 if(curOpacity >= 1 ){ // 停止定时器 curOpacity = 1; clearInterval(timer); } imgArray[curIndex].style.opacity = curOpacity; },40); } // 淡出图片 function hideImage(){ preOpacity = 1; let timer = setInterval(function(){ preOpacity -= 0.03; if(preOpacity <= 0 ){ preOpacity = 0; clearInterval(timer); } imgArray[preIndex].style.opacity = preOpacity; },40); } } </script> </body> </html>
JS中使用正则表达式
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="text" class="msg"> <button class="btn">确定</button> <script> window.onload = function(){ let btn = document.querySelector('.btn'); btn.onclick = function(){ let val = document.getElementsByTagName('input')[0].value; // JS中正则表达式必须放在一对斜杠中 // i:不区分大小写 let reg = /^[a-z]+$/i; if( !reg.test(val) ){ alert('Error'); } } let temp = new Date().toLocaleDateString(); console.log(temp); // g:表示所有或全局 temp = temp.replace(/\//g,"-"); console.log(temp); } </script> </body> </html>
JSON
JSON对象与数据
-
// 创建空的JSON对象,JSON对象中的内容放在一对大括号中 let user = {}; // JSON中数据的格式:key: value user = { 'userId': 100 } // 一个JSON对象中可以存在多个键值对,键值对之间逗号分隔 user = { 'userId': 100, 'userName': '张三' } // 等价于 user = { userId: 100, userName: '张三' }
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let user = { 'userId': 100, 'userName': '张三', 'userSex': '男', 'userRegDate': new Date(), 'userVip': false, 'userAddress': null }; console.log(user); console.log(user.userId); console.log(user.userName); console.log(user.userSex); console.log(user.userRegDate); console.log(user.userVip); console.log(user.userAddress); user.userId = 200; user.userName = '李四'; console.log(user); // 使用for-in循环获得JSON对象中所有的属性名 for(k in user){ console.log(k + "->" + user[k]); } </script> </body> </html>
JSON对象的嵌套
-
let emp = { 'empId': 100, 'empName': '张三', 'empSalary': 5000.00, 'dept': { 'deptId': 1, 'deptName': '培训部' } } console.log(emp); console.log(emp.dept.deptName);
删除JSON对象中的属性
-
let emp = { 'empId': 100, 'empName': '张三', 'empSalary': 5000.00, 'dept': { 'deptId': 1, 'deptName': '培训部' } } console.log(emp); console.log(emp.dept.deptName); // 删除JSON对象中指定的key delete emp.dept; console.log(emp); // 另一种方式:key必须放在引号中 delete emp['dept']; console.log(emp);
JSON数组
-
let array = [{ 'userId': 100, 'userName': '张三' }, { 'userId': 200, 'userName': '李四' }, { 'userId': 300, 'userName': '王五' }]; for(let i = 0 ; i < array.length ; i++){ console.log(array[i]); console.log(array[i].userId); console.log(array[i].userName); }
JSON的stringify()与parse()方法
-
stringify():将JSON的对象转换为JS的字符串。
-
parse():将JS的字符串转换为JSON对象。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let array = [{ 'userId': 100, 'userName': '张三', 'userMessage': function () { console.log(this.userId + "," + this.userName); } }, { 'userId': 200, 'userName': '李四', 'userMessage': function () { console.log(this.userId + "," + this.userName); } }, { 'userId': 300, 'userName': '王五', 'userMessage': function () { console.log(this.userId + "," + this.userName); } }]; for (let i = 0; i < array.length; i++) { array[i].userMessage(); } console.log(array); let str = JSON.stringify(array); console.log(str); let array1 = JSON.parse(str); console.log(array1); console.log(array1[0]); </script> </body> </html>
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="test"></div> <script> window.onload = function(){ let user = { 'userId': 100, 'userName': '张三' }; let div = document.getElementById("test"); div.setAttribute('name',JSON.stringify(user)); console.log(div.getAttribute("name")); let user1 = JSON.parse(div.getAttribute("name")); console.log(user1); } </script> </body> </html>
ES6
let与const
-
let不会出现变量提升的问题。
// 报错,不会出现变量提升的问题 console.log(num); let num = 100;
模板字符串
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul> </ul> <script> let user = { 'userId': 100, 'userName': '张三', 'userAge': 20 }; let msg = `<li>用户编号:${user.userId}</li> <li>用户姓名:${user.userName}</li> <li>用户年龄:${user.userAge}</li>` document.getElementsByTagName('ul')[0].innerHTML = msg; </script> </body> </html>
-
模板字符串使用``符号,其中可以使用${}编写JS代码。
函数参数的默认值
-
function sum(num1 = 10, num2 = 20) { return num1 + num2; } console.log(sum()); console.log(sum(100)); console.log(sum(100, 200));
rest与for..of循环
-
rest与Java中可变长参数功能一致。
-
rest的本质是一维数组。
-
rest可以使函数传递数据时,更灵活。
-
rest格式:...参数名
-
如果函数有多个参数,rest的参数必须出现在最后。
-
for..of循环:与JavaforEach循环一致。
function f1(...values){ console.log(values); for(let v of values){ console.log(v); } } f1(); console.log("----------------------"); f1(100); console.log("----------------------"); f1(10,20,30,40,50,60,70,80,90,100);
ES6箭头函数
-
ES6中为集合提供了一个名为forEach()的函数,用于遍历集合。
function fun(...numbers){ numbers.forEach(function(item){ console.log(item + 20); }); } fun(10,20,30,40,50,60);
-
当箭头函数只有一个参数时,参数列表的小括号可以省略。
-
如果函数体中只有一行代码时,大括号可以省略。如果大括号省略时,return关键字也必须省略。
let f1 = function () { console.log("无参数无返回值"); } let f2 = () => console.log("无参数无返回值"); f1(); f2(); let f3 = function (num) { console.log(`一个参数无返回值,num:${num}`); } let f4 = num => console.log(`一个参数无返回值,num:${num}`); f3(10); f4(100); let f5 = function (num1, num2) { console.log(num1 + num2); } let f6 = (num1, num2) => console.log(num1 * num2); f5(10, 20); f6(10, 20); // 没有参数有返回值 let f7 = function(){ return Math.random(); } // 没有参数有返回值 let f8 = () => Math.random(); console.log(f7()); console.log(f8()); // 一个参数有返回值 let f9 = function(num){ return num * Math.random(); } // 一个参数有返回值 let f10 = num => num * Math.random(); console.log(f9(10)); console.log(f10(100)); // 两个参数有返回值 let f11 = function(num1,num2){ return num1 + num2; } let f12 = (num1,num2) => num1 * num2; console.log(f11(10,20)); console.log(f12(10,20)); function fun(...numbers) { numbers.forEach(function (item) { console.log(item + 20); }); numbers.forEach(item => console.log(item * 10)); } fun(10, 20, 30, 40, 50, 60);
-
使用箭头函数返回JSON对象。
let f1 = function(userId,userName){ let user = { 'userId': userId, 'userName': userName } return user; } console.log(f1(100,'张三')); let f2 = (userId,userName) => ({'userId':userId,'userName':userName}) console.log(f2(200,'李四'));
-
示例
let array = [10, 45, 67, 36, 78, 9]; // 升序排序 array.sort(function (num1, num2) { return num1 - num2; }); console.log(array); // 降序排序 array.sort((num1, num2) => num2 - num1); console.log(array);
箭头函数与普通函数的区别
-
普通函数的this关键字,永远指向调用函数的对象。
-
箭头函数的this关键字,永远指定其定义的环境(上下文),任何方法都不能改变其指向。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="text"> <script> window.onload = () => { let input = document.getElementsByTagName("input")[0]; // input.onchange = function(){ // console.log(this.value); // console.log(this); // } input.onchange = ()=>{ console.log(this.value); console.log(this); } let user = { 'userId': 100, 'userName': '张三', 'userMessage': function(){ console.log('调用了userMessage函数'); console.log(this); }, 'userMessage1':() => { console.log('调用了userMessage1函数'); console.log(this); } }; user.userMessage(); user.userMessage1(); } </script> </body> </html>
使用函数模仿类
-
// 通过函数模拟类 function Person(name,age){ this.name = name; this.age = age; } // 返回类的实例 let p = new Person('张三',20); let p1 = new Person('李四',30); console.log(`${p.name},${p.age}`); console.log(`${p1.name},${p1.age}`); console.log(typeof Person);
-
原型对象:prototype
// 通过函数模拟类 function Person(name,age){ this.name = name; this.age = age; } // 向模拟的Person类中添加函数 Person.prototype.print = function(){ console.log(`${this.name},${this.age}`); } // 返回类的实例 let p = new Person('张三',20); let p1 = new Person('李四',30); p.print(); p1.print(); console.log(typeof Person);
-
类所有的对象共享一个prototype原型对象。
console.log(p === p1); console.log(p.prototype === p1.prototype);
-
构造函数的原型对象prototype是所有实例对象共享的。
-
每一个构造函数都有一个prototype属性。
-
-
原型对象存在的意义是什么?
- 共享方法,节省内存。
ES6中Class类
- ES6中的Class的本质还是function。
基本语法
-
// 匿名类 let Person = class{ // 构造方法 constructor(id = 100){ this.id = id; } } console.log(Person); let p = new Person(); console.log(p); console.log(p.id); let p1 = new Person(10); console.log(p1); console.log(p1.id); console.log(typeof Person);
-
// 命名类 let Person = class Example { constructor(id, name) { this.id = id; this.name = name; } } console.log(Person); let p = new Person(100,'张三'); console.log(p); console.log(p.id); console.log(p.name); console.log(Person.name); // 输出Example类名
-
// 声明类 class Person{ constructor(id,name,age){ this.id = id; this.name = name; this.age = age; } print(){ console.log(`${this.id},${this.name},${this.age}`); } } let p = new Person(100,'张三',20); console.log(p); p.print(); console.log(typeof Person);
类中的方法
-
constructor构造方法
-
类中默认的方法,如果没有在类中书写constructor()方法,则默认添加。
class Person{ constructor(){ console.log('调用了构造方法'); } } // 在new关键字的后面,自动调用构造方法 new Person();
-
class Person{ constructor(){ // 默认返回this,也可以返回其它类型的对象 return new Date(); } } // 在new关键字的后面,自动调用构造方法 console.log(new Person() instanceof Person); // false console.log(new Person() instanceof Date); // true
-
ES6中的模块(Module)
- ES6出现之前JS没有模块。为了解决这个问题出了两种解决方案:CommonJS和AMD。前者用于服务器端,后者用于浏览器端。
- 在ES6中出现了模块(Module)的概念,并且实现非常简单,所以ES6的出现,取代了CommonJS和AMD。
- ES6的模块化设计思想是尽量静态化,在编译时确定模块的依赖翔升,以及输入与输出的变量。
- ES6的模块主要由两个命令构成:export,import。
- export命令:设计向外输出的接口。
- import命令:导入模块。
export命令
-
// 声明并导出三个变量 export let userId = 100; export let userName = '张三'; export let userAge = 20;
-
let userId = 100; let userName = '张三'; let userAge = 20; // 一次性输出内容 export {userId,userName,userAge}
-
// 声明并输出方法 export function sum(num1,num2){ return num1 + num2; }
-
// 声明方法 function sum(num1, num2) { return num1 + num2; } // 一次性输出内容 export { userId, userName, userAge, sum }
-
export命令出现在JS的顶层,不能出现在函数或块中。
import命令
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script type="module"> import {userId,userName,userAge,sum} from './js/test.js'; console.log(userId); console.log(userName); console.log(userAge); console.log(sum(100,300)); </script> </body> </html>
Vue.js
MVVM
- M:Model,数据
- V:View,视图
- VM:ViewModel,连接M与V的工具。
Vue基本的使用与数据显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 插值表达式:两对嵌套的大括号,将Vue对象中指定名字的数据,显示在HTML页面指定的位置 -->
{{message}}
</div>
<div id="app1">
<!-- v-text的功能与插值表达式一致,如果网速慢插值表达式会出现闪烁的情况,v-text不会 -->
<p v-text="message"></p>
</div>
<div class="app2">
<p>{{message}}</p>
<p v-text="message"></p>
<!-- v-html可以执行数据中的HTML与CSS代码 -->
<p v-html="message"></p>
</div>
<!-- 导入Vue的JS文件 -->
<script src="./js/vue.js"></script>
<script>
const vue = new Vue({
// Vue操作的元素
el: "#app",
// 数据
data: {
message: '测试数据'
}
});
const vue1 = new Vue({
el: '#app1',
data: {
message: '测试数据1'
}
});
const vue2 = new Vue({
el: '.app2',
data: {
message: '<span style="color:#F00">测试数据1</span>'
}
});
</script>
</body>
</html>
循环
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <!-- 普通循环:v-for表示vue中的循环。 --> <div v-for="item in loop">{{item}}</div> <hr> <select name="" id=""> <!-- 为循环添加索引,索引从0开始 --> <option v-for="(item,index) in loop">{{index}}->{{item}}</option> </select> </div> <div id="app1"> <!-- 循环数组中的JSON对象 --> <table border="1" width="400px"> <tr v-for="user in userList"> <td>{{user.userId}}</td> <td>{{user.userName}}</td> <td>{{user.userSex==0?'男':'女'}}</td> </tr> </table> <!-- 循环整数:从1开始循环到指定的整数 --> <p v-for="num in count"> {{num}} </p> </div> <script src="./js/vue.js"></script> <script> const vue = new Vue({ el: '#app', data: { loop: ['AA', 'BB', 'CC', 'DD', 123, new Date().toLocaleDateString()] } }); const vue1 = new Vue({ el: '#app1', data: { userList: [{ 'userId': 100, 'userName': '张三', 'userSex': 0 }, { 'userId': 200, 'userName': '李四', 'userSex': 1 }, { 'userId': 300, 'userName': '王五', 'userSex': 0 }, { 'userId': 400, 'userName': '赵六', 'userSex': 1 }], count: 10 } }); </script> </body> </html>
v-model双向绑定
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <p> {{message}} <!-- v-model:数据双向绑定,视图中的数据与Vue对象中的数据会相互影响 --> <input type="text" v-model="message"> </p> <hr> <p> 用户编号:<input type="text" v-model="user.userId"> </p> <p> 用户姓名:<input type="text" v-model="user.userName"> </p> <p> 用户性别:<input type="text" v-model="user.userSex"> </p> <p> <!-- v-on:绑定事件,当发生指定的事件时,调用Vue对象中指定名字的函数 --> <button v-on:click="updateUser">编辑</button> </p> <hr> <p> 行:<input type="number" min="1" max="999" v-model="rowCount" v-on:change="changeRows"> </p> <p> 列:<input type="number" min="1" max="999" v-model="colCount" v-on:change="changeCols"> </p> <table border="1"> <tr v-for="r in rowArray"> <td v-for="c in colArray">{{r * c}}</td> </tr> </table> </div> <script src="./js/vue.js"></script> <script> const vue = new Vue({ el: '#app', data: { message: '', user: { 'userId': 100, 'userName': '张三', 'userSex': '男' }, rowCount: 1, colCount: 1, rowArray: [1], colArray: [1] }, // 函数 methods: { updateUser: function () { console.log(this.user); }, changeRows: function () { // 根据rowCount的值,重置rowArray数组 this.rowArray = []; for (let i = 1; i <= this.rowCount; i++) { this.rowArray.push(i); } }, changeCols: function () { this.colArray = []; for (let i = 1; i <= this.colCount; i++) { this.colArray.push(i); } } } }); </script> </body> </html>
Vue3的使用
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="testApp"> {{message}} <ul> <li v-text="user.userId"></li> <li v-text="user.userName"></li> </ul> </div> <!-- 导入Vue3 --> <script src="https://unpkg.com/vue@next"></script> <script> // Vue3.X const app = Vue.createApp({ data() { return { message: '测试数据', user: { 'userId': 100, 'userName': '张三' } } } }); // 挂载元素 app.mount('#testApp'); </script> </body> </html>
computed计算属性
-
computed有缓存,当数据没有变化时computed会读取缓存中的数据,只有当数据发生变化时,才会自动调用指定的方法。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="testApp"> <table style="width: 600px;text-align: left;"> <thead> <tr> <th>序号</th> <th>商品名称</th> <th>商品价格</th> <th>购买数量</th> <th>合计</th> </tr> </thead> <tbody> <tr v-for="(goods,index) in goodsList"> <td>{{index + 1}}</td> <td>{{goods.goodsName}}</td> <td>{{goods.goodsPrice}}</td> <td> <input type="number" v-model="goods.goodsNum" style="width: 50px;border: none;outline: none;"> </td> <td>{{goods.goodsPrice * goods.goodsNum}}</td> </tr> <tr> <td colspan="5" style="text-align: right;"> 合计:{{sum}} </td> </tr> </tbody> </table> </div> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data() { return { // 从后台服务器中得到的购物车信息 goodsList: [{ 'goodsId': 100, 'goodsName': 'XXXXXXX-1', 'goodsPrice': 10.0, 'goodsNum': 1 }, { 'goodsId': 101, 'goodsName': 'XXXXXXX-2', 'goodsPrice': 100.0, 'goodsNum': 1 }, { 'goodsId': 102, 'goodsName': 'XXXXXXX-3', 'goodsPrice': 30.0, 'goodsNum': 1 }, { 'goodsId': 103, 'goodsName': 'XXXXXXX-4', 'goodsPrice': 50.0, 'goodsNum': 1 }, { 'goodsId': 104, 'goodsName': 'XXXXXXX-5', 'goodsPrice': 150.0, 'goodsNum': 1 }] } }, /* 如果多次调用一个方法,每次调用方法都会执行。 如果多次调用一个计算属性,如果值没有发生任何变化,则计算属性只会调用一次,后面几次直接显示结果。 */ computed: { sum: function(){ let sum = 0; for(goods of this.goodsList){ sum = sum + (goods.goodsPrice * goods.goodsNum); } return sum; } } }); app.mount("#testApp"); </script> </body> </html>
watch属性
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="testApp"> <p>computed示例:</p> <input type="text" v-model="email1" > <div v-text="checkEmail"></div> <hr> <p>watch示例:</p> <input type="text" v-model="email2"> <div v-text="error2"></div> </div> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data() { return { reg: /^[a-z|A-Z|0-9]+@[a-z|A-Z|0-9]+\.(com|cn)$/, error1: '', error2: '', email1: '', email2: '' } }, computed: { checkEmail: function(){ console.log('调用了计算属性的方法'); if(this.email1 != '' && !this.reg.test(this.email1)){ return '邮箱格式不正确'; }else{ return ''; } } }, watch: { email2: function(newValue,oldValue){ if(newValue != '' && !this.reg.test(newValue)){ this.error2 = '邮箱格式不正确'; }else{ this.error2 = ''; } } } }); app.mount('#testApp'); </script> </body> </html>
- computed:有缓存,当数据没发生变化时,优先使用缓存中的数据,而不会重新执行代码,推荐使用。
- watch:没有缓存,无论数据是否发生变化,都会重新执行代码。
v-bind与v-on
-
v-bind:用于设置标签的属性。可以使用冒号代替。v-bind:style可以简写为:style。
-
v-on:用于设置标签的事件。可以使用@代码。v-on:click可以简写为@click。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="wrapper"> <p> 用户姓名: <input type="text" v-model="userName"> <span :style="fontColor" >{{userNameError}}</span> </p> <p> 用户密码: <input type="password" v-model="userPassword"> <span :style="fontColor">{{userPasswordError}}</span> </p> <p> <button @click="login">登录</button> </p> </div> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data () { return { fontColor: 'color:#F00', userName: '', userNameError: '*', userPassword: '', userPasswordError: '*' } }, methods: { login: function(){ if(this.userName == '' || this.userName.length == 0){ this.userNameError = '用户名不能为空'; document.getElementsByTagName("input")[0].focus(); return; }else{ this.userNameError = '*'; } if(this.userPassword == ''){ this.userPasswordError = '用户密码不能为空' return; }else{ this.userPasswordError = '*'; } } } }).mount('#wrapper'); </script> </body> </html>
操作Class属性
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="./css/vue-08.css"> <title>Document</title> </head> <body> <div id="wrapper"> <!-- 当layout1为true时,使用panel样式。当layout2为true时,使用panel1样式 --> <div :class="{panel:layout1,panel1:layout2}"> <div :class="{item:layout1,item1:layout2}"></div> <div :class="{item:layout1,item1:layout2}"></div> <div :class="{item:layout1,item1:layout2}"></div> <div :class="{item:layout1,item1:layout2}"></div> </div> <button @click="changeLayout(1)">水平布局</button> <button @click="changeLayout(2)">垂直布局</button> </div> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data() { return { layout1: true, layout2: false } }, methods: { changeLayout:function(type){ this.layout1 = false; this.layout2 = false; switch(type){ case 1: this.layout1 = true; break; case 2: this.layout2 = true; } } } }).mount('#wrapper'); </script> </body> </html>
v-if与v-show
-
v-if:当条件为true时元素显示,否则元素隐藏。
-
v-show:当变量为true时元素显示,否则元素隐藏。
-
v-if与v-show的区别:
- v-if:每次都会重新创建与删除元素,所以切换的消耗比较高,如果元素需要频繁切换不建议使用v-if。
- v-show:切换时不会重新创建与删除元素,只是修改元素的display属性。所以初始渲染消耗比较高。如果元素很少被显示不建议使用v-show。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="./css/vue-09.css"> <title>Document</title> </head> <body> <!-- 总容器的开始 --> <div id="wrapper"> <!-- 登录的开始 --> <!-- v- --> <div id="login-panel" v-if="showPanel === 'login'"> <!-- 第1行 --> <div class="row1"> <p>用户名:</p> <input type="text"> </div> <!-- 第2行 --> <div class="row2"> <p>密码:</p> <input type="password"> </div> <!-- 第3行 --> <div class="row3"> <button>登录</button> <button>重置</button> <button @click="showDiv('register')">注册</button> </div> </div> <!-- 登录的结束 --> <!-- 注册的开始 --> <div id="register-panel" v-if="showPanel === 'register'"> <div class="row"> <p>用户名:</p> <input type="text"> </div> <div class="row"> <p>密码:</p> <input type="password"> </div> <div class="row"> <p>确认密码:</p> <input type="password"> </div> <hr> <div class="row" v-show="showRow"> <p>邮箱:</p> <input type="text"> </div> <div class="row" v-show="showRow"> <p>联系电话:</p> <input type="text"> </div> <div> <button>注册</button> <button>重置</button> <button @click="showFun">更多……</button> <button @click="showDiv('login')">使用已有账号登录</button> </div> </div> <!-- 注册的结束 --> </div> <!-- 总容器的结束 --> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data() { return { showPanel: 'login', showRow: false } }, methods: { showDiv: function (type) { this.showPanel = type; }, showFun: function () { this.showRow = !this.showRow; } }, }).mount("#wrapper"); </script> </body> </html>
数组的变异方法
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <p> 内容:<input type="text" v-model="msg"> </p> <p> 位置:<input type="text" v-model="index"> </p> <button @click="push">末尾追加</button> <button @click="pop">末尾移除</button> <button @click="unshift">开头添加</button> <button @click="shift">开头移除</button> <button @click="add">指定位置添加</button> <button @click="deleteItem">指定位置删除</button> <button @click="reverse">反转</button> <button @click="sort">排序</button> <hr> <ul> <li v-for="item in dataList">{{item}}</li> </ul> </div> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data() { return { dataList: ['AA', 'BB', 'CC'], msg: '', index: 0 } }, methods: { push: function () { if (this.msg == '') { return; } this.dataList.push(this.msg); this.msg = ''; }, unshift: function () { if (this.msg == '') { return; } this.dataList.unshift(this.msg); this.msg = ''; }, pop: function () { if (this.dataList === null || this.dataList.length === 0) { return; } this.dataList.pop(); }, shift: function () { if (this.dataList === null || this.dataList.length === 0) { return; } this.dataList.shift(); }, deleteItem: function () { if (this.index == '' || this.index < 0 || this.index > this.dataList.length - 1) { return; } // 从数组指定的位置开始,删除指定个数的数据 this.dataList.splice(this.index, 1); }, add: function () { if (this.msg == '') { return; } if (this.index === '' || this.index < 0 || this.index > this.dataList.length - 1) { return; } // 在数组指定的位置之前,插入第三个参数的数据 // 当第二个参数大于0时,表示根据第一个参数,将指定长度(第二个参数)的数据,替换为第三个参数的值 this.dataList.splice(this.index, 0, this.msg); }, reverse: function () { this.dataList.reverse(); }, sort: function () { this.dataList.sort((item1, item2) => item1 - item2 ); } } }).mount('#app'); </script> </body> </html>
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <!-- 显示所有随机数的无序列表 --> <ul> <li v-for="num in numArray">{{num}}</li> </ul> <hr> <button @click="odd">奇数</button> <button @click="even">偶数</button> <h3>奇数</h3> <ul> <li v-for="odd in oddNumArray">{{odd}}</li> </ul> <h3>偶数</h3> <ul> <li v-for="even in evenNumArray">{{even}}</li> </ul> </div> <script src="./js/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { numArray: [], // 保存所有的随机数 oddNumArray: [], // 保存所有的奇数 evenNumArray: [] // 保存所有的偶数 } }, created() { for (let i = 0; i < 10; i++) { this.numArray[i] = parseInt(Math.random() * 100 + 1); } }, methods: { odd: function () { // 获得numArray数组中所有的奇数,并将奇数存入另一个数组中 this.oddNumArray = this.numArray.filter(function (item) { if (item % 2 != 0) { return item; } }); }, even: function(){ this.evenNumArray = this.numArray.filter(function(item){ if(item % 2 == 0){ return item; } }); } } }).mount('#app'); </script> </body> </html>
表单数据的绑定
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <table> <tr> <td>用户名:</td> <td> <input type="text" v-model="user.userName"> </td> </tr> <tr> <td>密码:</td> <td> <input type="password" v-model="user.userPassword1"> </td> </tr> <tr> <td>确认密码:</td> <td> <input type="password" v-model="user.userPassword2"> </td> </tr> <tr> <td>用户性别:</td> <td> <input type="radio" value="1" v-model="user.userSex">男 <input type="radio" value="2" v-model="user.userSex">女 </td> </tr> <tr> <td>城市:</td> <td> <input type="checkbox" value="1" v-model="user.userCity">北京 <input type="checkbox" value="2" v-model="user.userCity">上海 <input type="checkbox" value="3" v-model="user.userCity">大连 </td> </tr> <tr> <td>学历:</td> <td> <select v-model="user.userDegree"> <option value="1">小学</option> <option value="2">中学</option> <option value="3">大学</option> </select> </td> </tr> <tr> <td>教育经历:</td> <td> <textarea name="" id="" cols="30" rows="10" v-model="user.userEdu"></textarea> </td> </tr> <tr> <td colspan="2"> <button @click="saveUser">注册</button> </td> </tr> </table> </div> <script src="./js/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { user: { 'userName': '测试用户名', 'userPassword1': '', 'userPassword2': '', 'userSex': '1', 'userCity': ['1', '3'], 'userDegree': '2', 'userEdu': '' } } }, methods: { saveUser(){ console.log(this.user); } } }).mount('#app'); </script> </body> </html>
组件(componet)
全局组件
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script src="./js/vue.global.js"></script> <script> const app = Vue.createApp({}); // 创建全局组件,并为全局组件设置名字 app.component('my-component',{ template: `<ul> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> </ul>` }); app.mount('#app'); </script> </body> </html>
-
全局组件:只要声明,即使不使用也会初始化,影响性能。
组件中的数据与方法
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script src="./js/vue.global.js"></script> <script> const app = Vue.createApp({}); // 创建全局组件,并为全局组件设置名字 app.component('my-component', { template: `<ul> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> <li>得票总数:{{count}}</li> </ul> <button @click='add'>投票</button> <hr>`, data() { return { count: 0 } }, methods: { add: function () { this.count++; } } }); app.mount('#app'); </script> </body> </html>
局部组件
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-com></my-com> <my-com></my-com> <my-com></my-com> <my-com></my-com> <my-com></my-com> </div> <script src="./js/vue.global.js"></script> <script> // 创建局部组件 const myCom = { template: `<ul> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> <li>得票总数:{{count}}</li> </ul> <button @click='add'>投票</button> <hr>`, data() { return { count: 0 } }, methods: { add: function () { this.count++; } } } const app = Vue.createApp({ // 将局部组件以指定的名字,注册到Vue对象中 components: { 'my-com': myCom } }); app.mount('#app'); </script> </body> </html>
-
局部组件:如果不使用,就不会初始化,可以提高性能。
组件模板
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-com></my-com> <my-com></my-com> <my-com></my-com> <my-com></my-com> <my-com></my-com> </div> <!-- 组件模板:放在Vue对象挂载的DIV外面,作用:提高书写模板的效率 --> <template id="myTemplate"> <ul> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> <li>得票总数:{{count}}</li> </ul> <button @click='add'>投票</button> <hr> </template> <script src="./js/vue.global.js"></script> <script> // 创建局部组件 const myCom = { template: '#myTemplate', data() { return { count: 0 } }, methods: { add: function () { this.count++; } } } const app = Vue.createApp({ // 将局部组件以指定的名字,注册到Vue对象中 components: { 'my-com': myCom } }); app.mount('#app'); </script> </body> </html>
父子组件
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-com></my-com> <my-com></my-com> <my-com></my-com> </div> <!-- 父组件模板 --> <template id="myTemplate"> <ul> <!-- 包含子组件 --> <sub-com></sub-com> </ul> <button @click="add">投票</button> </template> <!-- 子组件模板 --> <template id="subTemplate"> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> <li>得票总数:</li> </template> <script src="./js/vue.global.js"></script> <script> // 声明子组件 const subCom = { template: '#subTemplate' } // 声明父组件 const myCom = { template:'#myTemplate', data(){ return { count: 0 } }, methods: { add:function(){ this.count++ } }, // 在父组件中注册子组件 components: { 'sub-com': subCom } } const app = Vue.createApp({ // 在Vue对象中注册父组件 components: { 'my-com': myCom } }).mount('#app'); </script> </body> </html>
父组件向子组件传递数据
-
组件的数据是独立。默认情况下,父子组件之间不能相互传递数据。
-
如果父组件需要向子组件传递数据,则需要使用prop属性设置。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-com></my-com> <my-com></my-com> <my-com></my-com> </div> <!-- 父组件模板 --> <template id="myTemplate"> <ul> <!-- 使用子组件时,将数据以指定属性传递到子组件中 --> <sub-com :usercount="count"></sub-com> </ul> <button @click="add">投票</button> </template> <!-- 子组件模板 --> <template id="subTemplate"> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> <li>得票总数:{{usercount}}</li> </template> <script src="./js/vue.global.js"></script> <script> // 声明子组件 const subCom = { template: '#subTemplate', // 在子组中使用prop设置接收数据的名字 props: ['usercount'] } // 声明父组件 const myCom = { template: '#myTemplate', data() { return { count: 0 } }, methods: { add: function () { this.count++ } }, // 在父组件中注册子组件 components: { 'sub-com': subCom } } const app = Vue.createApp({ // 在Vue对象中注册父组件 components: { 'my-com': myCom } }).mount('#app'); </script> </body> </html>
子组件向父组件传递数据
-
父组件不能一直监听子组件是否传递了数据。所以如果子组件需要向父组件传递数据,则子组件需要调用父组件的方法,向父组件传递数据。
-
子组件可以使用$emit()方法触发事件/自定义事件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-com></my-com> <my-com></my-com> <my-com></my-com> </div> <!-- 父组件模板 --> <template id="myTemplate"> <ul :style="color"> <!-- 使用子组件时,将数据以指定属性传递到子组件中 --> <sub-com :usercount="count"></sub-com> </ul> <button @click="add">投票</button> <sub-com2 @setcolor="setColor"></sub-com2> </template> <!-- 子组件模板 --> <template id="subTemplate"> <li>用户编号:100</li> <li>用户姓名:张三</li> <li>用户年龄:20</li> <li>得票总数:{{usercount}}</li> </template> <!-- 子组件模板 --> <template id="subTemplate2"> <input type="color" @change="colorChange"> </template> <script src="./js/vue.global.js"></script> <script> // 声明子组件 const subCom = { template: '#subTemplate', // 在子组中使用prop设置接收数据的名字 props: ['usercount'] } const subCom2 = { template: '#subTemplate2', methods: { colorChange: function(event){ // 获得触发事件控件的值 let color = event.path[0].value; // 触发父组件自定义事件,并将值传递到父组件中 this.$emit('setcolor',color); } }, } // 声明父组件 const myCom = { template: '#myTemplate', data() { return { count: 0, color: 'color:#000' } }, methods: { add: function () { this.count++ }, setColor: function(color){ this.color = 'color:' + color; } }, // 在父组件中注册子组件 components: { 'sub-com': subCom, 'sub-com2': subCom2 } } const app = Vue.createApp({ // 在Vue对象中注册父组件 components: { 'my-com': myCom } }).mount('#app'); </script> </body> </html>
插槽(slot)
-
组件可以使用插槽预留出空白位置,父组件再向子组件的插槽中添加内容。
-
插槽与prop的区别:
-
prop:只能传递字符串。
-
插槽:可以传递HTML代码。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <my-com v-for="(user,index) in userList" :userid="user.userId" :username="user.userName" :userage="user.userAge"> <!-- 向子组件的插槽中添加内容 --> <li><p style="color:#f00 ;">测试插槽{{index}}</p></li> </my-com> </div> <!-- 父组件模板 --> <template id="myTemplate"> <ul :style="color"> <!-- 预留插槽 --> <slot></slot> <!-- 使用子组件时,将数据以指定属性传递到子组件中 --> <sub-com :usercount="count" :id="userid" :name="username" :age="userage"></sub-com> </ul> <button @click="add">投票</button> <sub-com2 @setcolor="setColor"></sub-com2> </template> <!-- 子组件模板 --> <template id="subTemplate"> <li>用户编号:{{id}}</li> <li>用户姓名:{{name}}</li> <li>用户年龄:{{age}}</li> <li>得票总数:{{usercount}}</li> </template> <!-- 子组件模板 --> <template id="subTemplate2"> <input type="color" @change="colorChange"> </template> <script src="./js/vue.global.js"></script> <script> // 声明子组件 const subCom = { template: '#subTemplate', // 在子组中使用prop设置接收数据的名字 props: ['usercount', 'id', 'name', 'age'] } const subCom2 = { template: '#subTemplate2', methods: { colorChange: function (event) { // 获得触发事件控件的值 let color = event.path[0].value; // 触发父组件自定义事件,并将值传递到父组件中 this.$emit('setcolor', color); } }, } // 声明父组件 const myCom = { template: '#myTemplate', data() { return { count: 0, color: 'color:#000' } }, methods: { add: function () { this.count++ }, setColor: function (color) { this.color = 'color:' + color; } }, // 在父组件中注册子组件 components: { 'sub-com': subCom, 'sub-com2': subCom2 }, // 设置接收来自于Vue对象传递数据的属性名,均为小写 props: ['userid', 'username', 'userage'] } const app = Vue.createApp({ // 在Vue对象中注册父组件 components: { 'my-com': myCom }, data() { return { userList: [{ 'userId': 100, 'userName': '张三', 'userAge': 20 }, { 'userId': 101, 'userName': '李四', 'userAge': 20 }, { 'userId': 102, 'userName': '王五', 'userAge': 20 }, { 'userId': 103, 'userName': '赵六', 'userAge': 20 }, { 'userId': 103, 'userName': '宋六', 'userAge': 20 }] } } }).mount('#app'); </script> </body> </html>
-
Vue路由(Vue-router)
- vue-router不包含在vue中,所以需要单独导入vue-router的JS文件。
- Vue是单页面应用SPA(Simple Page Applicaiton)
路由基本使用
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <!-- 5.设置路由链接 --> <router-link to="/home">首页</router-link> <router-link to="/news">新闻</router-link> <!-- 6.设置路由出口 --> <router-view></router-view> </div> <script src="./js/vue.global.js"></script> <script src="./js/vue-router.global.js"></script> <script> // 1.创建组件 const Home = { template: '<h1>这是首页组件</h1>' } const News = { template: '<h1>这是新闻组件</h1>' } // 2.创建路由规则,设置请求与组件的映射关系 const routes = [ { path: '/', redirect: '/home' }, { path: '/home', component: Home }, { path: '/news', component: News }] // 3.创建Vue路由对象 const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: routes // 当键与值一样时,可以简写为routes }); const app = Vue.createApp({}); // 4.设置Vue对象使用的Vue路由对象 app.use(router); app.mount('#app'); </script> </body> </html>
路由嵌套
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <router-link to="/home">首页</router-link> <router-link to="/news">新闻</router-link> <router-view></router-view> </div> <!-- 1.设置首页组件模板 --> <template id="homeTemplate"> <div> <h3>首页组件</h3> <ul> <li> <router-link to="/home/login">登录</router-link> </li> <li> <router-link to="/home/register">注册</router-link> </li> </ul> <router-view></router-view> </div> </template> <script src="./js/vue.global.js"></script> <script src="./js/vue-router.global.js"></script> <script> // 2.重新设置首页组件 const Home = { template: '#homeTemplate' } const News = { template: '<h1>这是新闻组件</h1>' } // 3.创建登录与注册的子组件 const Login = { template: '<h4>这是登录子组件</h4>' } const Register = { template: '<h4>这是注册子组件</h4>' } const routes = [ { path: '/', redirect: '/home' }, { path: '/home', component: Home, // 4.设置子路由 children: [ { path: '/home/login', component: Login }, { path: '/home/register', component: Register } ] }, { path: '/news', component: News }] const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: routes // 当键与值一样时,可以简写为routes }); const app = Vue.createApp({}); app.use(router); app.mount('#app'); </script> </body> </html>
路由传递数据方法1-params
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <router-link to="/home">首页</router-link> <!-- 1.使用params传递数据 --> <router-link :to="{name: 'News',params:{userId:100,userName:'张三'}}">新闻</router-link> <router-view></router-view> </div> <template id="homeTemplate"> <div> <h3>首页组件</h3> <ul> <li> <router-link to="/home/login">登录</router-link> </li> <li> <router-link to="/home/register">注册</router-link> </li> </ul> <router-view></router-view> </div> </template> <script src="./js/vue.global.js"></script> <script src="./js/vue-router.global.js"></script> <script> const Home = { template: '#homeTemplate' } // 2.在路由对应的组件中,获得路由传递的数据 const News = { template: `<h3>新闻组件</h3> <ul> <li>{{$route.params.userId}}</li> <li>{{$route.params.userName}}</li> </ul> ` } const Login = { template: '<h4>这是登录子组件</h4>' } const Register = { template: '<h4>这是注册子组件</h4>' } const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, children: [ { path: '/home/login', component: Login }, { path: '/home/register', component: Register } ] }, { path: '/news', name: 'News', component: News }] const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: routes // 当键与值一样时,可以简写为routes }); const app = Vue.createApp({}); app.use(router); app.mount('#app'); </script> </body> </html>
-
使用params方式传递数据时,如果执行刷新操作,则数据会丢失。
路由传递数据方法2-query
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <router-link to="/home">首页</router-link> <!-- 2.设置使用query方式传递数据 --> <router-link :to="{path:'/news',query:{'userId':user.userId,'userName':user.userName}}">新闻</router-link> <router-view></router-view> </div> <template id="homeTemplate"> <div> <h3>首页组件</h3> <ul> <li> <router-link to="/home/login">登录</router-link> </li> <li> <router-link to="/home/register">注册</router-link> </li> </ul> <router-view></router-view> </div> </template> <script src="./js/vue.global.js"></script> <script src="./js/vue-router.global.js"></script> <script> const Home = { template: '#homeTemplate' } const News = { // 3.获得query方式传递的数据 template: `<h3>新闻组件</h3> <ul> <li>{{$route.query.userId}}</li> <li>{{$route.query.userName}}</li> </ul> ` } const Login = { template: '<h4>这是登录子组件</h4>' } const Register = { template: '<h4>这是注册子组件</h4>' } const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, children: [ { path: '/home/login', component: Login }, { path: '/home/register', component: Register } ] }, { path: '/news', name: 'News', component: News }] const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: routes // 当键与值一样时,可以简写为routes }); const app = Vue.createApp({ data(){ return { // 1.设置需要传递的数据 user:{ 'userId':101, 'userName':'李四' } } } }); app.use(router); app.mount('#app'); </script> </body> </html>
-
params与query的区别:
- params:传递的数据在浏览器地址栏中看不到,刷新页面时params传递的数据会丢失。
- query:传递的数据在浏览器地址栏中可以看到,刷新页面时query传递的数据不会丢失。
编程式路由
-
使用JS代码实现路由的功能。
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <!-- <router-link to="/home">首页</router-link> <router-link :to="{path:'/news',query:{'userId':user.userId,'userName':user.userName}}">新闻</router-link> --> <!-- 1.将router-link标签改为button --> <button @click="toHome">首页</button> <button @click="toNews">新闻</button> <router-view></router-view> </div> <template id="homeTemplate"> <div> <h3>首页组件</h3> <ul> <li> <router-link to="/home/login">登录</router-link> </li> <li> <router-link to="/home/register">注册</router-link> </li> </ul> <router-view></router-view> </div> </template> <script src="./js/vue.global.js"></script> <script src="./js/vue-router.global.js"></script> <script> const Home = { template: '#homeTemplate' } const News = { template: `<h3>新闻组件</h3> <ul> <li>{{$route.query.userId}}</li> <li>{{$route.query.userName}}</li> </ul> ` } const Login = { template: '<h4>这是登录子组件</h4>' } const Register = { template: '<h4>这是注册子组件</h4>' } const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, children: [ { path: '/home/login', component: Login }, { path: '/home/register', component: Register } ] }, { path: '/news', name: 'News', component: News }] const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: routes // 当键与值一样时,可以简写为routes }); const app = Vue.createApp({ data() { return { user: { 'userId': 101, 'userName': '李四' } } }, methods: { // 2.实现按钮单击事件对应的方法 toHome: function(){ this.$router.push('/home'); }, toNews: function(){ this.$router.push({ path: '/news', query: { 'userId': this.user.userId, 'userName': this.user.userName } }); } }, }); app.use(router); app.mount('#app'); </script> </body> </html>
编程式路由-前进/后退
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <button @click="toHome">首页</button> <button @click="toNews">新闻</button> <!-- 1.添加前进按钮 --> <button @click="toForward">前进</button> <router-view></router-view> </div> <template id="homeTemplate"> <div> <h3>首页组件</h3> <ul> <li> <router-link to="/home/login">登录</router-link> </li> <li> <router-link to="/home/register">注册</router-link> </li> </ul> <router-view></router-view> </div> </template> <script src="./js/vue.global.js"></script> <script src="./js/vue-router.global.js"></script> <script> const Home = { template: '#homeTemplate' } const News = { template: `<h3>新闻组件</h3> <ul> <li>{{$route.query.userId}}</li> <li>{{$route.query.userName}}</li> </ul> ` } const Login = { // 2.添加后退按钮 template: `<h4>这是登录子组件</h4> <button @click="toBack">后退</button>` ,methods: { // 4.实现后退功能 toBack: function(){ this.$router.back(); } } } const Register = { template: '<h4>这是注册子组件</h4>' } const routes = [ { path: '/', redirect: '/home' }, { path: '/home', name: 'Home', component: Home, children: [ { path: '/home/login', component: Login }, { path: '/home/register', component: Register } ] }, { path: '/news', name: 'News', component: News }] const router = VueRouter.createRouter({ history: VueRouter.createWebHashHistory(), routes: routes // 当键与值一样时,可以简写为routes }); const app = Vue.createApp({ data() { return { user: { 'userId': 101, 'userName': '李四' } } }, methods: { toHome: function(){ this.$router.push('/home'); }, toNews: function(){ this.$router.push({ path: '/news', query: { 'userId': this.user.userId, 'userName': this.user.userName } }); }, toForward: function(){ // 3.实现前进功能 this.$router.forward(); } }, }); app.use(router); app.mount('#app'); </script> </body> </html>
路由监听
-
const app = Vue.createApp({ data() { return { user: { 'userId': 101, 'userName': '李四' } } }, methods: { toHome: function () { this.$router.push('/home'); }, toNews: function () { this.$router.push({ path: '/news', query: { 'userId': this.user.userId, 'userName': this.user.userName } }); }, toForward: function () { this.$router.forward(); } }, watch: { // 添加路由监听 $route: function(newRouter,oldRouter){ console.log(newRouter); console.log(oldRouter); } } });
路由守卫
-
路由守卫与路由监听实现的功能类似。
-
路由守卫的分类:
-
全局守卫:适用所有路由。beforeEach(路由跳转之前),afterEach(路由跳转之后)。
-
组件内守卫:只针对一个路由组件。beforeRouterEnter(进入路由之前),beforRouterUpdate(更新路由之前),beforeRouterLeave(离开路由之前)
-
独享守卫:只针对一个路由组件,只有一个beforeEnter(进入路由之前)事件。
-
// 创建全局路由守卫 // next:是一个方法,表示系统的下一个动作 router.beforeEach((to, from, next)=>{ console.log(to); console.log(from); // …… next(); });
-
Vue-cli脚手架
Vue-cli项目结构
- node_modules目录:项目依赖包。
- public目录:存入模板文件与静态资源。
- src目录:开发目录。
- assets:存放CSS、图片等资源。
- components:组件(公用)。
- router:路由。
- views:视图组件。
- App.vue:根组件。
- main.js:项目入口。
- package.json:项目依赖信息。
- vue.config.js:项目配置。
TodoList练习
App.vue
-
<template> <h3>今日待办事件列表</h3> <!-- 3.使用子组件 --> <AddNew @submitNewItem="addNewItem"></AddNew> <!-- 待办事项 --> <TheList :list="todoList" @changeDone="changeDone"></TheList> <hr> <!-- 已完成事项 --> <TheList :list="doneList" :listType="true" @removeList="removeList"></TheList> </template> <script> // 1.导入AddNew.vue组件 import AddNew from './components/AddNew.vue'; import TheList from './components/TheList.vue'; export default { // 2.设置子组件 components: { AddNew, TheList }, data() { return { // 4.待办事项列表 todoList: [], // 已完成事项列表 doneList: [] } }, methods: { // 5.完成自定义事件对应的方法 addNewItem: function (item) { this.todoList.push(item); }, changeDone: function (index) { this.doneList.push(this.todoList.splice(index, 1)[0]); }, removeList: function (index) { this.doneList.splice(index, 1); } }, } </script> <style> </style>
AddNew.vue
-
<template> <div class="addNew"> <input type="text" v-model="newItem"> <button @click="addItem">添加</button> </div> </template> <script> export default { name: 'AddNew', data() { return { // 新待办事项 newItem:'' } }, methods: { addItem: function(){ if(this.newItem === ''){ alert('不能为空'); return; } // 将新待办事项,传递到父组件中 this.$emit('submitNewItem',this.newItem); this.newItem = ''; } } } </script> <!-- scoped:表示样式代码只作用于当前文件 --> <style scoped> input { border: none; outline: none; width: 300px; height: 30px; border: solid 1px #999; border-radius: 5px; padding-left: 10px; } button { border: none; outline: none; width: 80px; height: 36px; border-radius: 5px; margin-left: 5px; background-color: #42b983; color: #fff; } </style>
TheList.vue
-
<template> <ol> <li v-for="(item, index) in list" :key="index" @click="toDone(index)">{{ item }}</li> </ol> </template> <script> export default { name: 'TheList', props: { // 接收列表数据的属性名 list: { type: Array, required: true // 必须传递的数据 }, // 列表类型属性名,true表示已完成事项列表,false表示待办事项列表 listType: { type: Boolean, default: false } }, methods: { toDone: function (index) { if(this.listType){ // 已完成事项 this.$emit('removeList', index); }else{ // 待办事项 // 触发父组件自定义事件,并且将索引传递给父组件 this.$emit('changeDone', index); } } }, } </script> <style scoped> li { cursor: pointer; } </style>
Vue-cli打包编译
-
在vue.config.js文件中对打包信息进行配置。
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, // 打包编译时使用相对路径 publicPath: './', // 设置编译出的文件存放的目录 outputDir: 'dist', // 设置静态资源存放目录 assetsDir: 'assets' })
-
在控制台中执行:npm run build
AJAX基础
- AJAX的特点:
- 异步
- 页面不刷新
AJAX示例
-
AJAX中最重要的组件:XMLHttpRequest类。
-
onreadystatechange事件:可以监听readyState状态的变化。
-
readyState是XMLHttpRequest的属性,有5种状态:
- 0:未初始化,还没有调用send()方法。
- 1:载入,已经调用了send()方法,正在发出请求。
- 2:载入完成,send()方法全部执行完毕,并且已经接收到了所有的响应结果。
- 3:交互:正在解析响应的结果。
- 4:完成:响应的结果全部解析完毕,用于可以接收响应的结果。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let xhr = new XMLHttpRequest(); // 设置向服务器发出请求的模式以及URL xhr.open('get', 'http://api.tianapi.com/esports/index?key=键&num=10'); // 向服务器发出请求 xhr.send(null); // 监听readyState的状态 xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ console.log(JSON.parse(xhr.responseText)); } } </script> </body> </html>
AJAX异步
-
<script> let xhr = new XMLHttpRequest(); // 设置向服务器发出请求的模式以及URL xhr.open('get', 'http://api.tianapi.com/esports/index?key=键&num=10'); // 向服务器发出请求 xhr.send(null); // 声明变量保存响应的结果 let result ; // 监听readyState的状态 xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ // console.log(JSON.parse(xhr.responseText)); result = xhr.responseText; } } // 输出undefined,此时第27行代码没有执行 console.log(result); </script>
axios
axios发出get模式的请求
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> axios.get("http://api.tianapi.com/esports/index", { params: { key: '键', num: 10 } }).then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); </script> </body> </html>
axios发出post模式的请求
-
<script src="./js/axios.min.js"></script> <script> let params = new URLSearchParams(); params.append('key','键'); params.append('num','10'); axios.post("http://api.tianapi.com/esports/index",params).then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); </script>
axios拦截器
请求拦截器
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="./js/axios.min.js"></script> <script> let params = new URLSearchParams(); params.append('key','ada67558a172bf95a50818cbfc6a4333'); params.append('num','20'); // 创建请求拦截器 axios.interceptors.request.use(function(config){ // 发出请求之前执行的代码 console.log("发出请求之间执行的代码"); return config; },function(error){ // 发生异常时,处理异常的代码 }); axios.post("http://api.tianapi.com/esports/index",params).then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); </script> </body> </html>
响应拦截器
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src="./js/axios.min.js"></script> <script> let params = new URLSearchParams(); params.append('key','ada67558a172bf95a50818cbfc6a4333'); params.append('num','20'); // 创建请求拦截器 axios.interceptors.request.use(function(config){ // 发出请求之前执行的代码 console.log("发出请求之间执行的代码"); return config; },function(error){ // 发生异常时,处理异常的代码 }); // 创建响应拦截器 axios.interceptors.response.use(function(response){ // 得到响应后,执行的代码 console.log("得到响应后执行的代码"); return response; },function(error){ // 发生异常时,处理异常的代码 }); axios.post("http://api.tianapi.com/esports/index",params).then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); </script> </body> </html>
Vue-cli中使用axios
- 安装axios:cnpm install axios --save
- 安装qs:cnpm install qs --save,用于封装post请求的数据。
将axios配置到Vue全局属性中
-
main.js文件中。
import { createApp } from 'vue' import App from './App.vue' import router from './router' // 导入axios import axios from 'axios' // 导入qs import qs from 'qs' // 设置axios基础的URL axios.defaults.baseURL = 'http://api.tianapi.com/'; // 创建Vue对象 const app = createApp(App); // 将axios设置到Vue对象的全局属性中 app.config.globalProperties.$axios = axios; // 将qs设置到Vue对象的全局属性中 app.config.globalProperties.$qs = qs; app.use(router).mount('#app')
在Vue-cli中使用axios发出get模式请求
-
<template> <div class="home"> <h1>主页</h1> <button @click="selectItem">查询</button> </div> </template> <script> export default { name: 'HomeView', methods: { selectItem: function () { this.$axios.get('esports/index?key=键&num=10').then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); } }, } </script>
在Vue-cli中使用axios发出post模式请求
-
<template> <div class="home"> <h1>主页</h1> <button @click="selectItem">查询</button> </div> </template> <script> export default { name: 'HomeView', methods: { selectItem: function () { this.$axios.post('esports/index', this.$qs.stringify({ key: 'ada67558a172bf95a50818cbfc6a4333', num: '12' })).then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); } }, } </script>
跨域
- 同源策略(Sameoriginpolicy)是一种约定。
- 所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),域名(host)和端口号(port)。
- 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
使用Vue-cli的代理解决跨域问题
-
跨域
Access to XMLHttpRequest at 'http://v.juhe.cn/todayOnhistory/queryEvent.php' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
-
vue.config.js
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, devServer: { // 跨域代理:将以指定字符串开头的URL,开头部分替换为对应的内容 proxy: { '/juhe': { // 替换目标的URL target: 'http://v.juhe.cn/', // 是否使用相同端口号 changeOrigin: true, // 如何处理开头的内容 pathRewrite: { '/juhe': '' } } } } })
-
AboutView.vue
<template> <div class="about"> <h1>关于</h1> <button @click="select">查询</button> </div> </template> <script> export default { name: 'AboutView', methods: { select: function () { this.$axios.post('/juhe/todayOnhistory/queryEvent.php', this.$qs.stringify({ key: 'fd3b71a2f85eb7fedc35af6e70e51bf3', date: '8/11' })).then(function (response) { console.log(response); }).catch(function (error) { console.log(error); }); } } } </script>
Vuex
-
Vuex是一个专为Vue.js应用程序开发的状态管理模式+库。
-
集中式存储管理应用的所有组件的状态(其实是管理组件需要共同访问的数据)。
import { createStore } from 'vuex' export default createStore({ state: { // 存放全局数据 message: '测试全局数据' }, getters: { // 存放全局方法 }, mutations: { // 存放修改全局数据的方法 // 此部分的方法是线程安全的(同步) }, actions: { // 功能与mutations类似 // Actions返回的是mutations,而不是直接修改全局数据 // Actions是线程不安全的(异步) }, modules: { // 注册Vuex的子模块 } })
Vue的生命周期
-
什么是生命周期函数:在生命周期的某个时刻自动执行的函数。
-
Vue生命周期中有四个主要的事件:
- 创建:创建组件时执行。
- 挂载:DOM被挂载时执行。
- 更新:当数据修改时执行。
- 销毁:在元素被销毁之前立即执行。
-
每个生命周期的事件对应两个钩子函数。
- vue2.x钩子函数名
- beforeCreate()
- created()
- beforeMount()
- mountd()
- beforeUpdate()
- updated()
- beforeDestroy()
- destroyed()
- vue3.x钩子函数名
- beforeCreate()
- created()
- beforeMount()
- mountd()
- beforeUpdate()
- updated()
- beforeUnmount()
- unmounted()
<template> <div class="about"> <h1>This is an about page</h1> <h1>{{ $store.state.message }}</h1> <input type="text" ref="el"> {{ num }} </div> </template> <script> export default { name: 'AboutView', data() { return { msg: '测试生命周期的数据', num: 100 } }, beforeCreate() { // 创建组件之前执行,无法调用组件中的数据、函数等内容。 console.log('beforeCreate-->' + this.msg); }, created() { // 组件创建后执行,可以获得组件中的数据、函数等内容。 console.log('created-->' + this.msg); console.log(this.$refs.el); }, beforeMount() { // 在DOM对象挂载前执行 console.log('beforeMount-->' + this.msg); console.log(this.$refs.el); }, mounted() { // 在DOM对象挂载完毕后执行 console.log('mounted-->' + this.msg); console.log(this.$refs.el); setTimeout(() => this.num = 1000, 2000); }, beforeUpdate(){ // 组件数据修改前执行 console.log('beforeUpdate-->'); }, updated(){ // 组件数据修改后执行 console.log('updated-->'); }, beforeUnmount(){ // 对应Vue2.x中的beforeDestroy()函数,在组件销毁前执行 console.log('beforeUnmount-->'); }, unmounted(){ // 对应Vue2.x中的destroyed()函数,在组件销毁完毕时执行 console.log('unmounted-->'); } } </script>
- vue2.x钩子函数名
程序的模型
- 单机模型:数据共享困难。
- C(客户端)/S(服务器)模型
- 必须在PC中安装客户端程序,使用程序连接服务器。
- 缺点:对客户端PC的配置要求高,升级时成本高。
- 优点:客户体验好。
- 必须在PC中安装客户端程序,使用程序连接服务器。
- B(浏览器)/S(服务器)模型
- 优点:程序升级与维护时,成本相对低。对客户端PC配置要求低。
- 缺点:客户体验没有C/S好。
Tomcat
- Tomcat属于Web服务器。
配置Tomcat环境变量
- 首先,必须先安装配置相应的JDK。
- 再配置Tomcat的环境变量:
- JAVA_HOME:JDK的路径
- HOME_PATH:JDK的路径
Tomcat常用目录
- bin目录:存放与Tomcat运行相关的类库与批处理文件。
- conf目录:存放Tomcat配置文件。
- lib目录:存放公有的类库,此目录下的资源当前服务器下所有的Web应用(站点)都可以使用。
- logs目录:存放日志文件。
- webapps目录:Web Applications,用于存放当前服务器下所有的Web应用。
- work目录:存放JSP文件生成的.class文件。
解析URL
- http://www.baidu.com/bbs/index.html
- http:http协议,浏览器默认的协议。
- www.baidu.com:域名,可以通过DNS服务器将域名解析成唯一的IP地址。也可以替换为服务器名或IP地址。
- bbs:服务器中的目录。
- index.html:服务器中的文件。
修改Tomcat端口号
-
Tomcat默认监听的端口:8080。
-
修改Tomcat目录中-->conf目录-->server.xml文件。
<!-- A "Connector" represents an endpoint by which requests are received and responses are returned. Documentation at : Java HTTP Connector: /docs/config/http.html (blocking & non-blocking) Java AJP Connector: /docs/config/ajp.html APR (HTTP/AJP) Connector: /docs/apr.html Define a non-SSL/TLS HTTP/1.1 Connector on port 8080 --> <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- A "Connector" using the shared thread pool-->
在Eclipse中配置Tomcat
-
Window菜单->Preferences->Server->Runtime Environments
-
点击Add...按钮,选择对应版本的Tomcat。
-
浏览选择Tomcat目录。
-
点击Finish按钮即可。
第一个Servlet示例
-
浏览器如何访问服务器中的Servlet。
-
Servlet如何将数据传递到浏览器。
-
公有空间与私有空间的区别?
- 公有空间:WEB-INF以外的空间称为公有空间,公有空间下的资源用户可以访问,可以下载。
- 私有空间:WEB-INF目录称为私有空间,私有空间中的资源用户不能直接访问,不能下载。
-
WEB-INF目录中常用的文件与目录?
- web.xml文件:存放当前web项目的配置信息。
- classes目录:存放.class文件。
- lib目录:存放私有类库(.jar文件)。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="first">获得当前时间</a> </body> </html>
package com.test.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; // 设置当前类为Servlet,并设置访问的URL @WebServlet(urlPatterns = "/first") public class FirstServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获得向浏览器中输出数据的输出流 PrintWriter out = resp.getWriter(); // 使用输出流向浏览器输出数据 out.println("<html>"); out.println(" <body>"); out.println(" <p>" + new Date() + "</p>"); out.println(" </body>"); out.println("</html>"); // 刷新缓冲区 out.flush(); // 关闭输出流 out.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doPost(req, resp); } }
Servlet
-
Servlet是用Java编写的存放在服务器端的组件。可以动态扩展服务器的功能。
-
Servlet的结构
- javax.servletr.Servlet接口:声明了Servlet最基础的方法。
- javax.servlet.GenericServlet类:实现了Servlet接口,并重写了Servlet接口中的方法。
- javax.servlet.http.HttpServlet类:继承GenericServlet类,并对HTTP协议进行了优化。
-
创建自定义的Servlet:直接或间接实现Servlet接口。
Servlet生命周期
- 当浏览器向服务器发出请求,请求一个Servlet资源时。
- 服务器会接收请求后,会在内存(缓存)中查找是否存在指定的Servlet实例。
- 当服务器没有在内存中找到Servlet实例时,服务器会创建Servlet的实例,并调用Servlet的init()方法进行初始化,最后调用Servlet的service()方法对请求做出响应。
- 当服务器在内存中找到了Servlet实例时,直接调用Servlet实例的service()方法对请求做出响应。
- 当服务器发现在一段时间内没有任何请求访问Servlet实例时,服务器会调用Servlet的destroy()方法,再销毁此Servlet实例。
HttpServletRequest与HttpServletResponse
javax.servlet.http.HttpServletRequest常用方法
- getParameter("名字"):获得请求中指定名字的数据,返回类型一定是String类型。
- setCharacterEncoding("字符集"):设置请求的字符集。
- getParameterValues("名字"):获得请求中名字相同的一组数据,返回类型一定是String[]类型的数组。
- getServletConfig():获得当前Servlet对应的ServletConfig实例。
javax.servlet.http.HttpServletResponse常用方法
- setCharacterEncoding("字符集"):设置响应的字符集。
- setContentType("text/html;charset=字符集"):设置目标浏览器显示的内容类型以及使用的字符集。
服务器端跨域(CORS)
-
resp.setHeader("Access-Control-Allow-Origin", "*");
HTTP协议的“无状态”
- 服务器无法保存浏览器的状态。
- 服务器认为浏览器发出的请求,都是第一次请求。
javax.servlet.http.Cookie类
-
Cookie是存放在浏览器端的一个文本文件。
-
用户可以在浏览器中设置拒绝接收Cookie。
package com.test.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = "/cookie") public class CookieServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 创建Cookie Cookie cookie = new Cookie("userName", "admin"); // 设置Cookie的有效时间 cookie.setMaxAge(60 * 60 * 24); // 将Cookie添加到响应中 resp.addCookie(cookie); // 通过请求获得浏览器中的Cookie Cookie[] cookies = req.getCookies(); for (Cookie c : cookies) { System.out.println(c.getName()); System.out.println(c.getValue()); } } }
javax.servlet.http.HttpSession接口
-
Session保存在服务器端。
-
Session是服务器中的一段内存。
-
setAttribute("名字",数据):将数据以指定的名字存入到Session中。
-
getAttribute("名字"):根据名字从Session中获得指定的数据,返回类型一定为java.lang.Object类型。
-
removeAttribute("名字"):移除Session中指定名字的数据。
package com.test.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet(urlPatterns = "/session") public class SessionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获得浏览器对应的session,如果浏览器没有session则返回null // HttpSession session = req.getSession(); // 获得浏览器对应的session,如果浏览器没有session则为浏览器创建新的session HttpSession session1 = req.getSession(true); // 获得session的ID System.out.println(session1.getId()); // 获得session默认的有效时间,单位秒 System.out.println(session1.getMaxInactiveInterval()); // 设置指定session的有效时间 session1.setMaxInactiveInterval(60 * 60 * 24); // 获得session创建的时间,返回类型为long System.out.println(session1.getCreationTime()); // 获得session最后一次被访问的时间,返回类型为long System.out.println(session1.getLastAccessedTime()); // 向session中添加数据 session1.setAttribute("userName", "张三"); // 获得session中指定名字的数据 String name = (String) session1.getAttribute("userName"); System.out.println(name); // 移除session中指定名字的数据 session1.removeAttribute("userName"); } }