1.购物车案例
1.1 基本购物车
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
<style>
table, td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<h1>购物车</h1>
<table>
<tr>
<td>商品名称</td>
<td>价格</td>
<td>数量</td>
<td>选择</td>
</tr>
<tr v-for="item in dataList">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td>{{item.number}}</td>
<td><input type="checkbox" v-model="choice" :value="item"></td>
</tr>
</table>
选中的商品是:{{choice}}
<br>
商品价格:{{getPrice()}}
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
dataList: [
{name: '今瓶没', price: 99, number: 2},
{name: '西柚记', price: 59, number: 1},
{name: '水壶转', price: 89, number: 5},
],
choice: []
},
methods: {
getPrice() {
let total = 0
// js的循环方式:
// 1.For循环
// for (let i = 0; i < this.choice.length; i++) {
// total = total + this.choice[i].price * this.choice[i].number
// }
// 2.For In 循环 (i:对象就是键,数组就是索引)
// for (let i in this.choice) { // 这里的 i 是索引
// total += this.choice[i]['number'] * this.choice[i]['price']
// }
// 3.For Of 循环 (v:对象值本身) --ES6语法
// for (let v of this.choice) { // 这里的 v 是数组中每一个对象
// total += v.price*v.number
// }
// 4.数组的forEach() 为每个数组元素调用一次函数(回调函数)
this.choice.forEach((value, index, array) => { # 值,索引,数组本身
total += value.price * value.number
})
return total
}
},
})
</script>
</html>
1.2 全选全不选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
<style>
table, td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<h1>购物车</h1>
<table>
<tr>
<td>商品名称</td>
<td>价格</td>
<td>数量</td>
<td>选择 <input type="checkbox" v-model="checkAll" @change="handleAll"></td>
</tr>
<tr v-for="item in dataList">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td>{{item.number}}</td>
<td><input type="checkbox" v-model="choice" :value="item" @change="checkOne"></td>
</tr>
</table>
选中的商品是:{{choice}}
<br>
商品价格:{{getPrice()}}
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
dataList: [
{name: '今瓶没', price: 99, number: 2},
{name: '西柚记', price: 59, number: 1},
{name: '水壶转', price: 89, number: 5},
],
choice: [],
checkAll: false
},
methods: {
getPrice() {
let total = 0
for (v of this.choice) { // 这里的 v 是数组中每一个对象
total += v.price * v.number
}
return total
},
handleAll() {
if (this.checkAll) {
this.choice = this.dataList
} else {
this.choice = []
}
},
checkOne() {
if (this.choice.length == this.dataList.length) {
this.checkAll = true
} else {
this.checkAll = false
}
}
},
})
</script>
</html>
1.3 数量加入加减
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
<style>
table, td {
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<h1>购物车</h1>
<table>
<tr>
<td>商品名称</td>
<td>价格</td>
<td>数量</td>
<td>选择 <input type="checkbox" v-model="checkAll" @change="handleAll"></td>
</tr>
<tr v-for="item in dataList">
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td><button @click="handleJ(item)">-</button>{{item.number}}<button @click="item.number++">+</button></td>
<td><input type="checkbox" v-model="choice" :value="item" @change="checkOne"></td>
</tr>
</table>
选中的商品是:{{choice}}
<br>
商品价格:{{getPrice()}}
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
dataList: [
{name: '今瓶没', price: 99, number: 2},
{name: '西柚记', price: 59, number: 1},
{name: '水壶转', price: 89, number: 5},
],
choice: [],
checkAll: false
},
methods: {
getPrice() {
let total = 0
for (v of this.choice) { // 这里的 v 是数组中每一个对象
total += v.price * v.number
}
return total
},
handleAll() {
if (this.checkAll) {
this.choice = this.dataList
} else {
this.choice = []
}
},
checkOne() {
if (this.choice.length == this.dataList.length) {
this.checkAll = true
} else {
this.checkAll = false
}
},
handleJ(item){
if(item.number<=1){
alert('受不了了,不能再少了')
}else {
item.number--
}
}
},
})
</script>
</html>
2.v-model进阶
# v-model的修饰符
lazy:等待input框的数据绑定后,发生改变后再变化
number:数字开头,只保留数字,后面的字母不保留;字母开头,都保留
trim:去除首尾的空格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- lazy的使用:<input type="text" v-model.lazy="msg"> {{msg}}-->
<!-- number的使用:<input type="text" v-model.number="msg"> {{msg}}-->
trim的使用:<input type="text" v-model.number="msg"> {{msg}}
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
msg:''
},
methods: {
},
})
</script>
</html>
3.生命周期钩子
beforeCreate 创建Vue实例之前调用
created 创建Vue实例成功后调用(可以在此处发送异步请求后端数据) ******
beforeMount 渲染DOM之前调用
mounted 渲染DOM之后调用
beforeUpdate 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
updated 重新渲染完成之后调用
beforeDestroy 销毁之前调用
destroyed 销毁之后调用
# 重点:
1 created:在这个里面向后端发送请求,获取数据
2 mounted:
2.1 定时任务 每隔3s执行一次
this.t = setInterval(function () {
console.log('daada')
}, 3000)
# 定时操作的应用场景:可以设置成 间隔不断的 朝后端发送 http请求,以达到实时更新的情况。******
2.2 延迟任务(3s后执行该任务)
setTimeout( ()=> {
console.log('3s后执行')
# 3s后执行这个代码
}, 3000)
3 destroyed:
3.1关掉定时器
clearInterval(this.t)
t= null # 保险起见,并把定时器设置空
4.发送ajax请求
# axios: 第三方模块,专门发送Ajax请求
是一个基于 promise 的网络请求库,可以用于浏览器和 node.js
# 语法
axios
.get('http://127.0.0.1:5000/')
.then( response =>{this.info = response} ) // 请求成功处理 (响应回来的是对象,数据在.data中)
.catch( function (error) { // 请求失败处理
console.log(error);
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跟后端交互</title>
<script src="./js/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<button @click="handleClick">点我看美女</button>
<br>
我的名字是:{{name}}
<br>
我的年龄是:{{age}}
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
name:'',
age:0
},
methods:{
handleClick(){
// 会出跨域问题----使用 CORS 允许跨源访问:原生django响应,添加响应头***
axios.get('http://127.0.0.1:5000/').then(res=>{
console.log(res.data)
this.name=res.data.name
this.age=res.data.age
})
//
}
}
})
</script>
</html>
# 允许跨源访问--添加响应头
response["Access-Control-Allow-Origin"] = "*"
4.1 加载电影
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跟后端交互</title>
<script src="./js/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<ul>
<li v-for="item in dataList">
<p>电影标题:{{item.name}}</p>
<p>电影主演:{{item.director}}</p>
<img :src="item.poster" alt="">
</li>
</ul>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
dataList:[]
},
created(){
axios.get('http://127.0.0.1:5000/').then(res=>{
console.log(res.data)
this.dataList=res.data.data.films // 特别注意:后端返回的是json格式字符串,注意数据类型问题
// this.dataList = JSON.parse(res.data).data.films
})
}
})
</script>
</html>
5.计算属性
# 格式:
computed:{
方法函数
}
# 计算属性 Vs 方法 :
不同的是计算属性是基于它们的响应式依赖进行缓存的。
只在相关响应式依赖发生改变时它们才会重新求值。
这就意味着只要变量还没有发生改变,多次访问 该计算属性会立即返回之前的计算结果,而不必再次执行函数。
5.1 基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跟后端交互</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" v-model="msg">
<br>
1.直接在插值中写代码:
{{msg.substring(0,1).toUpperCase()+msg.substring(1)}}
<br>
2.写成一个函数:
{{getMsg()}}
{{getMsg()}}
<br>
3.使用计算属性
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
{{getCMsg}}
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
msg:''
},
methods:{
getMsg(){
// console.log('我执行了')
return this.msg.substring(0,1).toUpperCase()+this.msg.substring(1)
}
},
computed:{
getCMsg(){
console.log('我执行了')
return this.msg.substring(0,1).toUpperCase()+this.msg.substring(1)
}
}
})
</script>
</html>
5.2 重写过滤案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跟后端交互</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" v-model="msg">
<li v-for="item in new_data_list">{{item}}</li>
</div>
</body>
<script>
let vm = new Vue({
el: '#box',
data: {
msg: '',
datalist: ['aaa', 'abc', 'abcde', 'abcdef', 'bbb', 'bac'],
},
computed: {
new_data_list() {
return this.datalist.filter(item =>item.indexOf(this.msg) > -1)
}
}
})
</script>
</html>
6.组件化开发
# 1.自定义组件需要有一个根标签 (root element),一般包裹在一个div中
# 2.父子组件的data是无法直接共享 (需要通过其他方法)
# 3.组件可以有data,methods,computed....,但是data 必须是一个函数, 且必须是 return
# 4.组件名两种:驼峰体和短横线 都可以,但短横线(推荐,最好)
eg: Vue.component('my-component-name', { /* ... */ })
6.1 全局组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<child></child>
<hr>
<child></child>
</div>
</body>
<script>
// 定义一个名为child的全局组件
Vue.component('child', {
template: `
<div>
<h1>我是子组件</h1>
<br>
<button @click="handleClick">点我看美女--{{name}}</button>
</div>
`,
data() {
return {
name: 'lqz'
}
},
methods: {
handleClick() {
alert('美女,致命诱惑')
}
},
})
let vm = new Vue({
el: '#box',
data: {},
})
</script>
</html>
6.2 局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<child></child>
<hr>
</div>
</body>
<script>
// 定义一个全局组件,在全局组件中定义一个局部组件
Vue.component('child', {
template: `
<div>
<h1>我是子组件</h1>
<br>
<button @click="handleClick">点我看美女--{{name}}</button>
<hr>
<Header1></Header1>
</div>
`,
data() {
return {
name: 'lqz'
}
},
methods: {
handleClick() {
alert('美女,致命诱惑')
}
},
components:{
'Header1':{
template:`<h2>我是局部组件---{{msg}}</h2>`,
data(){
return {
msg:'SB'
}
},
methods:{},
}
}
})
let vm = new Vue({
el: '#box',
data: {},
})
</script>
</html>
6.3 动态组件
在一个多标签的界面中使用 is 属性 来切换不同的组件
# 通过指定 component标签的 is属性值,实现显示某个组件
<component :is="who"></component>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<span @click="who='index'">首页</span>  
<span @click="who='girl'">美女</span>  
<span @click="who='boy'">帅哥</span>
<hr>
<component :is="who"></component>
</div>
</body>
<script>
Vue.component('index', {
template: `
<div>
首页
</div>`,
})
Vue.component('girl', {
template: `<div>
美女
</div>`,
})
Vue.component('boy', {
template: `<div>
帅哥
</div>`,
})
let vm = new Vue({
el: '#box',
data: {
who: 'index'
},
methods: {}
})
</script>
</html>
6.4 keep-alive的使用
当在多个组件之间切换的时候,你有时会想保持这些组件的状态,
以避免反复重新渲染导致的性能问题,失活的组件所有内容将会被缓存
# 用一个<keep-alive> 元素将其动态组件包裹起来。
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
# 注意这个<keep-alive> 要求被切换到的组件都有自己的名字
7.组件通信
7.1 组件通信之父传子(通过自定义属性)
# 1.在子组件使用中:子组件上自定义属性,通过 属性指令 绑定好父组件的数据变量
eg: :mymsg="msg"
# 2.在子组件定义中:在props方法中注册该属性
eg: props:['mymsg','age']
# Prop验证: props 也可以是对象,key为属性名,value为属性的类型
eg: props:{mymsg:String}
# 3.在子组件定义中:template 就可以使用 该属性变量
eg: {{mymsg}}
# 注意:
HTML中的属性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。
这意味着当你使用DOM中的模板时,驼峰体命名的prop名,属性必须使用其等价的 短横线分隔命名:
<blog-post post-title="hello!"></blog-post>
Vue.component('blog-post', {
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
# 1.在组件上自定义属性,属性指令绑定好变量
<br>
<child :mymsg="msg" :age="age"></child>
<hr>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
# 3.template 就可以使用 该属性变量
<h1>我是子组件---从父组件传值过来--{{mymsg}}---{{age}}</h1>
<br>
<button @click="handleClick">点我看美女--{{name}}</button>
<hr>
</div>
`,
data() {
return {
name: 'lqz'
}
},
methods: {
handleClick() {
alert('美女,致命诱惑')
}
},
# 2.在props方法中注册该属性
props:['mymsg','age']
})
let vm = new Vue({
el: '#box',
data: {
msg:'我是父组件的数据',
age:999
},
})
</script>
</html>
7.2 父子通信之子传父(通过自定义事件)
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
思路:通过子组件触发父组件事件的执行,从而执行父组件事件对应的方法函数 (同时,也可以把子组件中的数据变量传入到父组件事件对应的方法上)
# 监听和触发事件的方法
使用 $on(eventName) 简写: @事件名 监听事件
使用 $emit(eventName) 触发事件
# 自定义事件 命名:
始终使用 kebab-case
# 步骤:
# 1.父组件通过自定义事件,绑定方法
<child v-if="isShow" @myevent="handleShow"></child>
# 2.子组件触发父组件事件的执行,把子组件中的变量b,传入到父组件事件对应的方法上
this.$emit('myevent',this.b)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<br>
# 1.父组件通过自定义事件,绑定方法
<child v-if="isShow" @myevent="handleShow"></child>
<hr>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
<h1>我是子组件</h1>
<br>
<button @click="handleClick">点我消失</button>
<hr>
</div>
`,
data() {
return {
b: false
}
},
methods: {
handleClick() {
# 2.子组件触发父组件事件的执行,把子组件中的变量b,传入到父组件事件对应的方法上
this.$emit('myevent',this.b)
}
},
})
let vm = new Vue({
el: '#box',
data: {
isShow: true,
},
methods:{
handleShow(b){
this.isShow=b
}
}
})
</script>
</html>
7.3 ref属性
# Vue支持:给所有的标签,提供ref属性
ref= '属性值'
# Vue中 就可以通过 this.$refs.属性值 拿到
-若ref在普通标签上,拿到的就是普通标签本身
-若ref在子组件上,拿到的就是子组件对象
-通过组件对象,可直接获取,修改属性
-直接执行方法,传值,返回值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
<input type="text" ref="myinput" name="lqz">
<br>
<child ref="mychild"></child>
<hr>
<button @click="handleClick">点我试一下</button>
</div>
</body>
<script>
// 定义一个全局组件,在全局组件中定义一个局部组件
Vue.component('child', {
template: `
<div>
<h1 v-if="b">我是子组件</h1>
<br>
<button>点我消失和显示</button>
<hr>
</div>
`,
data() {
return {
b: true
}
},
methods: {
handle1(msg){
// alert(msg)
return 'lqz'
}
},
})
let vm = new Vue({
el: '#box',
data: {},
methods: {
handleClick() {
// 若ref在普通标签上,拿到的就是普通标签本身
console.log(this.$refs.myinput)
// 若ref在子组件上,拿到的就是子组件对象
console.log(this.$refs.mychild)
// 修改子组件的数据
this.$refs.mychild.b = !this.$refs.mychild.b
// 调用子组件的方法
let res=this.$refs.mychild.handle1('致命诱惑')
console.log(res)
}
}
})
</script>
</html>
7.4 事件总线(不同层级的组件通信)
问题:若是不同层级的组件通信,再采用父传子、子传父的形式就比较麻烦。
思路:(观察者模式)
新建一个vue对象,是一条总的处理线;
在该总线上,不同层级的组件去监听(订阅)和触发总线的事件,从而达到通信效果。
# 很少用了,最简单的方式直接使用 ref形式就可以
# 例:两个全局组件通信
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件化开发</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="box">
<myhead></myhead>
<hr>
<myhead1></myhead1>
</div>
</body>
<script>
// 定义一个事件总线
let bus = new Vue()
Vue.component('myhead', {
template: `
<div>
<h4>我是组件一</h4>
<h4>另一个组件的数据:{{ msg }}</h4>
</div>
`,
data() {
return {
msg: ''
}
},
methods: {},
mounted() {
console.log('当前组件挂载后执行')
// 组件一:监听(订阅) suibian事件
bus.$on('suibian', (item) => {
console.log('收到了另一个组件的数据:', item)
this.msg = item
})
}
})
Vue.component('myhead1', {
template: `
<div>
<h4>我是组件二</h4>
<input type="text" v-model='name'>
<button @click="handleClick">点我传数据</button>
</div>
`,
data() {
return {
name: ''
}
},
methods: {
handleClick() {
// 组件二:触发suibian事件
bus.$emit('suibian', this.name)
}
},
})
let vm = new Vue({
el: '#box',
data: {},
methods: {}
})
</script>
</html>