文章目录
- 一、表单控制
- 二、购物车案例
- 三、v-model进阶
- 四、与后端交互
- 跨域问题解决,三种交互方法
- 跨域问题详解
- 1-CORS:后端代码控制,上面案例采用的方式
- 1) 方式一:后端添加请求头
- 2) 方式二:编写中间件
- 3) 方式三:第三方模块django-cors-headers
- 2-Nginx反向代理 (常用)
- 3-JSONP:很老不会用了,它只能发get请求
- 4-搭建Node代理服务器
- 五、计算属性
- 1) 重写过滤案例
- 六、监听属性
- 七、Vue生命周期
- 八个生命周期钩子函数
- 实操案例
一、表单控制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="div">
<h1>表单控制</h1>
<hr>
<p>用户名:<input type="text" v-model="username"></p>
<p>密码:<input type="password" v-model="password"></p>
<p>
性别:<br>
男:<input type="radio" v-model="gender" value="1">
女:<input type="radio" v-model="gender" value="2">
</p>
<p>记住密码:<input type="checkbox" v-model="set_pwd"></p>
<p>
爱好:<br>
运动:<input type="checkbox" v-model="hobby" value="运动">
健身:<input type="checkbox" v-model="hobby" value="健身">
旅游:<input type="checkbox" v-model="hobby" value="旅游">
</p>
<button @click="handleSubmit">提交</button>
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
username:'',
password:'',
gender:'',// radio单选,多个radio绑定同一个变量,选中某个,就对应value值
set_pwd:false,// checkbox 单选是true或false
hobby:[],// checkbox 多选是数组类型,必须一开始定义就是数组,多个checkbox绑定一个变量
},
methods:{
handleSubmit(){
console.log(this.username,this.password,this.gender,this.set_pwd,this.hobby)
}
}
})
</script>
</body>
</html>
二、购物车案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="../js/vue.js"></script>
<style>
#table{
margin-top:50px;
margin-bottom:30px;
}
input[type='checkbox']{
cursor:pointer;
}
.btn{
border:1px solid rgb(138, 138, 138);
}
</style>
</head>
<body>
<div id="div" class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<h1 class="text-center" id="table">购物车商品结算清单</h1>
<table class="table table-hover table-bordered">
<thead>
<tr>
<th class="text-center">商品id</th>
<th class="text-center">商品名</th>
<th class="text-center">商品价格</th>
<th class="text-center">商品数量</th>
<th class="text-center">
全选or全不选 <input type="checkbox" v-model="xuan" @change="CheckAll">
</th>
<th class="text-center">删除加购</th>
</tr>
</thead>
<tbody>
<tr v-for="data in shoplist">
<td class="text-center">{{data.id}}</td>
<td class="text-center">{{data.name}}</td>
<td class="text-center">{{data.price}}</td>
<td class="text-center">
<span @click="CheckRemove(data)" class="btn">-</span>
<span v-if="nm_count==true" @click="qieh">{{data.count}}</span>
<input v-else type="number" class="form-control-static" @change="number(data)" v-model="data.count" @blur="qieh">
<span @click="CheckAdd(data)" class="btn">+</span>
</td>
<td class="text-center">
<input type="checkbox" @change="Checkxuan" v-model="Bymore" :value="data">
</td>
<td class="text-center"><button class="btn btn-danger" @click="CheckDel(data)">删除</button></td>
</tr>
</tbody>
</table>
<h5>当前选中商品:{{Bymore}}</h5>
<h3>购物车结算金额为:¥{{CountPrice()}}</h3>
</div>
</div>
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
xuan:false,
shoplist:[
{id:1,name:'巧克力',price:66,count:5},
{id:2,name:'奶糖',price:3,count:8},
{id:3,name:'辣条',price:6,count:4},
{id:4,name:'果汁',price:9,count:55},
{id:5,name:'薯片',price:12,count:33},
],
Bymore:[],
nm_count:true,
},
methods:{
CountPrice(){ //对勾选物品进行实时总价格计算
var total = 0
for(var item of this.Bymore){
total += item.price*item.count
}
return total
},
CheckAll(){ //全选或全不选状态监控
if(this.xuan==true){
this.Bymore=this.shoplist
}else{
this.Bymore=[]
}
},
number(data){ //对coun数量设置最少不能小于1
if(data.count<1){
data.count=1
}
},
Checkxuan(){ //对单选进行监控,商品全勾选自动给全选勾上,否则不勾
if(this.Bymore.length==this.shoplist.length){
this.xuan=true
}else{this.xuan=false}
},
CheckAdd(data){ //点击事件,添加商品数量
data.count++
},
CheckRemove(data){ //点击事件,减去商品数量,限制大于1
if (data.count>1){
data.count--
}
},
CheckDel(data){ //点击对商品列表进行删除
if(this.shoplist.indexOf(data)>0){
console.log(this.shoplist.splice(this.shoplist.indexOf(data),1))
}
},
qieh(){ //对商品数量进行自选添加数量
this.nm_count=!this.nm_count
//console.log(this.nm_count)
}
}
})
</script>
</body>
</html>
三、v-model进阶
v-model双向数据绑定,还可以对输入框数据进行一定的限定。
v-modle | 释义 |
---|---|
lazy | 等待input框的数据绑定时区焦点之后再变化 |
number | 以数字开头并只保留后面的数字,不保留字母;字母开头都保留 |
trim | 去除首位的空格 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="div">
<h1>v-model进阶用法</h1><p/>
默认v-model----><input type="text" v-model="name">------->{{name}}<p/>
lazy----><input type="text" v-model.lazy="name1">------->{{name1}}<p/>
number----><input type="text" v-model.number="name2">------->{{name2}}<p/>
trim----><input type="text" v-model.trim="name3">------->{{name3}}
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
name:'',
name1:'',
name2:'',
name3:'',
},
methods:{
}
})
</script>
</body>
</html>
四、与后端交互
跨域问题解决,三种交互方法
与后端交互统一使用json编码格式
与后端交互涉及到跨域问题后,该如何解决跨域问题?
- 当前端发送请求,后端响应了,但是前端还是报错,这是因为:
跨域问题
的存在,浏览器检测到前端与后端不是来自同一个域
,所以认为这是不安全的,最终也就拦截了该资源的传递 - 想要解决这个问题,就要实现:CORS,也就是跨域资源共享
- 浏览器的原因,只要不是向地址栏中的【域:地址和端口】发送请求,拿到的数据,浏览器就会拦截
- 拦截例子:跨域问题
- 解决:在后端响应头中添加
headers={'Access-Control-Allow-Origin':'*'}
- 浏览器的原因,只要不是向地址栏中的【域:地址和端口】发送请求,拿到的数据,浏览器就会拦截
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script src="../js/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>Document</title>
</head>
<body>
<div id="div">
<h1>jquery的ajax与后端交互</h1><p/>
<!--一般不会在vue中使用jQuery的ajax发送请求,很多功能用不到-->
<h4>username: {{username}}</h4>
<h4>age:{{age}}</h4>
<button @click="clicksubmit1">点击获取数据</button>
<p/>
<hr>
<h1>JS的fetch与后端交互</h1>
<!--提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分-->
<h4>username: {{username}}</h4>
<h4>age:{{age}}</h4>
<button @click="clicksubmit2">点击获取数据</button>
<p/>
<hr>
<h1>axios与后端交互</h1>
<!--第三方ajax,只有ajax没有别的功能,很小,底层基于XMLHttprequest-->
<h4>username: {{username}}</h4>
<h4>age:{{age}}</h4>
<button @click="clicksubmit3">点击获取数据</button>
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
username:'',
age:'',
},
methods:{
//方式1:jQuery的ajax方式
clicksubmit1(){
//向后端发送请求,拿到数据,赋值给username、age
$.ajax({
url:'http://127.0.0.1:8000/submit/',
method:'get',
success:data=>{
console.log(typeof data)
this.username=data.username
this.age=data.age
}
})
},
//方式2:原生js(fetch)发送请求
clicksubmit2(){
//向后端发送请求,拿到数据,赋值给username、age
// fetch('http://127.0.0.1:8000/submit/')
// .then(function(response){
// return response.json();
// })
// .then(function(data){
// console.log(data);
// });
//箭头函数
fetch('http://127.0.0.1:8000/submit/')
.then(response=>{
return response.json();
})
.then(data=>{
this.username=data.username
this.age=data.age
});
},
//方式3:axios
clicksubmit3(){
//向后端发送请求,拿到数据,赋值给username、age
axios.get('http://127.0.0.1:8000/submit/')
.then(result => {
console.log(result.data);
this.username=result.data.username
this.age=result.data.age
}).catch(error => {
console.log(error);
});
}
}
})
</script>
</body>
</html>
跨域问题详解
前端发送ajax请求,后端会有跨域的拦截,原因是:同源策略。同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
-请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同.
-发送ajax请求的地址,必须跟浏览器上的url地址处于同域上 域[域名,地址,端口,协议]
-请求成功,数据库返回,但是浏览器拦截
# 补充:浏览器中输入域名,没有加端口
-www.baidu.com---->dns--->解析成地址 192.168.2.3----》没有加端口,默认是80
-dns解析,先找本地的host文件
-可以修改本地的host做映射
如何解决跨域问题?
1-CORS:后端代码控制,上面案例采用的方式
# cors: #xss,csrf---跨站请求伪造
跨域资源共享:后端技术,就是在响应头中加入 固定的头,就会运行前端访问了
'CORS基本流程'
1.浏览器发出CORS简单请求
只需要在头信息之中增加一个Origin字段。
2.浏览器发出CORS非简单请求
会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,
以及可以使用哪些HTTP动词和头信息字段。
只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
'什么是简单请求,什么是非简单请求'
# 符合如下条件,就是简单请求
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、
multipart/form-data、text/plain
'演示简单和非简单请求'
-如果是简单,直接发送真正的请求
-如果是非简单,先发送options,如果运行,再发真正的
1) 方式一:后端添加请求头
# 前端发送axios不添加请求头---简单请求
created() {
this.$axios.get(this.$settings.BASE_URL+ '/home/banner/').then(res=>{
console.log(res)
})
},
# 允许的前端地址
return APIResponse(data=res.data, headers={
"Access-Control-Allow-Origin": "http://192.168.1.47:8080"}) # {code:100,msg:成功,data=[{},{}]}
# 允许所有前端地址
return APIResponse(data=res.data,headers={'Access-Control-Allow-Origin':'*'}) # {code:100,msg:成功,data=[{},{}]}
2) 方式二:编写中间件
解决跨域问题和请求头携带数据
# 1.重写process_response方法
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
def process_response(self, request, response):
if request.method == 'OPTIONS': # 解决非简单请求的请求头
response["Access-Control-Allow-Headers"] = "*"
# 允许前端的地址,所有请求头允许
response["Access-Control-Allow-Origin"] = "*"
return response
# 2. 注册中间件
MIDDLEWARE = [
'utils.common_middle.CorsMiddleWare'
]
3) 方式三:第三方模块django-cors-headers
# 第一步:安装
pip install django-cors-headers
# 第二步:配置app
INSTALLED_APPS = [
'corsheaders'
]
# 第三步:配置中间件
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
]
# 第四步:在配置文件配置
# 允许所有域
CORS_ORIGIN_ALLOW_ALL = True
# 允许的请求方式
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
# 允许请求头中加的东西
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
'token',
)
2-Nginx反向代理 (常用)
3-JSONP:很老不会用了,它只能发get请求
4-搭建Node代理服务器
五、计算属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="div">
<h1>计算属性普通函数方式------>函数会重写计算</h1>
姓名:<input type="text" v-model="name">------>{{getName()}} <p/><br>
<hr>
<p>
<h1>计算属性Computed</h1>
年龄:<input type="text" v-model="age">------> {{NewAge}}<p/><br>
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
name:'',
age:'',
},
methods:{
//只要页面刷新(加载页面),函数就会执行,无论跟函数是否有关系
getName(){
console.log('名字首字母大写了!')
return this.name.substring(0,1).toUpperCase()+this.name.substring(1)
}
},
computed:{
//方法当属性来用,不加括号,只要computed里面的方法才能不加括号,一定要有返回值
NewAge(){
console.log('计算属性----执行了')
return Number(this.age)+20
}
}
})
</script>
</body>
</html>
1) 重写过滤案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="div">
<h1>过滤案例重写使用computed</h1>
<input type="text" v-model="search" >
<ul>
<li v-for="item in NewDatelist">{{item}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
search:'',
datelist:['a', 'at', 'atom', 'be', 'beyond', 'bee', 'c', 'cs', 'csrf'],
},
computed:{
NewDatelist(){
return this.datelist.filter(item => item.indexOf(this.search) >= 0)
}
}
})
</script>
</body>
</html>
六、监听属性
监听一个属性的变化 只要它发生变化 就执行一个函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="div">
<h1>监听属性</h1>
<button @click="type='Python'">Python</button> |
<button @click="type='Java'">Java</button>
<br>
<hr>
{{type}}
</div>
<script>
var vm = new Vue({
el:'#div',
data:{
type:'',
},
watch:{
type(){
console.log('向后端发送请求')
console.log(this.type)
}
}
})
</script>
</body>
</html>
七、Vue生命周期
对官网的生命周期进行理解注解的
八个生命周期钩子函数
函数 | 释义 |
---|---|
beforeCreate | 创建Vue实例之前调用 |
created | 创建Vue实例成功后调用(可以在此处发送异步请求后端数据) |
beforeMount | 渲染DOM之前调用 |
mounted | 渲染DOM之后调用 |
beforeUpdate | 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染) |
updated | 重新渲染完成之后调用 |
beforeDestroy | 销毁之前调用 |
destroyed | 销毁之后调用 |
从vue实例创建开始直到实例被销毁,总共经历了8个生命周期钩子
【只要写了就会执行】
函数
钩子:反序列化验证---》钩子函数
学名[专门名字]---》面向切面编程(AOP)
OOP:面向对象编程
'用途'
1 页面加载完成,向后端发请求拿数据
写在created中 发送ajax请求
有的人放在mounted中加载(也可以放,不过页面数据已经有了,
请求来数据更新,就执行了Update,效率上不如在created中)
2 组件中有定时任务,组件销毁,要销毁定时任务
beforeDestroy
-组件一创建,created中启动一个定时器
-组件被销毁,beforeDestroy销毁定时器
'补充延时器和定时器'
-定时器
setInterval(()=>{
console.log('每隔3s执行')
},3000)
-延时器
setTimeout( ()=>{
console.log('延时器,3s后执行')
},3000)
实操案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="div">
<h1>vue生命周期</h1>
<button @click="doubleShow">点击显示组件或消失</button>
<hr>
<!--全局组件,自定义-->
<child v-if="show==true"></child>
</div>
<script>
//全局组件
Vue.component('child',{
// 里面写html内容,必须包在一个标签中
template:`
<div>
<button @click="onClick">点击更新</button>
<br>
{{title}}
</div>
`,
data(){ // data必须是方法,返回对象
return {
title:'vue生命周期',
t:null,
}
},
methods:{
onClick(){
this.title='新的vue生命周期'
}
},
beforeCreate(){ //组件创建前执行,html,js都是空的
console.group('当前状态:beforeCreate')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
},
Created(){ // 组件创建完毕执行,js有值了,但是html还是空的
console.group('当前状态:Created')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
//创建定时器,每隔3秒打印hello world
this.t=setInterval(()=>{
console.log('hello world')
},3000)
},
beforeMount(){ //挂载模版之前执行,js有值了,但是html还是空的
console.group('当前状态:beforeMount')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
},
mounted(){ //挂载模版完毕执行,js有值,html也有了
console.group('当前状态:mounted')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
},
beforeUpdate(){ //重新渲染之前执行,只要页面发生变化或js变化就会执行
console.group('当前状态:beforeUpdate')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
},
updated(){ //重新渲染完毕执行,
console.group('当前状态:updated')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
},
beforeDestroy(){ //销毁之前执行,资源清理工作
console.group('当前状态:beforeDestory')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
},
destroyed(){ //销毁之后执行,
console.group('当前状态:destroyed')
console.log('当前el状态:',this.$el)
console.log('当前data状态:',this.$data)
//销毁定时器
clearInterval(this.t)
this.t=null
}
})
//根组件
var vm = new Vue({
el:'#div',
data:{
show:false,
},
methods:{
doubleShow(){
this.show=!this.show
}
}
})
</script>
</body>
</html>