Java Web - 前端
Java Web - 前端
Web
Web: 全球广域网, 万维网, 能够通过浏览器访问的网站
工作流程
- 浏览器向前端服务器发出请求, 前端服务器返回页面代码, 由浏览器接收并解析生成页面
- 浏览器向后端服务器发出请求, 后端服务器向数据库服务器发出请求, 数据库服务器返回数据给后端服务器, 后端服务器再返回给浏览器
开发模式
- 混合开发: 前后端在一个服务器上运行, 返回给浏览器的页面代码包含数据
- 前后端分离开发
Web 前端
浏览器内核: 浏览器中对代码进行解析渲染的部分
- 不同的浏览器, 内核不同, 对相同的前端代码解析的效果存在差异
- Web 标准
- HTML 负责网页的结构 (页面元素和内容)
- CSS 负责网页的表现 (页面元素的外观, 位置等页面样式, 如: 颜色, 大小等)
- JavaScript 负责网页的行为 (交互效果)
如何打开 Chrome 控制台
Ctrl + Shift + J
HTML & CSS
HTML: 超文本标记语言
- 超文本: 超越了文本的限制, 比普通文本更强大, 除了文字信息, 还可以定义图片, 音频, 视频等内容
- 标记语言: 由标签构成的语言
- HTML 标签都是预定义好的
- HTML 代码直接在浏览器中运行, HTML 标签由浏览器解析
CSS: 层叠样式表, 用于控制页的样式 (表现)
标题
排版
- 图片标签:
<img>
- src: 指定图像的 url
- 绝对路径
- 绝对磁盘路径
- 绝对网络路径
- 相对路径
./
当前目录 (可省略)../
上一级目录
- 绝对路径
- width: 图像的宽度
- 像素
width="300px"
- 相对于父元素的百分比
width="80%"
- 像素
- height: 图片的高度 (一般只设置宽度, 高度会等比例缩放)
- 像素
- 相对于父元素的百分比
- src: 指定图像的 url
- 标题标签:
<h1></h1>
有 1 - 6 级标题 - 水平线标签:
<hr>
<!-- 文档类型为 HTML --> <!DOCTYPE html> <html lang="en"> <head> <!-- 字符集为 UTF-8 --> <meta charset="UTF-8"> <!-- 设置浏览器兼容性 --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>焦点访谈: 中国底气 新思想夯实大国粮仓</title> </head> <body> <img src="https://i2.sinaimg.cn/dy/deco/2012/0613/yocc20120613img01/news_logo.png"> 新浪政务 > 正文 <h1>焦点访谈: 中国底气 新思想夯实大国粮仓</h1> <hr> 2023年03月02日 21:50 央视网 <hr> </body> </html>
样式1
-
CSS 引入方式:
- 行内样式: 写在标签的 style 属性中 (不推荐)
<h1 style="xxx: xxx; xxx: xxx;">中国新闻网</h1> <!-- 属性名: 属性值; --> - 内嵌样式: 写在 style 标签中 (可以写在页面任何位置, 但通常约定写在 head 标签中)
<!-- 对所有 h1 有效 --> <style> h1 { xxx: xxx; xxx: xxx; } </style> - 外嵌样式: 写在单独的 .css 文件中 (需要通过 link 标签在网页中引入)
<link rel="stylesheet" href="css/news.css"> -
颜色表现形式:
- 关键字: 预定义的颜色名
red, green, blue ...
- rgb 表示法: 红绿蓝三原色, 每项取值范围: 0~255
rgb(0, 0, 0), rgb(255, 0, 0)
- 十六进制表示法:
#
开头, 将数字转换成十六进制表示
#000000, #ff0000
- 关键字: 预定义的颜色名
样式2
- CSS 选择器: 用来选取需要设置样式的元素 (标签)
- 元素选择器
h1 { color: red; } <h1>Hello CSS</h1> - id 选择器
#hid { color: red; } <h1 id="hid">CSS id Selector</h1> - 类选择器
.cls { color: red; } <h1 class="cls">CSS class Selector</h1> - 优先级: id 先于类, 先于元素
超链接
- 标签
<a href="..." target="...">央视网</a>
-
属性
- href: 指定资源访问的 url
- target: 指定在何处打开资源链接
- _self: 默认值, 在当前页面打开
- _blank: 在空白页面打开
-
默认字体蓝色有下划线, 改为黑色无下划线
a { color: black; text-decoration: none; /* 设置文本为一个标准的文本 */ }
正文
排版
-
视频标签:
<video>
- src: 规定视频的 url
- controls: 显示播放控件
- width: 播放器的宽度
- height: 播放器的高度
-
音频标签:
<audio>
- src: 规定音频的 url
- controls: 显示播放控件
-
段落标签:
<p>
-
文本加粗标签:
<b> / <strong>
-
空格占位符:
<style> h1 { color: #4D4F53; } #time { color: #968D92; font-size: 13px; } a { color: black; text-decoration: none; } p { /* 设置首行缩进 */ text-indent: 35px; /* 设置行高 */ line-height: 40px; } #plast { text-align: right; } </style>
<!-- 正文 --> <!-- 视频 --> <video src="video/20250206-0746-52.8251230.mp4" controls width="950px"></video> <!-- 音频 --> <audio src="audio/1.mp3" controls></audio> <p> This is the <b>hard</b> version of the problem. The difference between the versions is that in this version you need to output all the operations that need to be performed. You can hack only if you solved all versions of this problem. </p> <p> In other words, you can insert an element at the beginning of any array, after which all elements in this and all following arrays are shifted by one to the right. The last element of the last array is removed. </p> <img src="img/image.png" width="950px"> <p> For each test case, output a single integer — the minimum number of operations that need to be performed. </p> <p id="plast"> 编写者: wxgmjfhy </p>
布局
-
盒子: 页面中所有的元素 (标签), 都可以看做是一个盒子, 由盒子把页面中的元素包含在一个矩形区域内, 通过盒子的视角更方便的进行页面布局
-
盒子模型组成: 内容区域 (content), 内边距区域 (padding), 边框区域 (border), 外边框区域 (margin)
-
布局标签
div
- 一行只显示一个 (独占一行)
- 宽度默认是父元素的宽度, 高度默认由内容撑开
- 可设置宽高
span
- 一行可以显示多个
- 宽度和高度默认由内容撑开
- 不可以设置宽高
<head> ... <style> /* 版心居中 */ #center { width: 65%; /* 上 右 下 左 (顺时针) */ margin: 0% 17.5% 0% 17.5%; /* 简化写法: 0 表示上下为 0, auto 表示自动计算左右并平均分配 */ margin: 0 auto; } </style> </head> <body> <div id="center"> ... </div> </body>
表格
-
<table></table>
: 定义表格整体, 可以包裹多个<tr></tr>
- border: 规定表格边框的宽度
- width: 规定表格的宽度
- cellspacing: 规定单元之间的空间
-
<tr></tr>
: 表格的行, 可以包裹多个<td></td>
-
<td></td>
: 表格单元格 (普通), 可以包裹内容- 如果是表头单元格, 可以替换为
<th></th>
- 如果是表头单元格, 可以替换为
表单
-
<form></form>
-
表单项
<input></input>
: 定义表单项, 通过 type 属性控制输入形式<select></select>
: 定义下拉列表<textarea></textarea>
: 定义文本域
-
属性
- action: 规定当前提交表单时向何处发送表单数据, URL
- method: 规定用于发送表单数据的方式, GET, POST
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- - action: 如果不指定, 默认提交到当前页面 - method: - 默认 get: 在 url 后面拼接表单数据, 比如 ?username=Tom&age=12, 大小有限制 - 设为 post: 在消息体 (请求体) 中传递的, 参数大小无限制 - 表单项必须有 name 属性才可以提交 --> <form action="" method="get"> 用户名: <input type="text" name="username"> 年龄: <input type="text" name="age"> <input type="submit" value="提交"> </form> </body> </html>
JavaScript
一门跨平台, 面向对象的脚本语言 (脚本语言不需要编译, 直接经过浏览器解释即可), 用于控制网页行为, 使网页可以交互
引入方式
-
内部脚本: 将 JS 代码定义在 HTML 页面中
- JS 代码必须在
<script></script>
之间 - 在 HTML 中, 可以在任意位置放置任意数量的
<script></script>
- 一般会把脚本放在
<body></body>
底部, 可以改善显示速度
- JS 代码必须在
-
外部脚本: 引入 JS 文件
- 外部 JS 文件中, 只包含 JS 代码, 不包含
<script></script>
标签 <script></script>
标签不能自闭合
- 外部 JS 文件中, 只包含 JS 代码, 不包含
<!-- 内部 --> <script> alert("Hello JS"); </script> <!-- 外部 --> <script src="js/demo.js"></script>
基础语法
-
书写语法
- 区分大小写
- 每行结尾的分号可有可无, 建议写
- 注释
- 单行 //
- 多行 /* */
- 大括号表示代码块
-
输出语句
- 写入警告框
window.alert(); // 浏览器弹出警告框 - 写入 HTML 输出
document.write() // 写入 HTML, 在浏览器展示 - 写入浏览器控制台
console.log(); // 写入浏览器控制台 -
变量
- 用
var
关键字声明变量 - JS 是弱类型语言, 变量可以存放不同类型的值
- 变量名规则
- 组成字符可以是字母, 数字, 下划线, 或 $
- 数字不能开头
- 建议使用驼峰命名
- 注意
var
定义的变量作用域比较大, 全局变量
{ var x = 1; } alert(x); - 可以重复定义
{ var x = 1; var x = "A"; } - ECMAScript 6 新增了
let
关键字定义变量, 声明的变量只在所在的代码块内有效, 且不允许重复声明 - ECMAScript 6 新增了
const
关键字来声明常量
- 用
-
数据类型: 原始类型 和 引用类型
- 原始类型
- number 数字 (整数, 小数, NaN)
- string 字符串, 单双引号皆可
- boolean 布尔, true, false
- null 对象为空
- undefined 声明的变量未初始化时变量的默认值
- typeof 运算符获取数据类型
alert(typeof 3); // number alert(typeof 'A'); // string alert(typeof true); // boolean alert(typeof null); // object (null 为对象的占位符) var a; alert(typeof a); // undefined - 原始类型
-
运算符
- 基本同 Java
==
和===
==
会进行类型转换, 再比较
var a = 10; alert(a == "10"); // true ===
不会进行类型转换
var a = 10; alert(a === "10"); // false alert(a === 10); // true
-
类型转换
- 字符串 -> 数字:
parseInt
将字符串字面值转为数字, 如果字面值不是数字, 转为 NaN
alert(parseInt("12")); // 12 alert(parseInt("12A45")); // 12 alert(parseInt("A45")); // NaN // 找到一个不是数字的, 后面的就不转了 - 其他类型 -> boolean:
- number: 0 和 NaN 为 false, 其余 true
- string: 空字符串为 false, 其余 true
- null 和 undefined: 均为 false
- 字符串 -> 数字:
-
流程控制语句: 基本同 Java
函数
- 定义方式一
function functionName(参数1, 参数2...) { } // 形参不需要类型 // 返回值不需要定义类型, 可以在函数内部直接使用 return 返回即可 function add(a, b) { return a + b; } // 调用 var result = add(1, 2); alert(result);
- 定义方式二
var functionName = function(参数1, 参数2...) { } // e.g. var add = function(a, b) { return a + b; }
- 可以传递任意个数的参数, 但只接受形参的个数个
var res = add(10, 20, 30, 40, 50); alert(res); // 30
对象
Array
用于定义数组
var arr = new Array(1, 2, 3, 4); // 方式一 var arr = [1, 2, 3, 4]; // 方式二 arr[10] = 'hello'; // 访问
长度可变, 类型可变
var arr = [1, 2, 3, 4]; arr[10] = 'hello';
- 属性
- length
for (let i = 0; i < arr.length; i++) { console.log(arr[i]); } - 方法
- forEach() 遍历数组中每个有值的元素, 并调用一次传入的函数
arr.forEach(function(e) { console.log(e); }); // 箭头函数简化 arr.forEach((e) => { console.log(e); }); - push() 添加元素到数组末尾, 并返回新的长度
arr.push(7, 8, 9); - splice() 删除元素
arr.splice(2, 2); // pos, len
String
var str = new String("Hello"); // 方式一 var str = "Hello"; // 方式二
-
属性
- length
-
方法
- charAt() 返回指定位置的字符
- indexOf() 检索字符串
var str = "Hello World"; console.log(str.indexOf("lo")); // 3 - trim() 去除字符串两边的空格
- substring() 提取字符串两个指定索引之间的子串 (含头不含尾)
console.log(s.substring(0, 5)); // Hello
JSON
- JS 中自定义对象
var user = { name: "Tom", age: 20, gender: "male", eat: function() { alert("吃"); } }; console.log(user.name); user.eat();
JSON 指通过 JavaScript 对象标记法书写的文本
{ "name": "Tom", "age": 20, "gender": "male" }
由于其语法简单, 层次结构鲜明, 现多用于作为数据载体, 在网络中进行数据传输
var user = '{"name": "Tom", "age": 18, "addr": ["北京", "上海", "西安"]}'; // JSON 字符串 alert(user.name); // undefined var jsObject = JSON.parse(user); // JSON 字符串 -> JS 对象 alert(jsObject.name); // Tom var jsonStr = JSON.stringify(jsObject); // JS 对象 -> JSON 字符串
BOM
浏览器对象模型, 允许 JS 与浏览器对话, JS 将浏览器的各个组成部分封装为对象
-
组成
- Window 浏览器窗口对象
- Navigator 浏览器对象
- Screen 屏幕对象
- History 历史记录对象
- Location 地址栏对象
-
Window
-
属性
- history: 对 History 对象的只读引用
- location: 用于窗口或框架的 Location 对象
- navigator: 对 Navigator 对象的只读引用
-
方法
- alert(): 显示带有一段消息和一个确认按钮的警告框
- confirm(): 显示带有一段消息以及确认按钮和取消按钮的对话框
- setInterval(): 按照指定的周期 (以毫秒计) 一直调用函数或计算表达式
- setTimeout(): 在指定的毫秒数后调用一次函数或计算表达式
-
window.alert("Hello"); // window 可省略 var flag = confirm("您确定删除吗?"); // 确认 true, 取消 false var i = 0; setInterval(function() { i++; console.log("定时器执行了" + i + "次") }, 2000); setTimeout(function() { alert("JS"); }, 3000);
- Location
alert(location.href); location.href = "https://www.itcast.cn";
DOM
文档对象模型, 将标记语言的各个组成部分封装为对应的对象:
- Document: 整个文档对象
- Element: 元素对象
- Attribute: 属性对象
- Text: 文本对象
- Comment: 注释对象
JS 通过 DOM, 能够对 HTML 进行操作:
- 改变 HTML 元素的内容
- 改变 HTML 元素的样式 (CSS)
- 对 HTML DOM 事件作出反应
- 添加和删除 HTML 元素
访问 HTML 和 XML 文档的标准, 分为:
- Core DOM - 所有文档类型的标准模型
- Document: 整个文档对象
- Element: 元素对象
- Attribute: 属性对象
- Text: 文本对象
- Comment: 注释对象
- XML DOM - XML 文档的标准模型
- HTML DOM - HTML 文档的标准模型
- image:
<img>
- Button:
<input type='button'>
- image:
- 获取 Element
- 根据 id 属性值获取, 返回单个 Element 对象
var h1 = document.getElementById('h1'); - 根据标签名称获取, 返回 Element 对象数组
var divs = document.getElementsByTagName('div'); - 根据 name 属性值获取, 返回 Element 对象数组
var hobbies = document.getElementsByName('hobby'); - 根据 class 属性值获取, 返回 Element 对象数组
var clss = document.getElementsByClassName('cls'); - e.g.
var divs = document.getElementsByClassName('cls'); var div1 = divs[0]; div1.innerHTML = "xxx"; // 更改文本内容
- e.g.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <img id="h1" src="img/image1.png" width="40%"> <br><br> <div class="cls">哈哈</div> <br> <div class="cls">哈哈哈</div> <br> <input type="checkbox" name="hobby"> 电影 <input type="checkbox" name="hobby"> 旅游 <input type="checkbox" name="hobby"> 游戏 </body> <script> var img = document.getElementById('h1'); img.src = "img/image2.png"; var divs = document.getElementsByTagName('div'); for (let i = 0; i < divs.length; i++) { const div = divs[i]; div.innerHTML += "<font color='red'>good</font>"; } var ins = document.getElementsByName('hobby'); for (let i = 0; i < ins.length; i++) { const check = ins[i]; check.checked = true; } </script> </html>
事件监听
事件: HTML 事件是发生在 HTML 元素上的"事情", 比如:
- 按钮被点击
- 鼠标移动到元素上
- 按下键盘按键
事件监听: JS 可以在事件被侦测到时执行代码
事件绑定
- 方式一: 通过 HTML 标签中的事件属性进行绑定
<input type="button" onclick="on()" value="按钮1"> <script> function on() { alert("被点击了"); } </script>
- 方式二: 通过 DOM 元素属性绑定
<input type="button" id="btn" value="按钮2"> <script> document.getElementById('btn').onclick = function() { alert("被点击了"); } </script>
常见事件
- onclick 鼠标单击事件
- onblur 元素失去焦点
- onfocus 元素获得焦点
- onload 某个页面或图像被完成加载
- onsubmit 当表单提交时触发该事件
- onkeydown 某个键盘的键被按下
- onmouseover 鼠标被移到某个元素之上
- onmouseout 鼠标从某个元素移开
案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <img id="h1" src="img/image1.png" width="40%"> <br> <input type="button" onclick="turnOn()" value="点亮"> <input type="button" onclick="turnOff()" value="熄灭"> <br><br> <input type="text" id="name" onblur="upper()" onfocus="lower()" value="NAME"> <br><br> <input type="checkbox" name="hobby"> 电影 <input type="checkbox" name="hobby"> 旅游 <input type="checkbox" name="hobby"> 游戏 <br> <input type="button" onclick="selectAll()" value="全选"> <input type="button" onclick="selectNone()" value="清空"> </body> <script> function turnOn() { var img = document.getElementById('h1'); img.src = "img/image2.png"; } function turnOff() { var img = document.getElementById('h1'); img.src = "img/image1.png"; } function lower() { var input = document.getElementById('name'); input.value = input.value.toLowerCase(); } function upper() { var input = document.getElementById('name'); input.value = input.value.toUpperCase(); } function selectAll() { var hobbies = document.getElementsByName('hobby'); for (let i = 0; i < hobbies.length; i++) { const hobby = hobbies[i]; hobby.checked = true; } } function selectNone() { var hobbies = document.getElementsByName('hobby'); for (let i = 0; i < hobbies.length; i++) { const hobby = hobbies[i]; hobby.checked = false; } } </script> </html>
模块化
复杂的项目需要一种将 JavaScript 程序拆分为可按需导入 (import) 的单独模块的机制
如果用到了模块化的 JS, 需要在 HTML 中加上 type="module"
<script type="module"> </script>
Vue
- 一套前端框架, 免除原生 JS 中的 DOM 操作, 简化书写
- 框架: 一个半成品软件, 一套可重用的, 通用的软件基础代码模型, 基于框架进行开发更加快捷高效
- 基于 MVVM (Model-View-ViewModel) 思想, 实现数据的双向绑定, 将编程的关注点放在数据上
- Model 数据模型, 包含数据和数据的处理方法
- View 视图层, 负责数据的展示
- ViewModel 是 View 和 Model 之间的桥梁, Model 中数据变化会更新 View 中展示, View 中数据变化也会更新 Model 中数据, 即双向数据绑定
- 官网
使用
使用ES 模块构建版本 vue.esm-browser.js
(专门为在浏览器环境中使用 ES 模块而构建的 Vue 版本), 通过 CDN (内容分发网络) 使用 Vue
<div id="app"> <h1>{{message}}</h1> <h1>{{count}}</h1> </div> <script type="module"> import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; createApp({ data() { return { message: 'Hello Vue', count: 100 }; } }).mount('#app'); </script>
使用步骤:
-
准备工作
- 从 Vue 引入 createApp 函数
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; - 调用 createApp 函数创建 Vue 应用实例, 这个实例代表了整个 Vue 应用
- 调用时需要传入一个选项对象作为参数, 这个选项对象可以包含多个属性, 如 data, methods
mount('#app')
表示将创建好的 Vue 应用挂载到 id 为 app 的 DOM 元素上, 这样 Vue 应用就能控制该元素及其子元素的渲染和交互了
createApp({ // 选项对象内容 }).mount('#app'); - 定义 DOM 元素, 交给 Vue 控制
<div id="app"> </div> -
数据驱动视图
- 定义属性, 准备数据
createApp({ data() { return { message: 'Hello Vue', count: 100 }; // 返回一个 JS 对象, 这个对象中定义的属性就是 Vue 应用的数据 } }).mount('#app'); - 用插值表达式渲染
<div id="app"> <h1>{{message}}</h1> <h1>{{count}}</h1> </div>
常见指令
<p v-xxx="...">...</p>
v-for
列表渲染, 遍历容器的元素或者对象的属性
<tr v-for="(item, index) in items" :key="item.id">{{item}}</tr>
- items 遍历的数组 (遍历的数组必须在 data 中定义), item 遍历的元素; index 为索引/下标, 从 0 开始, 可省略为
v-for="item in items"
- key 给元素添加的唯一标识, 便于 Vue 进行列表项的正确排序复用, 提高渲染性能; 推荐使用 id 作为 key (唯一), 不推荐使用 index
<body> <div id="container"> ... <!-- 表格 --> <table> <!-- 表头 --> <thead> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>头像</th> <th>职位</th> <th>入职时间</th> <th>最后操作时间</th> <th>操作</th> </tr> </thead> <!-- 表格主体内容 --> <tbody> <tr v-for="(e, index) in empList" :key="e.id"> <td>{{index + 1}}</td> <td>{{e.name}}</td> <td>{{e.gender == 1? '男' : '女'}}</td> <!-- 插值表达式不能出现在标签内部, 下面是错误的用法 --> <td><img class="avatar" src="{{e.image}}" alt="{{e.name}}"></td> <td>{{e.job}}</td> <td>{{e.entrydate}}</td> <td>{{e.updatetime}}</td> <td class="action-button"> <button type="button">编辑</button> <button type="button">删除</button> </td> </tr> </tbody> </table> ... </div> <script type="module"> import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; createApp({ data() { return { empList: [ { "id": 1, "name": "张三", "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg", "gender": 1, "job": "1", "entrydate": "2023-06-09", "updatetime": "2024-09-30T14:59:38" }, { "id": 2, "name": "李四", "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg", "gender": 1, "job": "1", "entrydate": "2023-05-09", "updatetime": "2024-09-01T00:00:00" }, { "id": 3, "name": "王五", "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg", "gender": 2, "job": "2", "entrydate": "2023-07-09", "updatetime": "2024-09-02T11:11:11" } ] }; } }).mount('#container'); </script> </body>
v-bind
为 HTML 标签绑定属性值, 如设置 href, css 样式等
<img v-bind:src="item.image" width="30px"> <img :src="item.image" width="30px">
v-if & v-show
- v-if/v-else-if/v-else: 条件性的渲染某元素, 判定为 true 时渲染
- v-show: 根据条件展示某元素, 区别在于切换的是 display 属性的值
v-if
<span v-if="gender == 1">男生</span> <span v-else-if="gender == 2">女生</span> <span v-else>未知</span>
- true 创建元素并显示, false 移除/不创建
- 场景: 要么显示, 要么不显示, 不频繁切换的场景
<td> <span v-if="e.job == 1">班主任</span> <span v-else-if="e.job == 2">讲师</span> <span v-else>其他</span> </td>
v-show
<span v-show="gender == 1">男生</span>
- 基于 CSS 样式 display 来控制显示与隐藏
- 场景: 频繁切换显示隐藏的场景
<td> <span v-show="e.job == 1">班主任</span> <span v-show="e.job == 2">讲师</span> <span v-show="e.job == 3">其他</span> </td>
v-model
在表单元素上创建双向数据绑定, 可以方便的获取或设置表单项数据
- 定义数据模型, 采集员工搜集表单数据
createApp({ data() { return { searchForm: { // 封装用户输入的查询条件 name: '', gender: '', job: '' } }; } }).mount('#container');
- 绑定
<input type="text" id="name" v-model="searchForm.name">
v-on
为 HTML 标签绑定事件 (添加事件监听)
<div id="app"> <button type="button" v-on:click="handle">点击</button> <!-- 简写为 --> <button type="button" @click="handle">点击</button> </div>
handle 为我们定义的方法
const app = createApp({ data() { // ... }, methods: { handle() { // ... } }, }).mount("#app");
管理系统 e.g.
(样式由豆包生成)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>管理系统</title> <style> /* 全局样式 */ body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 0; background-color: #f4f4f9; } /* 容器样式 */ #container { max-width: 1200px; margin: 0 auto; padding: 20px; background-color: #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); border-radius: 8px; min-height: 100vh; display: flex; flex-direction: column; } /* 导航栏样式 */ .navbar { display: flex; justify-content: space-between; align-items: center; background-color: #333; color: white; padding: 15px 20px; border-radius: 8px 8px 0 0; } .navbar h1 { margin: 0; font-size: 24px; } .navbar a { color: white; text-decoration: none; transition: color 0.3s ease; } .navbar a:hover { color: #ffc107; } /* 搜索框样式 */ .search-form { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; background-color: #f8f9fa; padding: 10px; border-radius: 8px; margin-top: 20px; } .search-form label { flex: 0 0 auto; font-weight: bold; margin-right: 5px; } .search-form input[type="text"], .search-form select { flex: 1 1 auto; padding: 5px; border: 1px solid #ccc; border-radius: 3px; } .search-form input[type="text"]:focus, .search-form select:focus { border-color: #007BFF; outline: none; box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); } .search-form button[type="button"] { padding: 5px 10px; background-color: #007BFF; color: white; border: none; border-radius: 3px; cursor: pointer; transition: background-color 0.3s ease, box - shadow 0.3s ease; } .search-form button[type="button"]:hover { background-color: #0056b3; box-shadow: 0 0 5px rgba(0, 86, 179, 0.5); } .search-form button[type="button"]:nth-of-type(2) { background-color: #6c757d; } .search-form button[type="button"]:nth-of-type(2):hover { background-color: #5a6268; box-shadow: 0 0 5px rgba(90, 98, 104, 0.5); } /* 表格样式 */ table { width: 100%; border-collapse: collapse; margin-top: 20px; } th, td { padding: 15px 20px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #f8f9fa; font-weight: 600; position: relative; transition: background-color 0.3s ease; } th:hover { background-color: #e9ecef; } tr:hover { background-color: #f1f1f1; } /* 头像样式 */ .avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; } /* 操作按钮样式 */ .action-button button { padding: 8px 12px; margin-right: 5px; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s ease, box - shadow 0.3s ease; } .action-button button:nth-child(1) { background-color: #007bff; color: white; } .action-button button:nth-child(1):hover { background-color: #0056b3; box-shadow: 0 0 5px rgba(0, 86, 179, 0.5); } .action-button button:nth-child(2) { background-color: #dc3545; color: white; } .action-button button:nth-child(2):hover { background-color: #bd2130; box-shadow: 0 0 5px rgba(189, 33, 48, 0.5); } /* 页脚样式 */ .footer { margin-top: auto; padding: 20px; text-align: center; background-color: #333; color: white; border-radius: 0 0 8px 8px; } .footer p { margin: 5px 0; transition: opacity 0.3s ease; } .footer p:hover { opacity: 0.8; } </style> </head> <body> <div id="container"> <!-- 顶部导航栏 --> <div class="navbar"> <h1>管理系统</h1> <a href="#">退出登录</a> </div> <!-- 搜索框 --> <form class="search-form"> <label for="name">姓名:</label> <input type="text" id="name" name="name" v-model="searchForm.name" placeholder="请输入姓名"> <label for="gender">性别:</label> <select id="gender" name="gender" v-model="searchForm.gender"> <option value=""></option> <option value=1>男</option> <option value=2>女</option> </select> <label for="position">职位:</label> <select id="position" name="position" v-model="searchForm.job"> <option value=""></option> <option value="1">班主任</option> <option value="2">讲师</option> <option value="3">其他</option> </select> <button type="button" @click="search">查询</button> <button type="button" @click="clear">清空</button> </form> <!-- 表格 --> <table> <!-- 表头 --> <thead> <tr> <th>序号</th> <th>姓名</th> <th>性别</th> <th>头像</th> <th>职位</th> <th>入职时间</th> <th>最后操作时间</th> <th>操作</th> </tr> </thead> <!-- 表格主体内容 --> <tbody> <tr v-for="(e, index) in empList" :key="e.id"> <td>{{index + 1}}</td> <td>{{e.name}}</td> <td>{{e.gender == 1? '男' : '女'}}</td> <td><img class="avatar" v-bind:src="e.image" v-bind:alt="e.name"></td> <td> <span v-if="e.job == 1">班主任</span> <span v-else-if="e.job == 2">讲师</span> <span v-else>其他</span> </td> <td>{{e.entrydate}}</td> <td>{{e.updatetime}}</td> <td class="action-button"> <button type="button">编辑</button> <button type="button">删除</button> </td> </tr> </tbody> </table> <!-- 页脚版权区域 --> <footer class="footer"> <p>xxx公司</p> <p>版权所有 Copyright 2006-2024 All Rights Reserved</p> </footer> </div> <script type="module"> import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; createApp({ data() { return { searchForm: { // 封装用户输入的查询条件 name: '', gender: '', job: '' }, empList: [ { "id": 1, "name": "张三", "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg", "gender": 1, "job": "1", "entrydate": "2023-06-09", "updatetime": "2024-09-30T14:59:38" }, { "id": 2, "name": "李四", "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg", "gender": 1, "job": "1", "entrydate": "2023-05-09", "updatetime": "2024-09-01T00:00:00" }, { "id": 3, "name": "王五", "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg", "gender": 2, "job": "2", "entrydate": "2023-07-09", "updatetime": "2024-09-02T11:11:11" } ] }; }, methods: { search() { // (当前) 将搜索条件, 输出到控制台 console.log(this.searchForm); }, clear() { // 清空表单项数据 this.searchForm = { name: '', gender: '', job: '' }; } } }).mount('#container'); </script> </body> </html>
Ajax
作用:
- 数据交换: 通过 Ajax 可以给服务器发送请求, 并获取服务器响应的数据
- 异步交互: 可以在不重新加载整个页面的情况下, 与服务器交换数据并更新部分网页的计数, 如: 搜索联想, 用户名是否可用的校验等等
- 同步: 客户端发出请求后等待服务端处理并响应
- 异步: 客户端发出请求后可以执行其他操作
Axios: 对原生 Ajax 进行了封装, 简化书写, 快速开发
步骤:
-
引入 Axios 的 js 文件
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> -
使用 Axios 发送请求, 并获取响应结果
axios({ method: 'GET', url: 'https://web-server.itheima.net/emps/list' }).then((result) => { console.log(result.data); }).catch((err) => { alert(err); }); - method: 请求方式, GET/POST
- url: 请求路径
- data: 请求数据 (POST) (请求体/消息体中的内容)
- params: 发送请求时携带的 url 参数, 如: ...?key=val
-
e.g.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="button" value="获取数据 GET" id="btnGet"> <input type="button" value="获取数据 POST" id="btnPost"> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> document.querySelector('#btnGet').addEventListener('click', () => { axios({ url: 'https://mock.apifox.cn/m1/3083103-0-default/emps/list', method: 'GET' }).then((result) => { console.log(result.data); }).catch((err) => { console.log(err); }); }) document.querySelector('#btnPost').addEventListener('click', () => { axios({ url: 'https://mock.apifox.cn/m1/3083103-0-default/emps/update', method: 'POST', data: 'id-1' // POST 请求方式, 请求体 }).then((result) => { console.log(result.data); }).catch((err) => { console.log(err); }); }) </script> </script> </body> </html>
- 简化
axios.请求方式(url [, data [, config]]);
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> document.querySelector('#btnGet').addEventListener('click', () => { axios.get('https://mock.apifox.cn/m1/3083103-0-default/emps/list').then((result) => { console.log(result.data); }).catch((err) => { console.log(err); }) }) document.querySelector('#btnPost').addEventListener('click', () => { axios.post('https://mock.apifox.cn/m1/3083103-0-default/emps/update', 'id=1').then((result) => { console.log(result.data); }).catch((err) => { console.log(err); }) }) </script> </script>
-
async & await 可以让异步变为同步操作
- async 声明异步方法
- await 等待异步任务执行
methods: { async search() { let result = await axios.get('xxx'); this.employees = result.data.data; } } - await 只在 async 函数内有效, await 取代 then 函数, 等待获取到请求成功的结果值
-
如何在页面加载完毕自动发起请求, 请求服务端?
- Vue 生命周期: 八个阶段, 每触发一个生命周期事件, 会自动执行一个生命周期方法 (钩子)
- beforeCreate 创建前
- created 创建后
- beforeMount 载入前
- mounted 挂载完毕
- beforeUpdate 数据更新前
- updated 数据更新后
- beforeUnmount 组件销毁前
- unmounted 组件销毁后
- 可以在 mounted 中发出请求
- Vue 生命周期: 八个阶段, 每触发一个生命周期事件, 会自动执行一个生命周期方法 (钩子)
-
管理系统 e.g.
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script type="module"> import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; createApp({ data() { return { searchForm: { // 封装用户输入的查询条件 name: '', gender: '', job: '' }, empList: [] }; }, methods: { async search() { // 发送 ajax 请求 let result = await axios.get(`https://web-server.itheima.net/emps/list?name=${this.searchForm.name}&gender=${this.searchForm.gender}&job=${this.searchForm.job}`); // 注意是 `` 而不是 '' this.empList = result.data.data; // result.data 是整个 JSON 格式的数据, 内部有一个 data 属性的数组 }, clear() { // 清空表单项数据 this.searchForm = { name: '', gender: '', job: '' }; this.search(); } }, // 钩子函数 mounted() { this.search(); } }).mount('#container'); </script>
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步