一、v-for练习
- v-for 是列表渲染的指令;
请用如下数据生成一个列表
{
fruits: [
{
name: '苹果',
color: ['green', 'yellow']
},
{
name: '香蕉',
color: ['red', 'green', 'yellow']
},
{
name: '芒果',
color: ['green', 'yellow']
}
]
}
- vue 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<ul>
<!--要循环谁,就把 v-for 写在谁身上-->
<li v-for="(item, index) in fruits" :key="index">
{{index + 1}}{{item.name}}
<ul>
<li v-for="(color, cIndex) in item.color" :key="cIndex">{{cIndex + 1}} {{color}}</li>
</ul>
</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
fruits: [
{
name: '苹果',
color: ['green', 'yellow']
},
{
name: '香蕉',
color: ['red', 'green', 'yellow']
},
{
name: '芒果',
color: ['green', 'yellow']
}
]
}
});
// vue 是数据映射视图,数据的结构就决定了 html 的结构;
</script>
</body>
</html>
二、vue中的事件绑定
使用 v-on 指令
- Vue 使用 v-on 绑定事件,无需获取 DOM,直接在模板中绑定
<button v-on:click="fn($event, 1, 2)">点我试试</button>
事件函数
- Vue 的事件函数写在 methods 属性中
let obj = {
el: '#app',
data: {
msg: '你很帅'
},
methods: {
fn (a, b, c) {
// 1. 如果在绑定时,fn 不带小括号,那么函数会默认接收一个事件对象作为参数
// 2. 如果绑定时带有小括号,那么默认不接收事件对象
// 3. 如果既要事件对象,又要传递参数,需要在小括号中写一个 $event 用来标识事件对象,后面才是真正的参数;
console.log(a);
console.log(b);
console.log(c);
}
}
}
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button v-on:click="fn($event, 1, 2)">点我试试</button>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
msg: '你很帅'
},
methods: {
fn (a, b, c) {
// 1. 如果在绑定时,fn 不带小括号,那么函数会默认接收一个事件对象作为参数
// 2. 如果绑定时带有小括号,那么默认不接收事件对象
// 3. 如果既要事件对象,又要传递参数,需要在小括号中写一个 $event 用来标识事件对象,后面才是真正的参数;
console.log(a);
console.log(b);
console.log(c);
}
}
});
// v-on:事件名 绑定事件
// v-on 可以加简写成@
</script>
</body>
</html>
三、事件修饰符
事件修饰符是什么?
- 为了方便 Vue 的事件处理,Vue 中增加了事件修饰符;
- 用法:v-on:事件名.修饰符
示例:
<a href="/" v-on:click.prevent="fn">请点击</a>
常见的事件修饰符
- 事件修饰符
- .prevent 阻止元素的默认行为
- .stop 阻止事件冒泡
- .capture 事件在捕获阶段触发
- .once 事件只执行一次
- .self 只有触发自身的事件才会触发
- 键盘事件修饰符:
- .enter 回车
- .esc 退出
- .delete 退格
- .space 空格
- .tab tab键
- .left 左
- .right 右
- .up 上
- .down 下
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#app {
font-size: 40px;
color: red;
}
</style>
</head>
<body>
<div id="app">
<div @click="parent">
parent
<div @click="child">
child
<div @click.stop="grandchild">
grandchild
</div>
</div>
</div>
<a href="/" v-on:click.prevent="fn">请点击</a>
<input type="text" @keydown.up="add" v-model="num">
</div>
<script src="vue.js"></script>
<script>
// 事件修饰符
// .prevent 阻止元素的默认行为
// .stop 阻止事件冒泡
// .capture 事件在捕获阶段触发
// .once 事件只执行一次
// .self 只有触发自身的事件才会触发
// 键盘事件修饰符:
// .enter 回车
// .esc 退出
// .delete 退格
// .space 空格
// .tab tab键
// .left 左
// .right 右
// .up 上
// .down 下
let vm = new Vue({
el: '#app',
data: {
msg: '帅',
num: 1
},
methods: {
fn(e) {
console.log(1)
},
parent() {
console.log('parent');
},
child() {
console.log('child');
},
grandchild() {
console.log('grandchild')
},
add(e) {
this.num++; // 在方法中使用数据,需要使用 this.xxx 的方式获取,并且操作这些值,页面中的值也会跟着改变
console.log('加')
}
}
})
</script>
</body>
</html>
四、练习-简易 todoList
需求
- todoList 是待处理任务表,在 input 的框中输入一条任务,回车即可加入任务列表;在任务列表中每一行都有一个删除按钮,点击删除按钮即可从任务列表中删除该任务;
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" @keydown.enter="add" v-model="todo">
<ul>
<li v-for="(item, index) in todoList" :key="index">
{{item}} <button @click="remove(index)">删除</button>
</li>
</ul>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
todoList: [],
todo: ''
},
methods: {
add () {
// methods 里面的方法中的 this 都指向当前 Vue 的实例;
// 把用户输入的内容添加到数组中
this.todoList.push(this.todo);
this.todo = '';
},
remove(index) {
// Vue 是数据驱动的,想要移除某一个 li,只需要从 todoList 中删除对应的数据即可,Vue 是双向数据绑定,一旦数据发生变化,Vue 会按照最新的数据映射视图;
this.todoList.splice(index, 1);
}
}
})
</script>
</body>
</html>
五、过滤器
过滤器是什么?
过滤器:用于处理数据,但是并不会改变原来的数据的一种处理方式;
创建过滤器:
- 全局过滤器: Vue.filter(过滤器名字, 函数)
Vue.filter('toDollar', val => '$' + val);
- 局部过滤器
let obj = {
el: '#app',
filters: {
toFixed (val, num = 2) {
// 返回一个保留 num 位的数字
return val.toFixed(num);
},
toRMB(val) {
return '¥' + val;
}
}
};
let vm = new Vue(obj);
使用过滤器
{{1.22222 | toFixed | toRMB}} <br>
{{1.22222 | toFixed(3)}} <br>
{{1.22222 | toFixed | toRMB}} <br>
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{1.22222 | toFixed | toRMB}} <br>
{{1.22222 | toFixed(3)}} <br>
{{1.22222 | toFixed | toRMB}} <br>
<!-- | 称为管道符,管道符会把其前面的值传给过滤器函数的第一个参数-->
<!--过滤器可以连续使用,后面过滤器的第一个参数是前面过滤器处理后的结果 -->
</div>
<script src="vue.js"></script>
<script>
// 过滤器:用于处理数据,但是并不会改变原来的数据的一种处理方式;
// 注册全局过滤器:这种过滤器在任何地方都能用
// Vue.filter(过滤器名字, 函数)
Vue.filter('toDollar', val => '$' + val);
// 局部过滤器:只能在当前组件可以使用
let vm = new Vue({
el: '#app',
filters: {
toFixed (val, num = 2) {
// 返回一个保留 num 位的数字
return val.toFixed(num);
},
toRMB(val) {
return '¥' + val;
}
}
})
</script>
</body>
</html>
六、radio 和 v-model
单选框中使用 v-model;会把这些绑定 sex 的分为一组,一次只能选中一个
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--单选框中使用 v-model;会把这些绑定 sex 的分为一组,一次只能选中一个-->
<label>男 <input type="radio" v-model="sex" value="男"></label>
<label>女 <input type="radio" v-model="sex" value="女"></label>
<label>其他 <input type="radio" v-model="sex" value="其他"></label>
<br>
{{sex}}
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
sex: '男'
}
})
</script>
</body>
</html>
七、checkbox
- 在复选框中,如果只有一个,会将值默认转换成布尔值;
<label>游泳:<input type="checkbox" v-model="val" /></label>
- 如果多个 checkbox 绑定同一个值,vue 会把选中的值放到一个数组中
<label>睡觉:<input type="checkbox" v-model="hobby" value="睡觉" /></label>
<label>吃饭:<input type="checkbox" v-model="hobby" value="吃饭" /></label>
<label>约会:<input type="checkbox" v-model="hobby" value="约会" /></label>
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--在复选框中,如果只有一个,会将值默认转换成布尔值-->
<label>游泳:<input type="checkbox" v-model="val" /></label>
<br>
<!--如果多个 checkbox 绑定同一个值,Vue 会把选中的值放到一个数组中-->
<label>睡觉:<input type="checkbox" v-model="hobby" value="睡觉" /></label>
<label>吃饭:<input type="checkbox" v-model="hobby" value="吃饭" /></label>
<label>约会:<input type="checkbox" v-model="hobby" value="约会" /></label>
<br>
<div>
{{hobby}}
</div>
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
val: 1,
hobby: []
}
})
</script>
</body>
</html>
八、select
- select v-model 的值和下面 option 的值相同时会选中该 option;
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select v-model="hobby">
<option value="1">篮球</option>
<option value="2">羽毛球</option>
<option value="3">乒乓球</option>
</select>
<br>
{{hobby}}
</div>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
hobby: '3'
}
})
</script>
</body>
</html>
九、axios-vue
在 Vue 中使用 axios
- 在 Vue 中使用 ajax 请求数据,一般放到 created 钩子函数中
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item, index) in arr" :key="index">
{{item.name}}
<ul>
<li v-for="(sItem, sIndex) in item.list" :key="sIndex">
{{sItem}}
</li>
</ul>
</li>
</ul>
</div>
<script src="axios.js"></script>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
arr: []
},
created () {
// 当 Vue 的实例创建成功以后会执行这个函数,Vue 中所有的 ajax 请求都在这里发送
console.log(this); // this 是 vm 的实例
this.getData(); // this.getData() 就是 methods 中的 getData() 方法
},
methods: {
getData() {
axios.get('list.json').then(({data}) => {
this.arr = data; // 我们直接把 arr 赋值成一个新的数组,因为 Vue 是响应式的,会自动更新页面
}).catch(e => {
console.log(e)
})
}
}
})
</script>
</body>
</html>
十、bootstrap
bootstrap 是 css 框架,依靠类名来控制 css 样式;
- bootstrap 采用的是栅格布局,把页面宽度分为12份
- bootstrap使用类名控制页面的样式
- .container 容器元素,左右居中
- .row 行
- .col-lg-数字 大屏幕
- .col-md-数字 中等屏幕
- .col-sm-数字 小屏幕
- .col-xs-数字 最小屏幕
- 示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
<style>
.row div {
border: 1px solid #000;
}
</style>
</head>
<body>
<!--bootstrap 采用的是栅格布局,把页面宽度分为12份-->
<!--bootstrap 使用类名控制页面的样式-->
<!--
.container 容器元素,左右居中
.row 行
.col-lg-x 大屏幕
.col-md-x 中等屏幕
.col-sm-x 小屏幕
.col-xs-x 最小屏幕
-->
<div class="container">
<div class="row">
<div class="col-md-3">哈哈</div>
<div class="col-md-3">嘿嘿</div>
<div class="col-md-6">呵呵</div>
<div class="col-md-12">嘻嘻</div>
</div>
<table class="table table-bordered table-hover table-striped">
<tr>
<td>
第一项
</td>
<td>
第二项
</td>
<td>
第三项
</td>
</tr>
<tr>
<td>
第一项
</td>
<td>
第二项
</td>
<td>
第三项
</td>
</tr>
<tr>
<td>
第一项
</td>
<td>
第二项
</td>
<td>
第三项
</td>
</tr>
<tr>
<td>
第一项
</td>
<td>
第二项
</td>
<td>
第三项
</td>
</tr>
</table>
</div>
</body>
</html>
十一、练习-购物车案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
<div id="app">
<!--caption 只能放在 table 中使用:表头-->
<!--bootstrap-->
<div class="container">
<div class="row">
<h2 class="text-center text-danger">珠峰购物车</h2>
<table class="table table-bordered">
<tr>
<td>
全选 <input type="checkbox" v-model="checkAll" @change="changeAll"/>
</td>
<td>
商品
</td>
<td>
单价
</td>
<td>
数量
</td>
<td>
小计
</td>
<td>
操作
</td>
</tr>
<tr v-for="(product, index) in products" :key="index">
<!-- {
"isSelected": true,
"productCover": "https://img10.360buyimg.com/cms/s80x80_jfs/t6094/107/710811867/382815/4d54717/592bf165N755a88f0.jpg",
"productName": "深入浅出Node.js",
"productInfo": "颜色:Node.js学习",
"productPrice": 57.8,
"productCount": 3
}-->
<td><input type="checkbox" v-model="product.isSelected" @change="changeOne"></td>
<td>
<img :src="product.productCover" :title="product.productName" alt="">
{{product.productInfo}}
</td>
<td>
{{product.productPrice}}
</td>
<td>
<input type="number" v-model="product.productCount" min="1"/>
</td>
<td>
{{product.productPrice * product.productCount | toFixed(2)}}
</td>
<td>
<button class="btn btn-danger" @click="remove(product)">删除</button>
</td>
</tr>
<tr>
<td colspan="6">
总价格:{{sum() | toFixed}}
</td>
</tr>
</table>
</div>
</div>
</div>
<script src="axios.js"></script>
<script src="vue.js"></script>
<script>
let vm = new Vue({
el: '#app',
data: {
products: [],
checkAll: true
},
filters: {
toFixed(val, num = 2) {
return '¥' + val.toFixed(num)
}
},
created() {
this.getData();
},
methods: {
getData() {
axios.get('carts.json').then(({data}) => {
this.products = data;
})
},
remove(val) {
// val 点击时删除的 product
this.products = this.products.filter(item => item !== val);
},
changeAll() {
// 如果全选为 true,即 this.checkAll 为 true,下面的商品的 checkbox 都要选中,如果是全选是 false,那么商品的 checkbox 也是 false
this.products.forEach(item => item.isSelected = this.checkAll)
},
changeOne() {
// 点击每一个 input 的复选框时,去校验是否有是所有的 product 中的 isSelected 都为 true,如果都是 true,那么 checkAll 结果也是 true,如果有一个是 false,那么 checkAll 就是 false,使用 every 方法
this.checkAll = this.products.every(item => item.isSelected);
},
sum() {
/* let total = 0;
this.products.filter(item => item.isSelected).forEach(item => total += (item.productPrice * item.productCount));
return total;*/
return this.products.filter(item => item.isSelected).reduce((prev, next) => {
return prev + next.productPrice * next.productCount;
}, 0)
}
}
})
</script>
</body>
</html>