2.Vue系列 基础语法

模板语法

一、插值操作

将值插入到html的内容当中

Mustache(就是双大括号)
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2>hello {{name}}</h2>  //插入到标签中
        <h2>{{first_name}} {{last_name}</h2>  使用了两个mustache
        <h2>{{counter**2}}</h2>  //也可以是一个表达式
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            name: 'Vue',
            first_name: 'kang',
            last_name: 'pc',
            counter: 10
        }
    })
</script>
</html>

v-once

该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)

该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2>hello {{name}}</h2>
        <h2 v-once>hello {{name}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            name: 'kang'
        }
    })
</script>
</html>

v-html : 使用v-html指令,解析出HTML展示

该指令后面往往会跟上一个string类型

会将string的html解析出来并且进行渲染

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2>{{url}}</h2>
        <h2 v-html="url"></h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            url: '<a href="https://www.baidu.com">百度一下</a>'
        }
    })
</script>
</html>

v-text 比较少用,因为不灵活

v-text作用和Mustache比较相似:都是用于将数据显示在界面中

v-text通常情况下,接受一个string类型

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2>{{message}}, kang</h2>
        // message会把, kang覆盖
        <h2 v-text="message">, kang</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
        }
    })
</script>
</html>

v-pre 比较少用

v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法。比如下面的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2>{{message}}</h2>
        <h2 v-pre>{{message}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
        }
    })
</script>
</html>

第一个h2元素中的内容会被编译解析出来对应的内容

第二个h2元素中会直接显示{{message}}

v-cloak 斗篷 ,少用

在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>
<body>
    <div id="app">
        <h2>{{message}}</h2>
        <h2 v-cloak>{{message}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    setTimeout(() => {
        let app = new Vue({
        el: '#app',
        data: {
            message: '你好啊'
            }
        })
    },5000)
</script>
</html>

二、绑定属性

v-bind

前面我们学习的指令主要作用是将值插入到我们模板的内容当中。

但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定。

  1. 比如动态绑定a元素的href属性
  2. 比如动态绑定img元素的src属性

这个时候,我们可以使用v-bind指令:

作用:动态绑定属性

缩写::

预期:any (with argument) | Object (without argument)

参数:attrOrProp (optional)

v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值(这个学到组件时再介绍).

在开发中,有哪些属性需要动态进行绑定呢?还是有很多的,比如图片的链接src、网站的链接href、动态绑定一些类、样式等等.

比如通过Vue实例中的data绑定元素的src和href,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        //v-bind语法糖
        <a :href="url">百度一下</a><br>
        <img v-bind:src="img_url" alt="">
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            img_url: 'https://i0.hdslb.com/bfs/sycp/creative_img/202104/9a5cf4c28ff903549de5702668892dfd.jpg',
            url: 'https://i0.hdslb.com/bfs/feed-admin/6e73bf15d0348ee1313c15b3812b88a7a998513e.jpg',
        }
    })
</script>
</html>

v-bind绑定class

很多时候,我们希望动态的来切换class,比如:

  1. 当数据为某个状态时,字体显示红色。

  2. 当数据另一个状态时,字体显示黑色。

绑定class有两种方式:

  1. 对象语法

  2. 数组语法

绑定方式:对象语法

对象语法的含义是:class后面跟的是一个对象。

对象语法有下面这些用法:

用法一:直接通过{}绑定一个类
<h2 :class="{active: isActive}">Hello World</h2>

用法二:也可以通过判断,传入多个值
<h2 :class="{active: isActive, line: isLine}">Hello World</h2>

用法三:和普通的类同时存在,并不冲突
注:如果isActive和isLine都为true,那么会有title/active/line三个类
<h2 class="title" :class="{active: isActive, line: isLine}">Hello World</h2>

用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
    <style>
        .isActive{
            color: red;
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- <h2 class="title" :class="{active: isActive,line:isLine}">{{message}}</h2> -->
        <!-- <button @click="f">按钮</button> -->
        <h3 class="title" :class="classStyle">{{message}}</h3>
        <button @click="btn_click">点一下</button>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: '你好呀',
            lst: [1,2],
            classStyle: {
                isActive: true,
                isLine: true,  
            }      
        },
        methods: {
            // f: function(){
            //     this.isActive = !this.isActive;
            // },
            btn_click () {
                this.classStyle.isActive =  !this.classStyle.isActive;
                this.classStyle.isLine =  !this.classStyle.isLine

                this.lst
            }
        }
    })
</script>
</html>
绑定方式:数组语法 比较少用

数组语法的含义是:class后面跟的是一个数组。

数组语法有下面这些用法:

用法一:直接通过{}绑定一个类
<h2 :class="['active']">Hello World</h2>

用法二:也可以传入多个值
<h2 :class=“[‘active’, 'line']">Hello World</h2>

用法三:和普通的类同时存在,并不冲突
注:会有title/active/line三个类
<h2 class="title" :class=“[‘active’, 'line']">Hello World</h2>

用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h2 class="title" :class="['active','line']">{{message}}</h2>
        <h2 class="title" :class="[active,line]">{{message}}</h2>
        <h3 :class="get_classes()">{{message}}</h3>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: '你好呀',
            active: 'aaa',
            line: 'bbb',        
        },
        methods: {
            get_classes: function () {
                return [this.active,this.line]  
            }
        }
    })
</script>
</html>
作业:点击列表中的哪一项,那么该项的文字变成红色
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
    <style>
        .active {
            color: red;
        }
    </style>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="(item, index) in movies" 
            :class="{active: current_index === index}" 
            @click="li_click(index)">
            {{index}}. {{item}}
        </li>
        </ul>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            movies: ['智能时代','异类','三体','数学之美','阅读和表达讲义'],
            current_index: 0
        },
        methods: {
            li_click (index) {
                this.current_index = index
            }
        }
    })
</script>
</html>

v-bind绑定style

我们可以利用v-bind:style来绑定一些CSS内联样式。

在写CSS属性名的时候,比如font-size

  1. 我们可以使用驼峰式 (camelCase) fontSize

  2. 或短横线分隔 (kebab-case,记得用单引号括起来) ‘font-size’

绑定class有两种方式:

  1. 对象语法

  2. 数组语法

绑定方式一:对象语法
:style="{color: currentColor, fontSize: fontSize + 'px'}"
style后面跟的是一个对象类型
对象的key是CSS属性名称
对象的value是具体赋的值,值可以来自于data中的属性

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <!-- <h3 v-for="(movie, index) in movies" :style="{color:color,fontSize:fontSize + 'px'}">{{index}}-{{movie}}</h3> -->
        <h3 v-for="(movie, index) in movies" :style="getStyles()">{{index}}-{{movie}}</h3>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            movies: ['海贼王','犬夜叉','围棋少年','秦时明月','哪吒'],
            color: 'red',
            fontSize: 20,
        },
        methods: {
            getStyles: function () {
                return {color: this.color, fontSize: this.fontSize + 'px'}
            }
        }
    })
</script>
</html>
绑定方式二:数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>
style后面跟的是一个数组类型
多个值以,分割即可

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h3 :style="[a, b]">{{message}}</h3>
        <h3 :style="getStyles()">{{message}}</h3>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好呀',
            a: {backgroundColor: 'red'},
            b: {fontSize: '50px'},
        },
        methods: {
            getStyles: function () {
                return [this.a, this.b]
            }
        }
    })
</script>
</html>

三、计算属性

基础操作

在模板中可以直接通过插值语法显示一些data中的数据,但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示。

比如我们有firstName和lastName两个变量,我们需要显示完整的名称。

但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}} {{lastName}}。

我们可以将上面的代码换成计算属性:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h2>{{first_name + ' ' + last_name}}</h2>
        <h2>{{first_name}} {{last_name}}</h2>
        <h2>{{get_full_name()}}</h2>
        <h2>{{full_name}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            first_name: 'Lebron',
            last_name: 'James',
        },
        computed: {
            full_name: function () {
                return this.first_name + ' ' + this.last_name;
            }
        },
        methods: {
            get_full_name: function () {
                return this.first_name + ' ' + this.last_name
            }
        }
    })
</script>
</html>
复杂操作
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h2>总价格(RMB):{{total_price}}</h2>  
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            books: [
                {id: 1, name: 'Unix编程艺术', price: 140},
                {id: 2, name: '代码大全', price: 130},
                {id: 3, name: '深入理解计算机原理', price: 120},
                {id: 4, name: '现代操作系统', price: 110},
            ]
        },
        computed: {
            total_price: function () {
                let result = 0
                for (let i = 0; i < this.books.length; i++) {
                    result += this.books[i].price
                }
                return result
            }
        }
    })
</script>
</html>
计算属性的setter和getter

每个计算属性都包含一个getter和一个setter

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h2>总价格(RMB):{{total_price}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            first_name: 'Kobe',
            last_name: 'Bryant'
        },
        computed: {
            // full_name: {
            //     get: function () {
            //         return this.first_name + ' ' + this.last_name
            //     }
            // },
            full_name: function () {  //computed属性是一个对象集,里面的属性也是一个对象,这里这样写其实是简写,原貌其实是上面的样子
                return this.first_name + ' ' + this.last_name
            }
        }
    })
</script>
</html>

计算属性一般没有set方法,这样叫只读属性,
特殊的也可以有set方法,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h2>{{full_name}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            first_name: 'Kobe',
            last_name: 'Bryant'
        },
        computed: {
            full_name: {
                set: function(new_value) {
                    const names = new_value.split(' ');
                    this.first_name = names[0];
                    this.last_name = names[1];
                    console.log('调用set', new_value);
                },
                get: function () {
                    return this.first_name + ' ' + this.last_name
                }
            },
            // full_name: function () {  //computed属性是一个对象集,里面的属性也是一个对象,这里这样写其实是简写,原貌其实是上面的样子
            //     return this.first_name + ' ' + this.last_name
            // }
        }
    })
</script>
</html>
计算属性的缓存

methods和computed看起来都可以实现我们的功能,

那么为什么还要多一个计算属性这个东西呢?

原因:计算属性会进行缓存,如果多次使用时,计算属性只会调用一次,而methods则不然,每一次调用都是执行一次。

所以,考虑性能,我们更提倡多用计算属性computed

示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue学习demo</title>
</head>
<body>
    <div id="app">
        <h2>总价格(RMB):{{total_price}}</h2>
        <h2>总价格(RMB):{{total_price}}</h2>
        <h2>总价格(RMB):{{total_price}}</h2>
        
        <h2>总价格(RMB):{{get_total_price()}}</h2>
        <h2>总价格(RMB):{{get_total_price()}}</h2> 
        <h2>总价格(RMB):{{get_total_price()}}</h2> 
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            books: [
                {id: 1, name: 'Unix编程艺术', price: 140},
                {id: 2, name: '代码大全', price: 130},
                {id: 3, name: '深入理解计算机原理', price: 120},
                {id: 4, name: '现代操作系统', price: 110},
            ]
        },
        computed: {
            total_price: function () {
                console.log('调用total_price');
                let result = 0
                for (let i = 0; i < this.books.length; i++) {
                    result += this.books[i].price
                }
                return result
            }
        },
        methods: {
            get_total_price: function () {
                console.log('调用get_total_price');
                let result = 0
                for (let i = 0; i < this.books.length; i++) {
                    result += this.books[i].price
                }
                return result               
            }
        }
    })
</script>
</html>

四、事件监听

在前端开发中,我们需要经常和用于交互。

这个时候,我们就必须监听用户发生的时间,比如点击、拖拽、键盘事件等等

在Vue中如何监听事件呢?使用v-on指令

v-on介绍

v-on 可以用来监听DOM事件、组件间自定义事件.

作用:绑定事件监听器

缩写:@

预期:Function | Inline Statement | Object

参数:event

v-on基础使用
<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2>当前计数:{{counter}}</h2>
        <button @click="increment">+</button>  
        <button @click="decrement">-</button>  
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            counter:0,
        },
        methods:{
            increment() {
                this.counter++
            },
            decrement() {
                this.counter--
            }
        }
    })
</script>
</html>
v-on修饰符
.stop 调用 event.stopPropagation()

直接上代码

<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app" @click="btn_click">
        --这里是div--
        <!-- 1..stop修饰符 -->
        <!-- <button @click="btn_click">按钮1</button> -->
        <button @click.stop="btn_click">按钮1</button>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            message: 'hello'
        },
        methods:{
            btn_click() {
                console.log("btn_click");
            },

        }
    })
</script>
</html>
<button @click="btn_click">按钮1</button>

button点击后的click事件会传递给div的click,然后执行2次btn_click,有时我们并不想要这样的效果,那么可以在button监听的click事件这里加上.stop修饰符即可。

<button @click.stop="btn_click">按钮1</button>
.prevent 调用 event.preventDefault()
<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        --这里是div--
        <form action="https://www.baidu.com">
            <!-- <input type="submit" value="提交" @click="submit_click">  //这里会有2个动作1.打印submit_click,2.提交(跳转到baidu) -->
            <input type="submit" value="提交" @click.prevent="submit_click">  //可以看到打印了打印submit_click,但是没有提交
        </form>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            message: 'hello'
        },
        methods:{
            submit_click() {
                console.log('submit_click');
            }
        }
    })
</script>
</html>

为什么要用.prevent?

有的时候我们并不想使用默认的submit事件去提交数据,而是希望我们自己做一些数据处理,然后再手动提交,那么就可以用上.prevent。

监听键盘按键的点击事件
<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        --这里是div--
            <!-- <input type="text" @keyup="key_up">  //监听所有按键 -->
            <!--仅监听ENTER键-->
        <input type="text" @keyup.enter="key_up">  

    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            message: 'hello'
        },
        methods:{
            key_up() {
                console.log("key_up");
            },
        }
    })
</script>
</html>
.once 仅第一次点击有效
<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        --这里是div--
        <input type="text" @keyup.once="xclick">  
        <button @click.once="xclick">仅点第一次有效</button>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            message: 'hello'
        },
        methods:{
            xclick() {
                console.log("key_up");
            },
        }
    })
</script>
</html>

五、条件判断

v-if、v-else-if、v-else

  • 这三个指令与JavaScript的条件语句if、else、else if类似。

  • Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件

v-if的原理:

v-if后面的条件为false时,对应的元素以及其子元素不会渲染。也就是根本不会有对应的标签出现在DOM中

<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <!-- <h2 v-if="score>=90">优秀</h2>
        <h2 v-else-if="score>=80">良好</h2>
        <h2 v-else-if="score>=60">及格</h2>
        <h2 v-else>不及格</h2> -->
        <h2>{{result}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            score:90
        },
        computed: {
            result(){
                let show_message = '';
                if (this.score >= 90) {
                    show_message = '优秀'
                }else if (this.score >= 80) {
                    show_message = '良好'
                }else if (this.score >= 60) {
                    show_message = '及格'
                }else {
                    show_message = '不及格'
                }
                return show_message
            }
        },
        methods:{

        }
    })
</script>
</html>
条件渲染案例

用户登录时,可以切换使用用户账号登录还是邮箱登录

<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <span v-if="is_user">
            <label for="username">用户账号</label>
            <input type="text" id="username" placeholder="用户账号">
        </span>
        <span v-else>
            <label for="email">用户邮箱</label>
            <input type="text" id="email" placeholder="用户邮箱">
        </span>
        <button @click="is_user = !is_user">切换登录方式</button>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            is_user:true
        }
    })
</script>
</html>
  1. Vue不会直接把元素无脑的渲染到浏览器页面上,而是会经过一个虚拟DOM来加载到内存,代码 -> 虚拟DOM -> 浏览器页面。

  2. 在切换操作中,Vue在进行渲染时,出于性能考虑,会尽可能复用已经存在的元素,而不是重新创建新的元素

  3. 如果我们不希望Vue出现类似重复利用的问题,可以给对应的元素添加唯一key

<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <span v-if="is_user">
            <label for="username">用户账号</label> 《!--for:label和input绑定-->
            <input type="text" id="username" placeholder="用户账号" key="username">
        </span>
        <span v-else>
            <label for="email">用户邮箱</label>
            <input type="text" id="email" placeholder="用户邮箱" key="email">
        </span>
        <button @click="is_user = !is_user">切换登录方式</button>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            is_user:true
        }
    })
</script>
</html>
v-show

v-show的用法和v-if非常相似,也用于决定一个元素是否渲染.

  1. v-show当条件为false时,仅仅是将元素的display属性设置为none而已

  2. v-if当条件为false时,元素不会存在于DOM中

  3. 既然如此,那如何选择?

    当需要在显示与隐藏之间切片很频繁时,使用v-show

    当只有一次切换时,通过使用v-if

<!DOCTYPE html>
<html>
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <h2 v-if="is_show">{{message}}</h2>
        <h2 v-show="is_show">{{message}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data:{
            message:'hello world!',
            is_show: true
        }
    })
</script>
</html>

六、循环遍历

v-for遍历数组
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <ul>
            <li>hello {{names}}</li><br>
            <li v-for = "name in names">{{name}}</li><br>
            <li v-for = "(name,index) in names">{{index}}.{{name}}</li>
        </ul>

    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            names: ['zhangsan','lisi','wangwu','kang']
        }
    })
</script>
</html>
v-for遍历对象
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <ul>
            <!--一个item是获取value-->
            <li v-for="item in info">{{item}}</li><br>
            <!--同时拿到key和value-->
            <li v-for="(value,key) in info">{{key}}: {{value}}</li><br>
            <!--获取key,value,index-->
            <li v-for="(value,key,index) in info">{{index}}.{{key}}: {{value}}</li>
        </ul>

    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            info: {
                name: 'kang',
                age: 18,
                salary: 30000
            }
        }
    })
</script>
</html>
组件的key属性

官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性

  • 为什么需要这个key属性呢(了解)?

    ​ 这个其实和Vue的虚拟DOM的Diff算法有关系。

    ​ 这里我们借用React’s diff algorithm中的一张图来简单说明一下:

  • 当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点

    ​ 我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。

    ​ 即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?

  • 所以我们需要使用key来给每个节点做一个唯一标识

    ​ Diff算法就可以正确的识别此节点

    ​ 找到正确的位置区插入新的节点。

所以一句话,key的作用主要是为了高效的更新虚拟DOM

检测数组更新

因为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。

Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。

  • push()

  • pop()

  • shift()

  • unshift()

  • splice()

  • sort()

  • reverse()

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Vue demo</title>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="item in letters">{{item}}</li>
        </ul>
        <button @click="btnclick">点一下</button>

    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            letters: ['A','B','C','D','E']
        },
        methods: {
            btnclick(){
                // //非响应式操作:通过索引添加元素
                // this.letters[0] = 'X'
                // //在最后插入
                // this.letters.push('F','G')
                // //在开头插入
                // this.letters.unshift('XYZ','oo','yy')
                // //删除最后一个元素
                // this.letters.pop()
                // //删除第一个元素
                // this.letters.shift()
                // //插入、删除、替换
                // this.letters.splice(2,this.letters.length-2)  //从第二个元素开始,删除后面全部元素(第三个、第四个...最后一个)
                // this.letters.splice(2,3,'m','n','l')  //替换CDE为mnl
                // this.letters.splice(1,0,'x')  //在第一个后面插入charuyuansu
                this.letters.splice(0,1,'x')  //在第一个元素前面插入x
                //Vue.set(this.letters,1,9)  // Vue内置函数:set(要修改的对象,索引值,修改后的值)
                // //排序
                // this.letters.sort()
                // //反转
                // this.letters.reverse()
                
            }
        }
    })
</script>
</html>

七、阶段案例

图书购物车

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

<div id="app">
  <div v-if="books.length">
    <table>
      <thead>
        <tr>
            <th></th>
            <th>书籍名称</th>
            <th>出版日期</th>
            <th>价格</th>
            <th>购买数量</th>
            <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item, index) in books">
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date}}</td>
            <td>{{item.price | showPrice}}</td>
            <td>
                <button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button>
                {{item.count}}
                <button @click="increment(index)">+</button>
            </td>
            <td>
                <button @click="removeHandle(index)">移除</button>
            </td>
        </tr>
      </tbody>
    </table>
    <h2>总价格: {{totalPrice | showPrice}}</h2>
  </div>
  <h2 v-else>购物车为空</h2>
</div>

<script src="../vue.js"></script>
<script src="main.js"></script>
</body>
</html>

main.js

const app = new Vue({
  el: '#app',
  data: {
    books: [
      {
        id: 1,
        name: '《算法导论》',
        date: '2006-9',
        price: 85.00,
        count: 1
      },
      {
        id: 2,
        name: '《UNIX编程艺术》',
        date: '2006-2',
        price: 59.00,
        count: 1
      },
      {
        id: 3,
        name: '《编程珠玑》',
        date: '2008-10',
        price: 39.00,
        count: 1
      },
      {
        id: 4,
        name: '《代码大全》',
        date: '2006-3',
        price: 128.00,
        count: 1
      },
    ]
  },
  methods: {
    // getFinalPrice(price) {
    //   return '¥' + price.toFixed(2)
    // }
    increment(index) {
      this.books[index].count++
    },
    decrement(index) {
      this.books[index].count--
    },
    removeHandle(index) {
      this.books.splice(index, 1)
    }
  },
  computed: {
    totalPrice() {
      //写法1
      // let totalPrice = 0
      // for (let i = 0; i < this.books.length; i++) {
      //   totalPrice += this.books[i].price * this.books[i].count
      // }
      // return totalPrice

      //写法2
      return this.books.reduce(function(preValue, book){
        return preValue + book.price * book.count
      }, 0)
    }
  },
  filters: {
    showPrice(price) {
      return '¥' + price.toFixed(2)
    }
  }
})

style.css

table {
  border: 1px solid #e9e9e9;
  border-collapse: collapse;
  border-spacing: 0;
}

th, td {
  padding: 8px 16px;
  border: 1px solid #e9e9e9;
  text-align: left;
}

th {
  background-color: #f7f7f7;
  color: #5c6b77;
  font-weight: 600;
}

八、javascript for补充

books: [
      {
        id: 1,
        name: '《算法导论》',
        date: '2006-9',
        price: 85.00,
        count: 1
      },
      {
        id: 2,
        name: '《UNIX编程艺术》',
        date: '2006-2',
        price: 59.00,
        count: 1
      },
      {
        id: 3,
        name: '《编程珠玑》',
        date: '2008-10',
        price: 39.00,
        count: 1
      },
      {
        id: 4,
        name: '《代码大全》',
        date: '2006-3',
        price: 128.00,
        count: 1
      },
    ]

for(let i of books){console.log(i.price)}

九、v-model

双向绑定 基本使用

v-model绑定的变量,无论输入什么,赋值的时候都是当作字符串处理

<html lang="en">
<head>
    <title></title>
</head>
<body>
    <div id="app">
        <input type="text" v-model="message">
        {{message}}
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: 'hello world!'
        }
    })
</script>
</html>
> app.message
<· "hello world!"

可以看到在控制台修改app.message = 'good',页面上会随着改变,当然这是我们前面的内容mustache语法已经可以实现的效果
> app.message = 'good'
<· "good"
> app.message
<· "good"

但是你在页面上的input里面输入一个内容,然后在控制台输出下app.message,会发现,Vue里面的数据也改变了,这样就形成了双向绑定,这里不同于mustache的能力
> app.message
<· "good night"

v-model其实是下面这段代码的高级实现,如果不用v-model,下面这段代码也是一样的实现

<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>
</head>
<body>
    <div id="app">
        <!--<input type="text" v-model="message" @input="valueChange">-->
        <!--或者一般我们更常用这种写法:不写methods,这样写-->
        <input type="text" :value="message" @input="message = $event.target.value">
        <h2>{{message}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: 'hello world!'
        },
        //methods: {
            //valueChange (event) {
                //this.message = event.target.value;
            //}
       //}
    })
</script>
</html>
原理

v-model其实是一个语法糖,它的背后本质上是包含两个操作:

  1. v-bind绑定一个value属性

  2. v-on指令给当前元素绑定input事件

<input type="text" v-model="message">
等同于
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">

radio v-model结合radio的使用
<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>
</head>
<body>
    <div id="app">
        <label for="male">
            <input type="radio" id="male" value="男" v-model="sex">男
        </label>
        <label for="female">
            <input type="radio" id="female" value="女" v-model="sex">女
        </label>
        <h2>你选择的性别是: {{sex}}</h2>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            sex: '男'  //默认选择男
        },
    })
</script>
</html>

加name是为了让两个radio互斥,要么男要么女

<input type="radio" id="male" name="sex" value="男">男
<input type="radio" id="female" value="女" v-model="sex">女

如果我们用了v-model,就不需要name,他们也已经是互斥

<input type="radio" id="male"value="男" v-model="sex">男
checkbox v-model结合checkbox使用

复选框分为两种情况:单个勾选框和多个勾选框

  • 单个勾选框:

    v-model即为布尔值,此时input的value并不影响v-model的值。

  • 多个复选框:

    当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组

    当选中某一个时,就会将input的value添加到数组中。

<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>
</head>
<body>
    <div id="app">
        <!--单选框-->
        <!-- <label for="licence">  label的好处是点文字也可以选中 -->
            <!-- <input type="checkbox" id="licence" v-model="licence">同意协议 -->
        <!-- </label> -->
        <!-- <h2>你选择的是: {{licence}}</h2> -->
        <!-- <button :disabled="!licence">同意协议,进行下一步</button> -->
        <br><br><br>
        <!--多选框-->
        <input type="checkbox" value="篮球" v-model="likes">篮球<br>
        <input type="checkbox" value="足球" v-model="likes">足球<br>
        <input type="checkbox" value="乒乓球" v-model="likes">乒乓球<br>
        <input type="checkbox" value="羽毛球" v-model="likes">羽毛球
        <h2>你的爱好是: {{likes}}</h2>
        
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            licence: false,
            likes: []
        },
    })
</script>
</html>
select v-model结合select的使用

和checkbox一样,select也分单选和多选两种情况。

  • 单选:只能选中一个值。
    v-model绑定的是一个值。
    当我们选中option中的一个时,会将它对应的value赋值到fruit中

  • 多选:可以选中多个值。
    v-model绑定的是一个数组。
    当选中多个值时,就会将选中的option对应的value添加到数组fruits中

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <!--1.选择一个-->
  <select name="abc" v-model="fruit">
    <option value="苹果">苹果</option>
    <option value="香蕉">香蕉</option>
    <option value="榴莲">榴莲</option>
    <option value="葡萄">葡萄</option>
  </select>
  <h2>您选择的水果是: {{fruit}}</h2>

  <!--2.选择多个: multiple属性可以选择多个值-->
  <select name="abc" v-model="fruits" multiple>
    <option value="苹果">苹果</option>
    <option value="香蕉">香蕉</option>
    <option value="榴莲">榴莲</option>
    <option value="葡萄">葡萄</option>
  </select>
  <h2>您选择的水果是: {{fruits}}</h2>
</div>
</body>
<script src="vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      fruit: '香蕉',
      fruits: []
    }
  })
</script>
</html>
值绑定 v-bind结合input的使用

通过v-bind:value,动态的给value赋值,以下动态绑定有3处(:for,:value,:id),还有一处mustache绑定({{item}})

<!DOCTYPE html>
<html lang="en">
<head>
    <title></title>
</head>
<body>
    <div id="app">
        <input type="checkbox" value="篮球" v-model="likes">篮球<br>
        <input type="checkbox" value="足球" v-model="likes">足球<br>
        <input type="checkbox" value="乒乓球" v-model="likes">乒乓球<br>
        <input type="checkbox" value="羽毛球" v-model="likes">羽毛球

        <h2>你的爱好是: {{likes}}</h2>
        
        <label v-for="item in origin_likes" :for="item">  <!--遍历origin_likes把每项存到likes数组-->
            <input type="checkbox" :value="item" :id="item" v-model="likes">{{item}}
        </label>
    </div>
    
</body>
<script src="vue.js"></script>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            likes: [],
            origin_likes: ["篮球","足球","乒乓球","羽毛球"]
        },
    })
</script>
</html>
修饰符

lazy修饰符:
默认情况下,v-model默认是在input事件中同步输入框的数据的,也就是说,一旦有数据发生改变对应的data 中的数据就会自动发生改变。lazy修饰符可以让数据在失去焦点或者回车时才会更新
number修饰符:
默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理,但是如果我们希 望处理的是数字类型,那么最好直接将内容当做数字处理,number修饰符可以让在输入框中输入的内容自动转成数字类型
trim修饰符:
如果输入的内容首尾有很多空格,通常我们希望将其去除,trim修饰符可以过滤掉内容左右两边的空格

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<div id="app">
  <!--1.修饰符: lazy,让数据在失去焦点或者回车时才会更新data中对应的变量-->
  <input type="text" v-model.lazy="message">
  <h2>{{message}}</h2>


  <!--2.修饰符: number,让在输入框中输入的内容自动转成数字类型-->
  <input type="number" v-model.number="age">
  <h2>{{age}}-{{typeof age}}</h2>  <!--typeof age:获取age的类型-->

  <!--3.修饰符: trim,过滤掉内容左右两边的空格-->
  <input type="text" v-model.trim="name">
  <h2>您输入的名字:{{name}}</h2>
</div>

<script src="vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      age: 0,
      name: ''
    }
  })

  var age = 0
  age = '1111'
  age = '222'
</script>

</body>
</html>
posted @ 2021-04-26 16:06  我是一言  阅读(154)  评论(1编辑  收藏  举报