一、v-for练习

  • v-for 是列表渲染的指令;

请用如下数据生成一个列表

  1. {
  2. fruits: [
  3. {
  4. name: '苹果',
  5. color: ['green', 'yellow']
  6. },
  7. {
  8. name: '香蕉',
  9. color: ['red', 'green', 'yellow']
  10. },
  11. {
  12. name: '芒果',
  13. color: ['green', 'yellow']
  14. }
  15. ]
  16. }
  • 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>