复习
Vue: 渐进式JavaScript框架
核心理念:MVVM模式 Model-View-ViewModel 模型与视图的双向绑定
模板语法:
{{变量名}}
v-bind 绑定html标签的属性
v-on 指定事件及处理函数
v-for 循环
v-if v-else-if v-else 判断
Vue实例:
let app = new Vue({
el:”#app”,//挂载点
data:{},//数据
methods:{}//方法
});
MDN文档:https://developer.mozilla.org/zh-CN/
<!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>
</head>
<body>
<div id="app">
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>状态</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tr v-for='t in teachers'>
<td>{{t.teacher_id}}</td>
<td>{{t.teacher_name}}</td>
<td>{{t.state}}</td>
<td>{{t.email}}</td>
<td>
<button v-on:click='audit(t,true)'>审核通过</button>
<button v-on:click='audit(t,false)'>审核不通过</button>
<button v-on:click='fire(t)'>开除</button>
</td>
</tr>
</table>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
let app = new Vue({
el: "#app",
data: {
teachers: [
{
teacher_id: 1,
teacher_name: "zhangsan",
state: "wait",
email: "abc@cyx.com",
},
{
teacher_id: 2,
teacher_name: "zhangsan2",
state: "wait",
email: "abc2@cyx.com",
}
],
},
methods:{
audit:function(teacher,pass){
teacher.state= pass?"NORMAL":"FAIL";
},
fire:function(t){
let pos = this.teachers.indexOf(t);
this.teachers.splice(pos,1);
}
}
});
</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>教师管理</title>
</head>
<body>
<div id="app">
<div><input type="text" v-model='form.username' placeholder="用户名"></div>
<div><input type="password" v-model='form.password' placeholder="密码"></div>
<div>
<select v-model='form.country'>
<option value="China">中国</option>
<option value="USA">美国</option>
<option value="Russia">俄罗斯</option>
</select>
</div>
<div>
讲师<input type="radio" v-model='form.role' name="role" value='teacher'>
学员<input type="radio" v-model='form.role' name="role" value='student'>
</div>
<div>
<button @click='login'>登录</button>
</div>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
let app = new Vue({
el: "#app",
data: {
form:{
username:'',
password:'',
country:'China',
role:'student'
}
},
methods:{
login:function(){
console.log(this.form);
axios
.post('http://localhost:8000/login',this.form)//发送到/login,参数是this.form
.then(function(response){//成功处理
console.log(response)
})
.catch(function(error){//异常处理
console.log(error);
})
}
}
});
</script>
</body>
</html>
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用
value
属性和input
事件; - checkbox 和 radio 使用
checked
属性和change
事件; - select 字段将
value
作为 属性并将change
作为事件。缩写
v-bind 缩写为:
v-on 缩写为@
axios 通信
专用于发送ajax请求的js库
https://www.kancloud.cn/yunye/axios/234845
当前项目前后端完全分离,后端需要在controller添加@CrossOrigin(“*”) 支持跨域
后端接受参数时默认使用@RequestBody
@RestController
@Slf4j
@CrossOrigin("*")
public class LoginController {
@PostMapping("/login")
public Result login(@RequestBody LoginForm loginForm){
axios参数结构
axios.request({
url:’’,
method:’get’,
responseType:’json’,
data:{},
…
})
类似jquery的$.ajax
axios.get() / axios.post()都是简化过后的版本
axios响应
response.data.data才可以引用到返回的结果对象
跨域
练习Get\Post请求
<!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>
</head>
<body>
<div id="app">
<button @click='queryTeacher'>查询</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>状态</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tr v-for='t in teachers'>
<td>{{t.teacherId}}</td>
<td>{{t.teacherName}}</td>
<td>{{t.state}}</td>
<td>{{t.email}}</td>
<td>
<button v-on:click='audit(t,true)'>审核通过</button>
<button v-on:click='audit(t,false)'>审核不通过</button>
<button v-on:click='fire(t)'>开除</button>
</td>
</tr>
</table>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
let app = new Vue({
el: "#app",
data: {
teachers: [
{
teacher_id: 1,
teacher_name: "zhangsan",
state: "wait",
email: "abc@cyx.com",
},
{
teacher_id: 2,
teacher_name: "zhangsan2",
state: "wait",
email: "abc2@cyx.com",
}
],
},
methods:{
audit:function(teacher,pass){
teacher.state= pass?"NORMAL":"FAIL";
axios
.post('http://localhost:8000/audit',
{
'teacherId':teacher.teacherId,
'pass':pass
})
.then(response=>{
console.log(response);
if(response.status==200 && response.data.success){
alert("审核操作成功完成")
}
})
.catch(error=>{
console.error(error);
alert("执行出错")
})
},
fire:function(t){
let pos = this.teachers.indexOf(t);
this.teachers.splice(pos,1);
},
queryTeacher:function(){
axios.get('http://localhost:8000/queryTeacher',{
params:{
state:'wait'
}
})
.then(response=>{
console.log(response)
this.teachers=response.data.data;
})
.catch(error=>{
console.error(error)
})
}
}
});
</script>
</body>
</html>
package com.example.demo56.controller;
import com.example.demo56.common.Result;
import com.example.demo56.controller.form.AuditForm;
import com.example.demo56.entity.Teacher;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
@RestController
@CrossOrigin("*")
@Slf4j
public class TeacherController {
@PostMapping("audit")
public Result audit(@RequestBody AuditForm form){
log.info("审核讲师:{}",form);
return Result.success();
}
@GetMapping("queryTeacher")
public Result queryTeacher(String state){
List<Teacher> teacherList = Arrays.asList(
new Teacher(1,"zhangsan","wait","abc@123.com"),
new Teacher(2,"chengyuxiang","wait","abc1@123.com")
);
return Result.success(teacherList);
}
}
Vue实例
let app = new Vue({
el:"",
data:{},
methods:{}
});
生命周期钩子
bean的生命周期: init destroy
static代码块 构造器(带参构造器)
在某个时间点可以介入到生命周期中,进行一些操作
vue实例具备哪些生命周期阶段:
生命周期钩子函数
- beforeCreate / created 初始化
- beforeMount / mounted 挂载
- beforeUpdate / updated 更新
beforeDestory / destroyed 销毁 ```javascript let app = new Vue({
mounted:function(){
}
});
<a name="GTkAA"></a>
## 计算属性、监听属性
通过计算原有的值得到一个属性
```javascript
<!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>
</head>
<body>
<div id="app">
<input type="text" v-model='familyName'>-<input type="text" v-model='givenName'>
<div>
尊敬的{{name}}
</div>
<div>
<ul>
<li v-for='i in cartItems'>
{{i.pName}} - {{i.price}}
<input type="number" v-model="i.count">
</li>
</ul>
<div>{{totalAmount}}</div>
</div>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
let app = new Vue({
el: "#app",
data: {
familyName:'',
givenName:'',
cartItems:[{pId:1,pName:'鞋子',price:200.0,count:3},{pId:2,pName:'袜子',price:30.0,count:2}]
},
computed:{
name(){
return this.familyName+"."+this.givenName;
},
totalAmount(){
let totalAmount = 0.0;
for(let i = 0;i<this.cartItems.length;i++){
totalAmount+=(this.cartItems[i].price*this.cartItems[i].count);
}
return totalAmount;
}
},
methods:{}
});
</script>
</body>
</html>
私有过滤器与全局过滤器
日期格式化,金额格式化,中英文状态转换
私有过滤器
let app = new Vue({
el: "#app",
data: {
teachers: []
},
mounted(){
//ecmascript = es / es6
this.queryTeacher();
},
//私有过滤器
filters:{//日期格式化,金额格式化,中英文状态转换
transalteState(raw){
let result = '';
switch(raw){
case 'wait': result='待审核';break;
case 'normal': result='审核通过';break;
case 'fail': result='审核失败';break;
default:
console.warn("错误的状态:"+raw);
}
return result;
}
},
全局过滤器
//注册全局过滤器
Vue.filter('transalteState',function(raw){
let result = '';
switch(raw){
case 'wait': result='待审核';break;
case 'normal': result='审核通过';break;
case 'fail': result='审核失败';break;
default:
console.warn("错误的状态:"+raw);
}
return result;
})
使用过滤器
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>状态</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tr v-for='t in teachers'>
<td>{{t.teacherId}}</td>
<td>{{t.teacherName}}</td>
>>>> <td>{{t.state | transalteState}}</td>
<td>{{t.email}}</td>
<td>
<button v-on:click='audit(t,true)'>审核通过</button>
<button v-on:click='audit(t,false)'>审核不通过</button>
<button v-on:click='fire(t)'>开除</button>
</td>
</tr>
</table>
处理样式
内联样式或者使用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">
<title>Vue入门案例</title>
<style>
.hot{
background-color: red;
color:yellow;
}
.cold{
background-color: blue;
color:aliceblue;
}
</style>
</head>
<body>
<!-- 视图 -->
<div id="container">
<!-- {类名:开关变量} -->
<h2 :class="{cold:isClassPresent}">vue真好用啊~</h2>
<div id="hello" :style="{fontSize:num+'px',textShadow:ts}">hello</div>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
//创建VUE对象
//{}表示构造器参数
let app = new Vue({//ViewModel
el:"#container", //挂载点,与页面的某个dom节点关联
data:{ //数据 Model
myClass:'cold',
isClassPresent:false,
num:30,
ts:'3px 3px 3px gold'
},
methods:{
}
});
</script>
</body>
</html>
事件修饰符与按键修饰符
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
按键修饰符
<!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>Vue入门案例</title>
</head>
<body>
<!-- 视图 -->
<div id="container">
<input type="text" v-model="info" @keyup.enter='send'>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
//创建VUE对象
//{}表示构造器参数
let app = new Vue({//ViewModel
el:"#container", //挂载点,与页面的某个dom节点关联
data:{ //数据 Model
info:''
},
methods:{
send(){
alert(this.info)
}
}
});
</script>
</body>
</html>
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
组件化编程
<!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>
<!-- 封装html组件 -->
<navbar></navbar>
<sidebar></sidebar>
<form>
<mz-input></mz-input>
</form>
</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>
<todo-item v-for='t in todos' :todo="t" :key='t'></todo-item>
</ul>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
//全局注册一个组件
Vue.component('todo-item',{
template:'<li>{{todo}}</li>',//html的内容
props:['todo']//属性
});
let app = new Vue({
el: "#app",
data:{
todos:["买锅","买刀","买把铁丝","买sql"]
},
methods:{}
});
</script>
</body>
</html>
加一个在页面上通过input输入待办事项的功能
注意事项:
- 组件的模板只能有一个根标签
- 组件的data是一个function
- 组件内部支持事件及生命周期钩子函数
- 命名,分词使用
-
父子组件通信
父组件->子组件传值, 使用props
子组件-> 父组件传值,使用自定义事件
<!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">
<input type="text" v-model="newTodo" @keyup.enter='addTodo'>
<ul>
<!-- (2)在组件外部监听自定义事件del,交给处理函数 -->
<todo-item v-for='t in todos' @del='handleDelete' :todo="t" :key='t.text'></todo-item>
</ul>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
//全局注册一个组件
Vue.component('todo-item',{
template:'<li>{{todo.text}} {{content}} <input type="button" @click="del(todo)" value="点我"></input></li>',//html的内容
props:['todo'],//属性,
data:function(){
return {
content:'123'
}
},
methods:{
del(todo){
console.log(todo);
this.$emit("del",todo);//(1)在组件内触发一个自定义的事件,名为del,事件对象(事件内容)todo
}
},
mounted(){
}
});
let app = new Vue({
el: "#app",
data:{
newTodo:"",
todos:[{text:"买锅",state:false},{text:"买刀",state:false},{state:false,text:"买把铁丝"}]
},
methods:{
handleDelete(todo){
console.log("外部")
console.log(todo);
this.todos.splice(this.todos.indexOf(todo),1);
},
addTodo(){
let todo = {text:this.newTodo,state:false};
this.todos.push(todo)
this.newTodo="";
}
}
});
</script>
</body>
</html>