文章目录
1、购物车案例升级版(含价格统计、全选/反选、商品增加减少)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/vue.js"></script>
<div id="box">
<input type="checkbox" v-model="selectAll" @change="selectHandler">全选/全不选
<ul>
<li v-for="item in data_list">
<input type="checkbox" v-model="my_car" :value="item" @change="checkHandler">
{{item}}
<button @click="item.number++">新增</button>
{{item.number}}
<button @click="j_goods(item)">减少</button>
</li>
</ul>
<p>我的购物车: {{my_car}}</p>
<p>总价格: {{get_price()}}</p>
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
data_list: [
{name: '西瓜', price: 10, number: 3, id: '1'},
{name: '苹果', price: 3, number: 4, id: '2'},
{name: '香蕉', price: 80, number: 6, id: '3'}
],
my_car: [],
selectAll: false,
},
methods: {
get_price() {
var total_price = 0;
for (i in this.my_car) {
total_price += this.my_car[i].price * this.my_car[i].number;
}
return total_price
},
selectHandler() {
if (this.my_car.length > 0) {
this.my_car = []
} else {
this.my_car = this.data_list
}
},
checkHandler() {
if (this.my_car.length == this.data_list.length) {
this.selectAll = true
} else {
this.selectAll = false
}
},
// 减少商品
j_goods(obj) {
if (obj.number <= 1) {
alert('不能再少了');
obj.number = 1
} else {
obj.number--
}
},
},
})
</script>
</body>
</html>
2、v-model之lazy、number、trim的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/vue.js"></script>
<div id="box">
<h1>lazy的使用</h1>
<p>使用v-model.lazy方式不会随着键盘输入直接在后面打印,而是失去焦点才会显示最终输入的数据</p>
请输入信息: <input type="text" v-model.lazy="mytext">
{{mytext}}
<h1>number的使用</h1>
<p>使用v-model.number方式会从头开始匹配数字,自动过滤掉其他非数字部分,如果开头是字母或其他就直接显示</p>
请输入信息: <input type="text" v-model.number="mynumber">
{{mynumber}}
<h1>trim的使用</h1>
<p>使用v-model.trim方式会自动过滤掉前后空格</p>
请输入信息: <input type="text" v-model.trim="mytrim">
{{mytrim}}
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
mytext: '',
mynumber: '',
mytrim: '',
},
methods: {},
})
</script>
</body>
</html>
3、fetch和axios
axios与fetch实现数据请求
fetch(不是所有浏览器都支持,谷歌浏览器支持)
XMLHttpRequest 是一个设计粗糙的 API,配置和调用方式非常混乱,而且基于事件的异步模型写起来不友好,兼容性不好
polyfill:https://github.com/camsong/fetch-ie8
vue项目跟后端交互,可以使用jquery+ajax实现
3.1、通过jquery+ajax实现vue和后端交互
3.1.1、后端代码
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/')
def index():
print('请求来了')
res = make_response('hello world')
# 处理跨域
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
3.1.2、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="js/vue.js"></script>
<div id="box">
<button @click="clickHandler">ajax+jquery方式加载flask后端数据</button>
<p>flask后端传递过来的数据: {{mydata}}</p>
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
mydata: '',
},
methods: {
clickHandler() {
$.ajax({
url: 'http://127.0.0.1:5000/ ',
method: 'get',
success: data => {
console.log(data); // hello world
this.mydata = data;
},
})
}
},
})
</script>
</body>
</html>
3.2、通过fetch实现vue和后端交互
3.2.1、后端代码
from flask import Flask, make_response, jsonify
app = Flask(__name__)
@app.route('/get_userinfo')
def getinfo():
res = jsonify({'name': 'allen', 'age': 18})
res = make_response(res)
# 处理跨域
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
3.2.2、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/vue.js"></script>
<div id="box">
<button @click="clickHandler">fetch方式加载flask后端数据</button>
<p>flask后端传递过来的数据: </p>
<p>用户名: {{name}}</p>
<p>年龄: {{age}}</p>
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
name: '',
age: ''
},
methods: {
clickHandler() {
fetch('http://127.0.0.1:5000/get_userinfo').then(response => {
return response.json()
}).then(json => {
console.log('从后端获取的json数据: ', json);
this.name = json.name;
this.age = json.age;
}).catch(ex => {
cosnole.log('出现异常', ex);
})
}
},
})
</script>
</body>
</html>
3.3、通过axios实现vue和后端交互
3.3.1、film.json
{"status":0,"data":{"films":[{"filmId":5241,"name":"海兽之子","poster":"https://pic.maizuo.com/usr/movie/b41a1016400f00f2b1c2c3e6b4e40e71.jpg","actors":[{"name":"渡边步","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/b9ef78c5531f1d8f9ff7c457e695646c.jpg"},{"name":"芦田爱菜","role":"安海琉花","avatarAddress":"https://pic.maizuo.com/usr/movie/7fdc9dda0cd442cedebd489a6e48ddaf.jpg"},{"name":"石桥阳彩","role":"海","avatarAddress":"https://pic.maizuo.com/usr/movie/b83700ec7e695233eea84f15818dcbfb.jpg"},{"name":"浦上晟周","role":"空","avatarAddress":"https://pic.maizuo.com/usr/movie/476f07fb7bdb09d6ad08a8c76276afea.jpg"},{"name":"森崎温","role":"安格勒 Angrad","avatarAddress":"https://pic.maizuo.com/usr/movie/7f4238502d845f75cc088ae28cd2cbd8.jpg"}],"director":"渡边步","category":"动画","synopsis":"偶遇到神秘少年“海”(石桥阳彩 配音)和“空”(浦上晟周 配音)的这个炎炎夏天,是琉花(芦田爱菜 配音)暑期的正式开始。天真无邪的“海”,看透一切的“空”,海洋馆里发光的鱼群,对琉花来说都像是一场浪漫的约定如期而至。","filmType":{"name":"2D","value":1},"nation":"日本","language":"","videoId":"","premiereAt":1605830400,"timeType":3,"runtime":112,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false},{"filmId":5270,"name":"南拳之英雄崛起","poster":"https://pic.maizuo.com/usr/movie/375327924cbe12ec09861919b86f039d.jpg","actors":[{"name":"吴俊贤","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/88f4a0499bb3cb54ea0cc5e11fc5eb09.jpg"},{"name":"王婉中","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/571e8f0fed6296a4e6624dd2fb6340bc.jpg"},{"name":"陈浩民","role":"刘远拔","avatarAddress":"https://pic.maizuo.com/usr/movie/cd068140ce67f86e067576f343c9a8d7.jpg"},{"name":"戚云鹏","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/eaf70115bfb07d5cf4f774d2ce0923a6.jpg"},{"name":"邵老五","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/1bec3de7a2899f1d62f5f7d519547b68.jpg"}],"director":"吴俊贤","category":"剧情|动作","synopsis":"江湖传言威震洪为了南拳宗师名号杀了严石崇,而威震洪之徒刘远跋不信此事,决定为其正名。寻师过程中意外结识严石崇之女严霜,二人从排斥到相互扶持合作,一步步探寻事件真相,发现并打败了最后的操纵者。","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1607904000,"timeType":3,"runtime":104,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false},{"filmId":5276,"name":"灌篮高手的契约","poster":"https://pic.maizuo.com/usr/movie/738bd3c5c666659f6f49847c88d62ddd.jpg","actors":[{"name":"王岽鉴","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/409ee4dd31c3bbb13f2ad96ac125fdca.jpg"},{"name":"叶文灏","role":"江译","avatarAddress":"https://pic.maizuo.com/usr/movie/6ce55417120a1d950ecc895ef89d7e84.jpg"},{"name":"李觅尔","role":"林晓东","avatarAddress":"https://pic.maizuo.com/usr/movie/dd51e89ddf62fb784900534ae1f14f2b.jpg"},{"name":"赵哲晨","role":"梁羽","avatarAddress":"https://pic.maizuo.com/usr/movie/ab423d79c169f786a5a6b1295e58fa90.jpg"},{"name":"钟艺云","role":"胡心儿","avatarAddress":"https://pic.maizuo.com/usr/movie/35395ac6833946aa5793e6770375c7ca.jpg"}],"director":"王岽鉴","category":"运动|青春","synopsis":"本片通过女性视角讲述高中篮球赛季的故事,并引出两代人的情感恩怨。一个被阴谋笼罩的赛季,一支残缺不全的球队,一位对篮球怀有绝对执念的美少女,一位天赋异禀的篮球少年,他们同时被一份契约裹挟在一起。自私与恐惧,奉献与背叛。一生一次的比赛能否不留遗憾?父辈的悲剧是否还要重演?队友的信任是否被辜负?原生家庭的阴霾能否消?敬请期待“灌篮高手的契约”。","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1607644800,"timeType":3,"runtime":98,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false},{"filmId":5283,"name":"半条棉被","poster":"https://pic.maizuo.com/usr/movie/180fb81b87333addeab1c1e05c463789.jpg","actors":[{"name":"孟奇","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/0eaf221041cbf01ab3b6004564a8bb5a.jpg"},{"name":"陶慧","role":"董秀云","avatarAddress":"https://pic.maizuo.com/usr/movie/7d6f7f8f5c0d9ac8296781234157cece.jpg"},{"name":"童蕾","role":"徐解秀","avatarAddress":"https://pic.maizuo.com/usr/movie/1fea9eafce6c7bfee06bfcd85f094425.jpg"},{"name":"陈衍利","role":"王秋兰","avatarAddress":"https://pic.maizuo.com/usr/movie/21212608d87425ca62336b23f91aba01.jpg"}],"director":"孟奇","category":"战争|剧情","synopsis":"大雨滂沱的秋夜,途径小山村的三名女红军在一处屋檐下避雨,一杆枪,两只桶,一个电台,一床棉被是她们的全部,而屋内一名小脚女人带着生病的孩子正注视着这一切,从此刻起,她们的命运将因为这床充满故事,充满期待的棉被而紧密相连……","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1599177600,"timeType":3,"runtime":97,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false},{"filmId":5212,"name":"未来的未来","poster":"https://pic.maizuo.com/usr/movie/1b482779c0ed44b02e468a3e3fae7eb3.jpg","actors":[{"name":"细田守","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/dfecce60c85b6bab3e2e3b8a689e377f.jpg"},{"name":"真田麻美","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/ae059d556394d5e00bf6ca1b709957c9.jpg"},{"name":"中村正","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/4a504b8600437dff057e30c2d97ffc85.jpg@2500w_2500h_1l_0e"},{"name":"山像香","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/3fc09be2b3457acc5b232f824f20cfd9.jpg"},{"name":"玉川纱己子","role":"演员","avatarAddress":"https://pic.maizuo.com/usr/movie/2d45232c653aea80f714acd043e60fdc.jpg"}],"director":"细田守","category":"动画|奇幻|家庭","synopsis":"在东京的宁静角落,生活着幸福的三口之家。而今,这户人家迎来了新生命。爱撒娇的儿子小君,迎来刚出生的妹妹,他感到父母对自己的爱被妹妹夺走,正在恼怒之时,小君却在庭院中遇到来自“未来”的妹妹,并开启了穿越之旅,在家族之树的时空中,他和“未来”的妹妹一起,与童年的母亲、年轻时代的曾外祖父、甚至未来的自己相遇,在冒险中,小君领悟到不同形式的“家族之爱”。","filmType":{"name":"2D","value":1},"nation":"日本","language":"","videoId":"","premiereAt":1604620800,"timeType":3,"runtime":98,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false},{"filmId":5224,"name":"小破孩大状元","poster":"https://pic.maizuo.com/usr/movie/b292cf69cae8dbc4e303cb5efa1a89a6.jpg","actors":[{"name":"拾荒","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/0c3cb928aba78b87403b6421386fa2e3.png"},{"name":"郑成峰","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/2ee70842221a54fc246bc965051e0a50.jpg"}],"director":"拾荒|郑成峰","category":"喜剧|动画|奇幻","synopsis":"穷酸秀才小破孩进京赶考,路遇“彪悍女侠”、江湖骗子、冷酷杀手等人,引出一系列啼笑皆非、荒唐无语的故事,一路有惊无险,竟然考中了大状元。随后,小破孩凭借非凡的绝学,收编了一彪人马杀奔古城洛阳,破获一个“天大”的奇案。","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1605312000,"timeType":3,"runtime":86,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false},{"filmId":5284,"name":"神剑奇缘","poster":"https://pic.maizuo.com/usr/movie/a833d23987835b6e4f66b523e18805eb.jpg","actors":[{"name":"杨永","role":"导演","avatarAddress":"https://pic.maizuo.com/usr/movie/efdab0e0e9b60b7fc47b63cace345a5d.jpg"},{"name":"袁伟龙","role":"无念","avatarAddress":"https://pic.maizuo.com/usr/movie/db11464e97a61e22cda6f993f2b7409f.jpg"},{"name":"王飞","role":"小白","avatarAddress":"https://pic.maizuo.com/usr/movie/3743283ee953501ef56845737f9969e4.jpg"},{"name":"秦琴","role":"如云","avatarAddress":"https://pic.maizuo.com/usr/movie/e5d765528f375551dbef3a2d84cd9ea7.jpg"},{"name":"赵华","role":"玲霜","avatarAddress":"https://pic.maizuo.com/usr/movie/5cecb50a4fec7de3535d1ff903f85cf7.jpg"}],"director":"杨永","category":"动作|奇幻","synopsis":"讲述了百年前仙魔大战,修仙门死伤无数,清微派灵光子为抢夺上古神兵轩辕剑勾结魔界教主幻影,设计陷害无念道长,又加害天心派掌门李素玉。最终魔君幻影身受重伤逃去幻海界。轩辕剑下落不明,传闻被上古大神封存在峨眉群山之中","filmType":{"name":"2D","value":1},"nation":"中国大陆","language":"","videoId":"","premiereAt":1607385600,"timeType":3,"runtime":90,"grade":"7.2","item":{"name":"2D","type":1},"isPresale":true,"isSale":false}],"total":47},"msg":"ok"}
3.3.2、后端代码
import json
from flask import Flask, make_response, jsonify
app = Flask(__name__)
@app.route('/film')
def getfilm():
with open('film.json', 'rt', encoding='utf-8') as f:
dic = json.load(f)
res = jsonify(dic)
res = make_response(res)
# 处理跨域
res.headers['Access-Control-Allow-Origin'] = '*'
return res
if __name__ == '__main__':
app.run()
3.3.3、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="js/vue.js"></script>
<div id="box">
<button @click="clickHandler">axios方式加载flask后端数据</button>
<p>flask后端传递过来的数据: </p>
<ul>
<li v-for="item in data_list">
<p>电影名: {{item.name}}</p>
<p>电影类型: {{item.category}}</p>
<p>导演: {{item.director}}</p>
<p>评分: {{item.grade}}</p>
<p>图片: <img :src="item.poster" alt=""></p>
</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
data_list: [],
},
methods: {
clickHandler() {
axios.get('http://127.0.0.1:5000/film').then(res => {
console.log(res.data);
if (res.data.status == 0) {
this.data_list = res.data.data.films;
}
}).catch(err => {
console.log('出现错误: ', err)
})
}
},
})
</script>
</body>
</html>
4、计算属性
1、直接在{{}}中写js代码 html中尽量少写js代码
2、使用函数 {{函数()}} 使用多次会执行多次
3、使用计算属性 当作变量来使用,多次使用只会执行一次
4.1、通过计算属性来实现人名首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/vue.js"></script>
<div id="box">
<h1>将名字的首字母变成大写</h1>
<p>原始数据: {{name}}</p>
<h3>方式一: 直接在html中执行js代码</h3>
<p>修改后的数据(方式一): {{name.substring(0,1).toUpperCase() + name.substring(1)}}</p>
<h3>方式二: 在methods中定义函数修改名字,如果调用多次会重复执行,调用的时候加括号,如果不加括号就是放函数的代码在这</h3>
<p>修改后的数据(方式二): {{upperName()}}</p>
<p>{{upperName()}}</p>
<p>{{upperName()}}</p>
<h3>方式三: 在computed中定义函数修改名字,如果调用多次不会重复执行,调用的时候不加括号</h3>
<p>修改后的数据(方式二): {{getName}}</p>
<p>{{getName}}</p>
<p>{{getName}}</p>
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
name: 'allen',
},
methods: {
upperName() {
console.log('我执行了');
return this.name.substring(0, 1).toUpperCase() + this.name.substring(1);
},
},
computed: {
getName() {
console.log('我执行了');
return this.name.substring(0, 1).toUpperCase() + this.name.substring(1);
},
},
})
</script>
</body>
</html>
4.2、通过计算属性重写过滤小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/vue.js"></script>
<div id="box">
请输入数据: <input type="text" v-model="myinput">{{myinput}}
<ul>
<li v-for="item in new_arr">{{item}}</li>
</ul>
</div>
<script>
var vm = new Vue({
el: '#box',
data: {
myinput: '',
arr: ['aabbc', 'abc', 'aabcd', 'ccdd', 'bbcc'],
},
computed: {
new_arr() {
return this.arr.filter(item => {
return item.indexOf(this.myinput) > -1
})
}
},
})
</script>
</body>
</html>
5、Mixins
混入 (mixins) 是一种分发 Vue组件中可复用功能的非常灵活的方式,混入对象可以包含任意组件选项,当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项
6、虚拟dom与diff算法 key的作用
6.1、Vue2.0 v-for 中 :key的作用
不只是vue,react中在执行列表渲染时也会要求给每个组件添加key这个属性
key简单点来说就是唯一标识,就像ID一样具有唯一性
vue和react都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面,而隐藏在背后的原理便是其高效的Diff算法
只做同层级的对比
按照key值比较,出现新的key就插入
同组件对比
6.2、虚拟DOM的diff算法
6.3、具体实现
6.3.1、把树按照层级分解
6.3.2、同key值比较
6.3.3、同组件对比
<div id="box">
<div v-if="isShow">111</div>
<p v-else>222</p>
<!--
{tag:div,value:111}
{tag:p,value:222}
直接不比较,直接删除div,新增p
-->
<div v-if="isShow">111</div>
<div v-else>222</div>
<!--
{tag:div,value:111}
{tag:div,value:222}
比较都是div,只替换文本内容
-->
</div>
Vue中的虚拟DOM及diff算法详解:https://segmentfault.com/a/1190000020170310
7、组件化开发
7.1、组件的定义及作用
扩展 HTML 元素,封装可重用的代码,目的是为了复用
例: 有一个轮播图,可以在很多页面中使用,一个轮播图有js,css,html
组件把js,css,html放到一起,有逻辑,有样式,有html
工程化以后,一个组件就是一个 xx.vue
element ui 其实就是写了一堆好看的组件,如果需要使用我们可以直接拿过来用
7.2、组件分类
1、全局组件
2、局部组件
7.3、定义全局组件及使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/vue.js"></script>
<div id="box">
<div @click="clickHandle">我是根组件的div</div>
<div>
<child></child>
<ul>
<li v-for="item in 4">{{item}}</li>
</ul>
<child></child>
</div>
</div>
<script>
// 定义一个全局组件
Vue.component('child', {
template: `
<div>
<div style="background: red;" @click="clickHandler">我是头部</div>
<div v-if="isShow">显示/消失</div>
</div>
`,
methods: {
clickHandler() {
console.log('我被点击了');
this.isShow = !this.isShow;
},
},
data() {
return {
isShow: true,
}
},
});
var vm = new Vue({
el: '#box',
data: {},
methods: {
clickHandle() {
console.log('根组件被点击了');
}
},
})
</script>
</body>
</html>