# JavaWeb

## JavaWeb学习路线

![image-20240227162313041](https://pic.bitday.top/i/2025/03/19/u6kvx7-2.png)

## 前后端分离开发

![image-20240229125233265](https://pic.bitday.top/i/2025/03/19/u6m408-2.png)



![image-20240229125254635](https://pic.bitday.top/i/2025/03/19/u6kpkw-2.png)

1. 需求分析：首先我们需要阅读需求文档，分析需求，理解需求。
2. 接口定义：查询接口文档中关于需求的接口的定义，包括地址，参数，响应数据类型等等
3. 前后台并行开发：各自按照接口文档进行开发，实现需求
4. 测试：前后台开发完了，各自按照接口文档进行测试
5. 前后段联调测试：前段工程请求后端工程，测试功能

## Html/CSS

### 标签速记：

不闭合标签:<!--<br> <img> <input> <meta> <hr>-->

 空格占位符：<!--&nbsp;-->

正文格式：line-height:设置行高；text-indent:设置首行缩进；text-align:规定文本的水平对齐方式

### CSS引入方式

| 名称     | 语法描述                                          | 示例                                           |
| -------- | ------------------------------------------------- | ---------------------------------------------- |
| 行内样式 | 在标签内使用style属性，属性值是css属性键值对      | &lt;h1 style="xxx:xxx;">中国新闻网&lt;/h1>     |
| 内嵌样式 | 定义&lt;style&gt;标签，在标签内部定义css样式      | &lt;style> h1 {...} &lt;/style>                |
| 外联样式 | 定义&lt;link&gt;标签，通过href属性引入外部css文件 | &lt;link rel="stylesheet" href="css/news.css"> |

### CSS选择器

**1.元素（标签）选择器：** 

- 选择器的名字必须是标签的名字
- 作用：选择器中的样式会作用于所有同名的标签上

~~~
元素名称 {
    css样式名:css样式值；
}
~~~

例子如下：

~~~css
 div{
     color: red;
 }
~~~

**2.id选择器:**

- 选择器的名字前面需要加上#
- 作用：选择器中的样式会作用于指定id的标签上，而且**有且只有一个**标签（由于id是唯一的）

~~~
#id属性值 {
    css样式名:css样式值；
}
~~~

例子如下：

~~~css
#did {
    color: blue;
}
~~~

**3.类选择器：**

- 选择器的名字前面需要加上 .
- 作用：选择器中的样式会作用于所有class的属性值和该名字一样的标签上，可以是多个

~~~
.class属性值 {
    css样式名:css样式值；
}
~~~

例子如下：

~~~css
.cls{
     color: green;
 }
~~~

这里使用了第二种CSS引入方式，内嵌样式，<style>包裹，里面用了三种CSS选择器

```text
<!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>焦点访谈：中国底气 新思想夯实大国粮仓</title>
    <style>
        h1 {
            color: #4D4F53;
        }

        /* 元素选择器 */
        /* span {
            color: red;
        } */

        /* 类选择器 */
        /* .cls {
            color: green;
        } */
        
        /* ID选择器 */
        #time {
            color: #968D92;
            font-size: 13px; /* 设置字体大小 */
        }

    </style>
</head>
<body>

    <img src="img/news_logo.png"> 新浪政务 > 正文

    <h1>焦点访谈：中国底气 新思想夯实大国粮仓</h1>

    <hr>
    <span class="cls" id="time">2023年03月02日 21:50</span>  <span class="cls">央视网</span>
    <hr>

</body>
</html>
```

### 页面布局

盒子模型，盒子部分指的是border及以内的部分，不包括margin

![image-20240228095942357](https://pic.bitday.top/i/2025/03/19/u6lpxd-2.png)

![image-20240228100247314](https://pic.bitday.top/i/2025/03/19/u6lxdu-2.png)



- 布局标签：实际开发网页中，会大量频繁的使用 div 和 span 这两个没有语义的布局标签。

- 标签：<div> <span>

- 特点：

  - div标签：

    - 一行只显示一个（独占一行）

    - 宽度默认是父元素的宽度，高度默认由内容撑开

    - 可以设置宽高（width、height）

  - span标签：

    - 一行可以显示多个

    - 宽度和高度默认由内容撑开

    - 不可以设置宽高（width、height）

box-sizing: border-box，此时指定width height为盒子的高宽，而不是content的高宽

### 表格标签

- table> : 用于定义整个表格, 可以包裹多个 &lt;tr>， 常用属性如下： 
  - border：规定表格边框的宽度
  - width：规定表格的宽度
  - cellspacing: 规定单元之间的空间

- &lt;tr> : 表格的行，可以包裹多个 &lt;td>  
- &lt;td> : 表格单元格(普通)，可以包裹内容 , 如果是表头单元格，可以替换为 &lt;th>  ,th具有加粗居中展示的效果

### 表单标签

- 表单场景: 表单就是在网页中负责数据采集功能的，如：注册、登录的表单。 

- 表单标签: &lt;form>

- 表单属性:

  - action: 规定表单提交时，向何处发送表单数据，表单提交的URL。
  - method: 规定用于发送表单数据的方式，常见为： GET、POST。
    - GET：表单数据是拼接在url后面的， 如： xxxxxxxxxxx?username=Tom&age=12，url中能携带的表单数据大小是有限制的。
    - POST： 表单数据是在请求体（消息体）中携带的，大小没有限制。

- 表单项标签: 不同类型的input元素、下拉列表、文本域等。

  - input: 定义表单项，通过type属性控制输入形式

  | type取值                 | **描述**                             |
  | ------------------------ | ------------------------------------ |
  | text                     | 默认值，定义单行的输入字段           |
  | password                 | 定义密码字段                         |
  | radio                    | 定义单选按钮                         |
  | checkbox                 | 定义复选框                           |
  | file                     | 定义文件上传按钮                     |
  | date/time/datetime-local | 定义日期/时间/日期时间               |
  | number                   | 定义数字输入框                       |
  | email                    | 定义邮件输入框                       |
  | hidden                   | 定义隐藏域                           |
  | submit / reset / button  | 定义提交按钮 / 重置按钮 / 可点击按钮 |

  - select: 定义下拉列表
  - textarea: 定义文本域



```text
<!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>HTML-表单项标签</title>
</head>
<body>

<!-- value: 表单项提交的值 -->
<form action="" method="post">
     姓名: <input type="text" name="name"> <br><br>
     密码: <input type="password" name="password"> <br><br> 
     性别: <input type="radio" name="gender" value="1"> 男
          <label><input type="radio" name="gender" value="2"> 女 </label> <br><br>
     爱好: <label><input type="checkbox" name="hobby" value="java"> java </label>
          <label><input type="checkbox" name="hobby" value="game"> game </label>
          <label><input type="checkbox" name="hobby" value="sing"> sing </label> <br><br>
     图像: <input type="file" name="image">  <br><br>
     生日: <input type="date" name="birthday"> <br><br>
     时间: <input type="time" name="time"> <br><br>
     日期时间: <input type="datetime-local" name="datetime"> <br><br>
     邮箱: <input type="email" name="email"> <br><br>
     年龄: <input type="number" name="age"> <br><br>
     学历: <select name="degree">
               <option value="">----------- 请选择 -----------</option>
               <option value="1">大专</option>
               <option value="2">本科</option>
               <option value="3">硕士</option>
               <option value="4">博士</option>
          </select>  <br><br>
     描述: <textarea name="description" cols="30" rows="10"></textarea>  <br><br>
     <input type="hidden" name="id" value="1">
	 	
     <!-- 表单常见按钮 -->
     <input type="button" value="按钮">
     <input type="reset" value="重置"> 
     <input type="submit" value="提交">   
     <br>
</form>

</body>
</html>
```

- `name="gender"`：这个属性定义了单选按钮组的名称，它们被分为同一个组，因此只能选择其中的一个按钮。在这种情况下，所有具有相同 `name` 属性值的单选按钮都被视为同一组。
- `value="1"` 和 `value="2"`：这些是单选按钮的值。当用户选择某个单选按钮时，该单选按钮的值将被提交到服务器。在这种情况下，`value="1"` 表示选择男性，而 `value="2"` 表示选择女性。
- 用户在浏览器中看到的文本内容是 "男" 和 "女"。

<label><input type="radio" name="gender" value="2"> 女 </label>  这里的label意味着用户不仅可以点击单选按钮本身来选择选项，当用户单击 "女" 这个标签文本时，与之关联的单选按钮也会被选中。



## JavaScript

### JS引入方式

**第一种方式：**内部脚本，将JS代码定义在HTML页面中

- JavaScript代码必须位于&lt;script&gt;&lt;/script&gt;标签之间
- 在HTML文档中，可以在任意地方，放置任意数量的&lt;script&gt;
- 一般会把脚本置于&lt;body&gt;元素的底部，可改善显示速度

例子：

~~~html
<script>
    alert("Hello JavaScript")
</script>
~~~

**第二种方式：**外部脚本将， JS代码定义在外部 JS文件中，然后引入到 HTML页面中

- 外部JS文件中，只包含JS代码，不包含<script&gt;标签
- 引入外部js的&lt;script&gt;标签，必须是双标签

例子：

~~~html
<script src="js/demo.js"></script>
~~~

注意：demo.js中只有js代码，没有&lt;script&gt;标签



### JS基础语法

#### 书写语法

- 区分大小写：与 Java 一样，变量名、函数名以及其他一切东西都是区分大小写的

- 每行结尾的分号可有可无

- 大括号表示代码块

- 注释：

  - 单行注释：// 注释内容

  - 多行注释：/* 注释内容 */

输出的三种形式：

| api              | 描述             |
| ---------------- | ---------------- |
| window.alert()   | 警告框           |
| document.write() | 在HTML 输出内容  |
| console.log()    | 写入浏览器控制台 |

#### 变量

| 关键字 | 解释                                                         |
| ------ | ------------------------------------------------------------ |
| var    | 早期ECMAScript5中用于变量声明的关键字                        |
| let    | ECMAScript6中新增的用于变量声明的关键字，相比较var，let只在代码块内生效（大括号） |
| const  | 声明常量的，常量一旦声明，不能修改                           |

var:作用域比较大，全局的；可以重复定义，后面的覆盖前面的

let：局部变量(代码块内生效{})，不可重复定义。

const: const pi=3.14

#### 数据类型和运算符

| 数据类型  | 描述                                               |
| --------- | -------------------------------------------------- |
| number    | 数字（整数、小数、NaN(Not a Number)）              |
| string    | 字符串，单双引皆可                                 |
| boolean   | 布尔。true，false                                  |
| null      | 对象为空                                           |
| undefined | 当声明的变量未初始化时，该变量的默认值是 undefined |

| 运算规则   | 运算符                                                       |
| ---------- | ------------------------------------------------------------ |
| 算术运算符 | + , - , * , / , % , ++ , --                                  |
| 赋值运算符 | = , += , -= , *= , /= , %=                                   |
| 比较运算符 | &gt; , < , >= , <= , != , == , ===   **注意     == 会进行类型转换，=== 不会进行类型转换** |
| 逻辑运算符 | && , \|\| , !                                                |
| 三元运算符 | 条件表达式 ? true_value: false_value                         |

![image-20240228122315690](https://pic.bitday.top/i/2025/03/19/u6lj59-2.png)

parseint()  ,将其他类型转化为数字

#### 函数

第一种：

~~~js
function 函数名(参数1,参数2..){
    要执行的代码
}
~~~

因为JavaScript是**弱数据类型**的语言，所以有如下几点需要注意：

- 形式参数不需要声明类型，并且JavaScript中不管什么类型都是let或者var去声明，加上也没有意义。
- 返回值也不需要声明类型，直接return即可

如下示例：

```text
function add(a, b){
    return a + b;
}
```

var  result=add(10,20)可以接收返回值



第二种可以通过var去定义函数的名字，具体格式如下：

```text
var functionName = function (参数1,参数2..){   
	//要执行的代码
}
```

如下示例：

```text
var add = function(a,b){
        return  a + b;
    }
```

 var result = add(10,20); 函数的调用不变

### JS对象

#### Array对象

方式1：

~~~js
var 变量名 = new Array(元素列表); 
~~~

例如：

~~~js
var arr = new Array(1,2,3,4); //1,2,3,4 是存储在数组中的数据（元素）
~~~

方式2：

~~~js
var 变量名 = [ 元素列表 ]; 
~~~

例如：

~~~js
var arr = [1,2,3,4]; //1,2,3,4 是存储在数组中的数据（元素）
~~~

长度可变=》可以直接arr[10]=100，不会报错

类型可变=》arr[1]="hello"，可以既存数字又存字符串



属性：

| 属性   | 描述                         |
| :----- | :--------------------------- |
| length | 设置或返回数组中元素的数量。 |

方法：

| 方法方法  | 描述                                                 |
| :-------- | :--------------------------------------------------- |
| forEach() | 遍历数组中的每个**有值的**元素，并调用一次传入的函数 |
| push()    | 将新元素添加到数组的**末尾**，并返回新的长度         |
| splice()  | 从数组中删除元素                                     |

普通for循环：会遍历每个数组元素，无论是否有值

```text
var arr = [1,2,3,4];
arr[10] = 50;
	for (let i = 0; i < arr.length; i++) {
	console.log(arr[i]);
}
```

foreach：

```text
arr.forEach(function(e){
     console.log(e);
})
```

在ES6中，引入箭头函数的写法，语法类似java中lambda表达式，修改上述代码如下：

```text
arr.forEach((e) => {
     console.log(e);
}) 
```

push: arr.push(7,8,9)  可以一次添加多个元素

splice: arr.splice（start，cnt），从start开始，删cnt个元素

#### String字符串

String对象也提供了一些常用的属性和方法，如下表格所示：

属性：

| 属性   | 描述           |
| ------ | -------------- |
| length | 字符串的长度。 |

方法：

| 方法        | 描述                                     |
| ----------- | ---------------------------------------- |
| charAt()    | 返回在指定位置的字符。                   |
| indexOf()   | 检索字符串。                             |
| trim()      | 去除字符串两边的空格                     |
| substring() | 提取字符串中两个指定的索引号之间的字符。 |

- length属性：

  length属性可以用于返回字符串的长度，添加如下代码：

  ~~~js
  //length
  console.log(str.length);
  ~~~

- charAt()函数：

  charAt()函数用于返回在指定索引位置的字符，函数的参数就是索引。添加如下代码：

  ~~~js
  console.log(str.charAt(4));
  ~~~

- indexOf()函数

  indexOf()函数用于检索指定内容在字符串中的索引位置的，返回值是索引，参数是指定的内容。添加如下代码：

  ~~~js
  console.log(str.indexOf("lo"));
  ~~~

- trim()函数

  trim()函数用于去除字符串两边的空格的。添加如下代码：

  ~~~js
  var s = str.trim();
  console.log(s.length);
  ~~~

- substring()函数

  substring()函数用于截取字符串的，函数有2个参数。

  参数1：表示从那个索引位置开始截取。包含

  参数2：表示到那个索引位置结束。不包含

  ~~~js
  console.log(s.substring(0,5));
  ~~~



#### JSON对象

##### 自定义对象

```text
var 对象名 = {
    属性名1: 属性值1, 
    属性名2: 属性值2,
    属性名3: 属性值3,
    函数名称: function(形参列表){}
};
```

我们可以通过如下语法调用属性：

~~~js
对象名.属性名
~~~

通过如下语法调用函数：

~~~js
对象名.函数名()
~~~

##### json对象

JSON对象：**J**ava**S**cript **O**bject **N**otation，JavaScript对象标记法。是通过JavaScript标记法书写的文本。其格式如下：

~~~js
{
    "key":value,
    "key":value,
    "key":value
}
~~~

其中，**key必须使用引号并且是双引号标记，value可以是任意数据类型。**

JSON字符串示例：

```text
var jsonstr = '{"name":"Tom", "age":18, "addr":["北京","上海","西安"]}';
alert(jsonstr.name);
```

注意外层的单引号不要忘记！

JSON字符串=》JS对象

```text
var obj = JSON.parse(jsonstr);
```

**对象.属性   就可以获得key对应的值**

JS对象=》JS字符串

```text
var jsonstr=JSON.stringify(obj)
```

##### JSON格式数据

`{"name":"666"}` 是一个 JSON 对象，`[{"name":"666"},{"name":"li"}]` 是一个 JSON 数组，它们都是 JSON 格式的数据。

#### BOM对象

重点学习的是Window对象、Location（地址栏）对象

##### window对象

常用方法：通过可简写，window.alert()->alert()

| 函数          | 描述                                               |
| ------------- | -------------------------------------------------- |
| alert()       | 显示带有一段消息和一个确认按钮的警告框。           |
| comfirm()     | 显示带有一段消息以及确认按钮和取消按钮的对话框。   |
| setInterval() | 按照指定的周期（以毫秒计）来调用函数或计算表达式。 |
| setTimeout()  | 在指定的毫秒数后调用函数或计算表达式。             |

**setInterval**(fn,毫秒值)：定时器，用于周期性的执行某个功能，并且是**循环执行**。该函数需要传递2个参数：

fn:函数，需要周期性执行的功能代码

毫秒值：间隔时间

```text
//定时器 - setInterval -- 周期性的执行某一个函数
var i = 0;
setInterval(function(){
     i++;
     console.log("定时器执行了"+i+"次");
},2000);
```



**setTimeout**(fn,毫秒值) ：定时器，只会在一段时间后**执行一次功能**。参数和上述setInterval一致

注释掉之前的代码，添加代码如下：

~~~js
//定时器 - setTimeout -- 延迟指定时间执行一次 
setTimeout(function(){
	alert("JS");
},3000);
~~~

浏览器打开，3s后弹框，关闭弹框，发现再也不会弹框了。



##### Location对象

location是指代浏览器的地址栏对象，对于这个对象，我们常用的是href**属性**，用于获取或者设置浏览器的地址信息，添加如下代码：

```text
//获取浏览器地址栏信息
alert(location.href);
//设置浏览器地址栏信息
location.href = "https://www.itcast.cn";
```

设置后会自动跳转到该地址。



#### DOM对象

##### DOM介绍

DOM：Document Object Model 文档对象模型。也就是 JavaScript 将 HTML 文档的各个组成部分封装为对象。

封装的对象分为

- Document：整个文档对象
- Element：元素对象
- Attribute：属性对象
- Text：文本对象
- Comment：注释对象

![1668796698067](https://pic.bitday.top/i/2025/03/19/u6l3cm-2.png)

那么我们学习DOM技术有什么用呢？主要作用如下：

- 改变 HTML 元素的内容
- 改变 HTML 元素的样式（CSS）
- 对 HTML DOM 事件作出反应
- 添加和删除 HTML 元素

从而达到**动态改变页面效果**目的。

##### DOM获取

| 函数                              | 描述                                         |
| --------------------------------- | -------------------------------------------- |
| document.getElementById()         | 根据id属性值获取，返回单个Element**对象**    |
| document.getElementsByTagName()   | 根据标签名称获取，返回Element对象**数组**    |
| document.getElementsByName()      | 根据name属性值获取，返回Element对象**数组**  |
| document.getElementsByClassName() | 根据class属性值获取，返回Element对象**数组** |

示例代码：

```text
<body>
    <img id="h1" src="img/off.gif">  <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>
```

- document.getElementById()： 根据标签的id属性获取标签对象，id是唯一的，所以获取到是单个标签对象。 

```text
<script>
//1. 获取Element元素

//1.1 获取元素-根据ID获取
 var img = document.getElementById('h1');
 alert(img);
</script>
```

- document.getElementsByTagName() :  根据标签的名字获取标签对象，同名的标签有很多，所以返回值是数组。<font color=red>重点！</font>

```text
var divs = document.getElementsByTagName('div');
for (let i = 0; i < divs.length; i++) {
     alert(divs[i]);
}
```

##### DOM修改

同上面的例子：

你想要如何操作获取到的DOM元素，你需要查阅手册，看它支持的属性

![image-20240228185708363](https://pic.bitday.top/i/2025/03/19/u6k7vg-2.png)

```text
var divs = document.getElementsByClassName('cls');
var div1 = divs[0];
div1.innerHTML = "传智教育666";
```

### JS事件

JavaScript对于事件的绑定提供了2种方式：

- 方式1：通过html标签中的事件属性进行绑定

```text
<input type="button" id="btn1" value="事件绑定1" onclick="on()">
<script>
    function on(){
        alert("按钮1被点击了...");
    }
</script>
```

- 方式2：通过DOM中Element元素的事件属性进行绑定

```text
<input type="button" id="btn2" value="事件绑定2">
<script>  
document.getElementById('btn2').onclick = function(){
    alert("按钮2被点击了...");
}
</script>
```

常见事件：

| 事件属性名  | 说明                     |
| ----------- | ------------------------ |
| onclick     | 鼠标单击事件             |
| onblur      | 元素失去焦点             |
| onfocus     | 元素获得焦点             |
| onload      | 某个页面或图像被完成加载 |
| onsubmit    | 当表单提交时触发该事件   |
| onmouseover | 鼠标被移到某元素之上     |
| onmouseout  | 鼠标从某元素移开         |

## VUE

### VUE简介

我们引入了一种叫做**MVVM(Model-View-ViewModel)的前端开发思想**，即让我们开发者更加关注数据，而非数据绑定到视图这种机械化的操作。那么具体什么是MVVM思想呢？

MVVM:其实是Model-View-ViewModel的缩写，有3个单词，具体释义如下：

- Model: 数据模型，特指前端中通过请求从后台获取的数据
- View: 视图，用于展示数据的页面，可以理解成我们的html+css搭建的页面，但是没有数据
- ViewModel: 数据绑定到视图，负责将数据（Model）通过JavaScript的DOM技术，将数据展示到视图（View）上

![image-20240228194959643](https://pic.bitday.top/i/2025/03/19/u6mbl5-2.png)

基于上述的MVVM思想，其中的Model我们可以通过Ajax来发起请求从后台获取;对于View部分，我们将来会学习一款ElementUI框架来替代HTML+CSS来更加方便的搭建View;而今天我们要学习的就是侧重于ViewModel部分开发的vue前端框架，用来替代JavaScript的DOM操作，让数据展示到视图的代码开发变得更加的简单。

### VUE快速上手

第一步：在VS Code中创建名为12. Vue-快速入门.html的文件，并且在html文件同级创建js目录，将**资料/vue.js文件**目录下得vue.js拷贝到js目录

第二步：然后编写&lt;script&gt;标签来引入vue.js文件，代码如下：

```text
<script src="js/vue.js"></script>
```

第三步：在js代码区域定义vue对象,代码如下：

```text
<script>
    //定义Vue对象
    new Vue({
        el: "#app", //vue接管区域
        data:{
            message: "Hello Vue"
        }
    })
</script>
```

在创建vue对象时，有几个常用的属性：

- el:  用来指定哪儿些标签受 Vue 管理。 该属性取值 `#app` 中的 `app` 需要是受管理的标签的id属性值
- data: 用来定义数据模型
- methods: 用来定义函数。这个我们在后面就会用到

第四步：在html区域编写视图，其中{{}}是插值表达式，用来将vue对象中定义的model展示到页面上的

~~~html
<body>
    <div id="app">
        <input type="text" v-model="message">
        {{message}}
    </div>
</body>
~~~

### Vue指令

**指令：**HTML 标签上带有 v- 前缀的特殊属性，不同指令具有不同含义。

| **指令**  | **作用**                                            |
| --------- | --------------------------------------------------- |
| v-bind    | 为HTML标签绑定属性值，如设置  href , css样式等      |
| v-model   | 在表单元素上创建双向数据绑定                        |
| v-on      | 为HTML标签绑定事件                                  |
| v-if      | 条件性的渲染某元素，判定为true时渲染,否则不渲染     |
| v-else    |                                                     |
| v-else-if |                                                     |
| v-show    | 根据条件展示某元素，区别在于切换的是display属性的值 |
| v-for     | 列表渲染，遍历容器的元素或者对象的属性              |

#### V-bind和v-model

- v-bind:  为HTML标签绑定属性值，如设置  href , css样式等。当vue对象中的数据模型发生变化时，标签的属性值会随之发生变化。**单向**绑定！

- v-model： 在表单元素上创建**双向**数据绑定。什么是双向？

  -  vue对象的data属性中的数据变化，视图展示会一起变化

  -  视图数据发生变化，vue对象的data属性中的数据也会随着变化。


data属性中数据变化，我们知道可以通过赋值来改变，但是视图数据为什么会发生变化呢？**只有表单项标签！所以双向绑定一定是使用在表单项标签上的**。

```text
<body>
    <div id="app">
        <a v-bind:href="url">链接1</a>
        <a :href="url">链接2</a>
        <input type="text" v-model="url">
    </div>
</body>
<script>
    //定义Vue对象
    new Vue({
        el: "#app", //vue接管区域
        data:{
           url: "https://www.baidu.com"
        }
    })
</script>
```

#### v-on

v-on: 用来给html标签绑定事件的

```text
<input type="button" value="点我一下" v-on:click="handle()">
```

简写：

```text
<input type="button" value="点我一下" @click="handle()">
```

script：

```text
<script>
    //定义Vue对象
    new Vue({
        el: "#app", //vue接管区域
        data:{
           
        },
        methods: {
            handle: function(){
                alert("你点我了一下...");
            }
        }
    })
</script>
```

#### v-if和v-show

```text
年龄<input type="text" v-model="age">经判定,为:
<span v-if="age <= 35">年轻人(35及以下)</span>
<span v-else-if="age > 35 && age < 60">中年人(35-60)</span>
<span v-else>老年人(60及以上)</span>
```

```text
年龄<input type="text" v-model="age">经判定,为:
<span v-show="age <= 35">年轻人(35及以下)</span>
<span v-show="age > 35 && age < 60">中年人(35-60)</span>
<span v-show="age >= 60">老年人(60及以上)</span>
```

v-show和v-if的作用效果是一样的，只是原理不一样。v-if指令，不满足条件的标签代码直接没了，而v-show指令中，不满足条件的代码依然存在，只是添加了css样式来控制标签不去显示。

#### vue-for

v-for: 从名字我们就能看出，这个指令是用来遍历的。其语法格式如下：

```text
 <div id="app">
     <div v-for="addr in addrs">{{addr}}</div>
     <hr>
     <div v-for="(addr,index) in addrs">{{index}} : {{addr}}</div>
</div>
```

```text
<script>
    //定义Vue对象
    new Vue({
        el: "#app", //vue接管区域
        data:{
           addrs:["北京", "上海", "西安", "成都", "深圳"]
        },
        methods: {
            
        }
    })
</script>
```

index从0开始

### Vue生命周期

| 状态          | 阶段周期 |
| ------------- | -------- |
| beforeCreate  | 创建前   |
| created       | 创建后   |
| beforeMount   | 挂载前   |
| mounted       | 挂载完成 |
| beforeUpdate  | 更新前   |
| updated       | 更新后   |
| beforeDestroy | 销毁前   |
| destroyed     | 销毁后   |

其中我们需要重点关注的是**mounted,**其他的我们了解即可。

与methods平级

mounted：挂载完成，Vue初始化成功，HTML页面渲染成功。**以后我们一般用于页面初始化自动的ajax请求后台数据**



## Ajax-Axios

Ajax: 全称Asynchronous JavaScript And XML，异步的JavaScript和XML。其作用有如下2点：

- 与服务器进行数据交换：通过Ajax可以给服务器发送请求，并获取服务器响应的数据。
- 异步交互：可以在**不重新加载整个页面**的情况下，与服务器交换数据并**更新部分网页**的技术，如：搜索联想、用户名是否可用的校验等等。

现在Ajax已经淘汰，用Axios了，是对Ajax的封装

### Axios快速上手

Axios的使用比较简单，主要分为2步：

- 引入Axios文件

  ~~~html
  <script src="js/axios-0.18.0.js"></script>
  ~~~

- 使用Axios发送请求，并获取响应结果，官方提供的api很多，此处给出2种，如下

  - 发送 get 请求

    ~~~js
    axios({
        method:"get",
        url:"http://localhost:8080/ajax-demo1/aJAXDemo1?username=zhangsan"
    }).then(function (resp){
        alert(resp.data);
    })
    ~~~

  - 发送 post 请求

    ```js
    axios({
        method:"post",
        url:"http://localhost:8080/ajax-demo1/aJAXDemo1",
        data:"username=zhangsan"
    }).then(function (resp){
        alert(resp.data);
    });
    ```


推荐以下方法！

| 方法                               | 描述           |
| ---------------------------------- | -------------- |
| axios.get(url [, config])          | 发送get请求    |
| axios.delete(url [, config])       | 发送delete请求 |
| axios.post(url [, data[, config]]) | 发送post请求   |
| axios.put(url [, data[, config]])  | 发送put请求    |

```text
axios.get("http://yapi.smart-xwork.cn/mock/169327/emp/list").then(result => {
    console.log(result.data);
})
```

```text
axios.post("http://yapi.smart-xwork.cn/mock/169327/emp/deleteById","id=1").then(result => {
    console.log(result.data);
})
```

### axios使用步骤：

步骤：

1. 首先创建文件，提前准备基础代码，包括表格以及vue.js和axios.js文件的引入
2. 我们需要在vue的mounted钩子函数中发送ajax请求，获取数据
3. 拿到数据，数据需要绑定给vue的data属性
4. 在&lt;tr&gt;标签上通过v-for指令遍历数据，展示数据，这里同Vue中的步骤。

```text
<script>
    new Vue({
       el: "#app",
       data: {
         emps:[]
       },
       mounted () {
          //发送异步请求,加载数据
          axios.get("http://yapi.smart-xwork.cn/mock/169327/emp/list").then(result => {
            console.log(result.data);
            this.emps = result.data.data;
          })
       }
    });
</script>
```

Vue中先定义emps空数组，再axios将数据取到里面 this.emps=xxxx



## Nginx

**docker-compose.yml**

```yml
version: '3.8'

networks:
  group-buy-network:
    external: true

services:
  # 前端（保持不变）
  group-buy-market-front:
    image: nginx:alpine
    ports: ['86:80']
    volumes:
      - ./nginx/html:/usr/share/nginx/html
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - group-buy-network

  # 后端实例1
  group-buying-sys-1:
    image: smile/group-buying-sys:latest
    ports: ['8091:8091']
    networks:
      - group-buy-network

  # 后端实例2
  group-buying-sys-2:
    image: smile/group-buying-sys:latest  # 使用相同镜像
    ports: ['8092:8091']  # 宿主机端口不同，容器内部端口相同
    networks:
      - group-buy-network

```

**nginx.conf**

```nginx
# 全局配置块
user  nginx;                      # 以nginx用户身份运行worker进程（安全性考虑）
worker_processes  auto;           # 自动根据CPU核心数设置工作进程数量（优化性能）
error_log  /var/log/nginx/error.log warn;  # 错误日志路径，只记录警告及以上级别的错误
pid        /var/run/nginx.pid;     # 存储Nginx主进程ID的文件位置（用于进程管理）

# 事件处理模块配置
events {
  worker_connections  1024;       # 每个worker进程能处理的最大并发连接数
                                  # 总并发量 = worker_processes * worker_connections
}

# HTTP服务器配置
http {
  # 基础文件类型支持
  include       /etc/nginx/mime.types;  # 包含MIME类型定义文件（扩展名与Content-Type映射）
  default_type  application/octet-stream; # 默认MIME类型（当无法识别文件类型时使用）

  # 性能优化参数
  sendfile        on;             # 启用高效文件传输模式（零拷贝技术）
  keepalive_timeout  65;         # 客户端保持连接的超时时间（秒），减少TCP握手开销

  # 上游服务器组定义（负载均衡）
  upstream gbm_backend {
    # 负载均衡配置（两个后端实例）
    server group-buying-sys-1:8091 weight=3;  # 后端实例1，权重为3（获得60%流量）
    server group-buying-sys-2:8091 weight=2;  # 后端实例2，权重为2（获得40%流量）
    keepalive 32;                # 保持到后端服务器的长连接数（提升性能）
  }

  # 支付服务上游（单实例）
  upstream pay_backend {
    server pay-mall:8092;        # 支付服务地址（Docker服务名）
  }

  # 虚拟主机配置（一个server代表一个网站）
  server {
    # 监听配置
    listen       80 default_server;       # 监听IPv4的80端口，作为默认服务器
    listen       [::]:80 default_server;  # 监听IPv6的80端口
    server_name  groupbuy.bitday.top;    # 绑定的域名（支持多个，用空格分隔）

    # 静态文件服务配置
    root /usr/share/nginx/html;   # 前端静态文件根目录（Docker需挂载此目录）
    index index.html;             # 默认访问的索引文件

    # 前端路由处理（适配Vue/React等单页应用）
    location / {
      try_files $uri $uri/ /index.html;  # 尝试顺序：匹配文件→匹配目录→回退到index.html
    }

    # 组购系统API代理配置
    location /api/v1/gbm/ {
      proxy_pass         http://gbm_backend;  # 请求转发到负载均衡组
      proxy_set_header   Host            $host;       # 传递原始域名
      proxy_set_header   X-Real-IP       $remote_addr;   # 传递客户端真实IP
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for; # 代理链IP信息
      
    }

    # 支付/登录API代理（正则匹配）
    location ~ ^/api/v1/(alipay|login)/ {
      proxy_pass         http://pay_backend;
      proxy_set_header   Host            $host;
      proxy_set_header   X-Real-IP       $remote_addr;
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }
}
```

**注意事项：**

1.由于是docker部署，要区别宿主机端口与容器内端口！比如 `server group-buying-sys-1:8091 weight=3;` 这里的8091就是 `group-buying-sys-1` 这个容器内端口。类似地，nginx也是docker部署，通过宿主机端口86映射到`group-buy-market-front`这个容器内的80端口。`nginx.conf`配置中的端口一定是和容器内挂钩的，而不是和宿主机！！！

2.如果不是docker部署，比如在本地windows运行`nginx.exe` ，那么 就没有 `ports: ['8091:8091']` 这种映射关系，你的java项目中写的端口是多少，那么`nginx.conf`就配置多少

3.docker部署，如果 `nginx` 与 `group-buying-sys` 位于同一网络中，可以`服务名:容器内端口` 等价于 `宿主机ip:端口`。比如 `group-buying-sys-2` 中 `ports: ['8092:8091']`  ，假设服务器ip地址为`124.71.159.xxx` ，那么

```nginx
upstream gbm_backend { 
    server group-buying-sys-2:8091 weight=2;   #推荐！ nginx->后端容器
  }
```

```nginx
upstream gbm_backend {
    server 124.71.159.xxx:8092 weight=2;   #非常不推荐！相关nginx->宿主机->后端容器
  }
```

两种效果一样，但推荐第一种！！！

4.Nginx 反向代理的核心配置

```nginx
location /api/v1/gbm/ {
      proxy_pass         http://gbm_backend;  # 请求转发到负载均衡组
      proxy_set_header   Host            $host;       # 传递原始域名
      proxy_set_header   X-Real-IP       $remote_addr;   # 传递客户端真实IP
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for; # 代理链IP信息
      
}
```

将所有匹配 `/api/v1/gbm/` 路径的请求转发到 `gbm_backend` 这个后端容器（可负载均衡为多台）。

请求 `http://nginx-server/api/v1/gbm/order`    →  转发到 `http://gbm_backend/api/v1/gbm/order`

**注意，**如果

```nginx
location /api/v1/gbm/ {
  proxy_pass http://gbm_backend/;  # 注意末尾的斜杠
}
```

请求 `http://nginx-server/api/v1/gbm/order`    →  转发到 `http://gbm_backend/order`（`/api/v1/gbm/` 被移除）

5.如果配置了反向代理（第4点内容），那么前端调用后端接口时，HTML、JS中无需写具体的后端服务器所在地址（ip:端口），而且如果做了负载均衡，有多台，这里也不好指定哪一台。

**为什么？**

比如前端发送请求fetch(`/api/v1/gbm/index/query_group_buy_market_config`)

发现匹配 `/api/v1/gbm` ，nginx根据配置就发给http://gbm_backend负载均衡组，组里有`group-buying-sys-1`和 `group-buying-sys-2`，根据负载均衡规则转发到其中一台后端服务器。

6.静态文件挂载

```nginx
server {
    ...
    # 静态文件服务配置
    root /usr/share/nginx/html;   # 前端静态文件根目录（Docker需挂载此目录）
    index index.html;     
    ...
}
```

root 要指定静态文件根目录，如果是docker部署，一定要写**容器内**的位置；`index.html`  这个文件是`/usr/share/nginx/html`目录下的。
