复习
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("*")@Slf4jpublic 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 / es6this.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({//ViewModelel:"#container", //挂载点,与页面的某个dom节点关联data:{ //数据 ModelmyClass:'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({//ViewModelel:"#container", //挂载点,与页面的某个dom节点关联data:{ //数据 Modelinfo:''},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>

