03-Vue基础知识

137 阅读4分钟

模板数据绑定渲染

  模板数据绑定渲染可生成动态的 HTML 页面,页面中使用嵌入 Vue.js 语法可动态生成:

  • {{xxx}} 双大括号文本绑定
  • v-xxxv- 开头用于标签属性绑定,称为 指令

双大括号语法

  • 格式:{{表达式}}
  • 作用:
    • 使用在标签体中,用于获取数据
    • 可以使用 JavaScript 表达式
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>1. 双大括号输出文本内容</h3>
        <!-- 文本内容 -->
        <p>普通文本:{{message}}</p>
        <!-- JS表达式 -->
        <p>JS表达式:{{number + 1}}</p>
    </div>
    <script>
        new Vue({
            data() {
                return {
                    message: 'Hello World',
                    number: 1
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

一次性插值

  通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>一次性插值</h3>
        <!-- Hello World -->
        <p v-once>这个值不会改变:{{message}}</p>
        <!-- Hello Vue! -->
        <p >这个值会改变:{{message}}</p>
    </div>
    <script>
        var vm = new Vue({
            data() {
                return {
                    message: 'Hello World',
                }
            },
        }).$mount('#app');

        vm.message = 'Hello Vue!';
    </script>
</body>
</html>

输出 HTML 指令

  • 格式:v-html='xxx'
  • 作用:如果是 HTML 格式数据,双大括号会将数据解释为普通文本,为了输出真正的 HTML,需要使用 v-html 指令;Vue 为了防止 XSS 攻击,在此指令上做了安全处理,当发现输出内容有 script 标签时,则不渲染
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>v-html指令</h3>
        <p>双大括号:{{message}}</p>
        <p>v-html指令:<span v-html="message"></span></p>
    </div>
    <script>
        var vm = new Vue({
            data() {
                return {
                    message: '<span style="color:red">红色字体内容<script>alert("hello vue")<\/script></span>',
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

XSS 攻击主要是利用 JS 脚本注入到网页中,读取 Cookie 值(Cookie 一般存储了登录身份信息),读取到了发送到黑客服务器,从而黑客可以使用你的账户做非法操作。XSS 攻击还可以在你进入到支付时,跳转到钓鱼网站。

01.png

元素绑定指令

  • 完整格式:v-bind:元素的属性名='xxx'
  • 缩写格式::元素的属性名='xxx'
  • 作用:将数据动态绑定到指定的元素上
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>v-bind指令</h3>
        <a :href="url">百度</a>
    </div>
    <script>
        var vm = new Vue({
            data() {
                return {
                    url: "http://www.baidu.com/",
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

事件绑定指令

  • 完整格式:v-on:事件名称="事件处理函数名"
  • 缩写格式:@事件名称="事件处理函数名"@后面没有冒号
  • 作用:用于监听 DOM 事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>v-on指令</h3>
        <p>number:{{number}}</p>
        <button @click="handleAdd()">+1</button>
    </div>
    <script>
        new Vue({
            data() {
                return {
                    number: 1
                }
            },
            methods: {
                handleAdd () {
                    this.number++;
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

02.gif

计算属性和监听器

计算属性

  computed 选项用于定义计算属性,计算属性类似于 methods 中定义的函数,它们之间的不同是:

  • 计算属性会进行缓存,只在相关响应式依赖发生改变时它们才会重新求值
  • 函数每次都会执行函数体进行计算
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>计算属性和 methods 方法</h3>
        数学分数:<input type="text" v-model="mathScore"> <br>
        英语分数:<input type="text" v-model="englishScore"> <br>
        总分(方法-单向):<input type="text" v-model="sum1()"> <br>
        总分(计算属性-单向):<input type="text" v-model="sum2">
    </div>
    <script>
        new Vue({
            data() {
                return {
                    mathScore: 100,
                    englishScore: 100
                }
            },
            methods: {
                sum1 () {
                    return (this.mathScore - 0) + (this.englishScore - 0);
                }
            },
            computed: {
                sum2 () {
                    return (this.mathScore - 0) + (this.englishScore - 0);
                }
            }
        }).$mount('#app');
    </script>
</body>
</html>

03.gif

  computed 选项内的计算属性默认是 getter 函数,所以上面只支持单向绑定,当修改数学和英语的数据才会更新总分,而修改总分不会更新数学和英语分数。不过在需要的时候,也可以提供一个 setter 方法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>计算属性和 methods 方法</h3>
        数学分数:<input type="text" v-model="mathScore"> <br>
        英语分数:<input type="text" v-model="englishScore"> <br>
        总分(方法-单向):<input type="text" v-model="sum1()"> <br>
        总分(计算属性-单向):<input type="text" v-model="sum2"> <br>
        总分(计算属性-双向):<input type="text" v-model="sum3">
    </div>
    <script>
        new Vue({
            data() {
                return {
                    mathScore: 100,
                    englishScore: 100
                }
            },
            methods: {
                sum1 () {
                    return (this.mathScore - 0) + (this.englishScore - 0);
                }
            },
            computed: {
                sum2 () {
                    return (this.mathScore - 0) + (this.englishScore - 0);
                },
                sum3 : {
                    get: function () {
                        return (this.mathScore - 0) + (this.englishScore - 0);
                    },
                    set: function (newValue) {
                        this.mathScore = newValue / 2;
                        this.englishScore = newValue / 2;
                    }
                }
            }
        }).$mount('#app');
    </script>
</body>
</html>

04.gif

监听器

  当属性数据发生变化时,对应属性的回调函数会自动调用,并在函数内部进行计算。通过 watch 选项或者 vm 实例的 $watch() 来监听指定的属性:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>计算属性和 methods 方法</h3>
        数学分数:<input type="text" v-model="mathScore"> <br>
        英语分数:<input type="text" v-model="englishScore"> <br>
        总分:{{totalScore}} 
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    mathScore: 100,
                    englishScore: 100,
                    totalScore: 200
                }
            },
            watch: {
                // 监听 mathScore 的变化
                mathScore: function (newValue, oldValue) { 
                    this.totalScore = (newValue - 0) + (this. englishScore - 0);
                }
            }
        }).$mount('#app');

        // 通过实例对象创建监听
        app.$watch('englishScore', function(newValue, oldValue) { 
            this.totalScore = (newValue - 0) + (this.mathScore - 0);
        });
    </script>
</body>
</html>

05.gif

当对象中的某个属性发生改变之后,默认情况下是不会被监听到的。如果希望修改对象属性后也能够被监听到,就需要使用深度监听:

watch: {
   items : {
     deep: true,
     handler : function(newItems, oldItems) {

     }
   }
}

class 与 style 绑定

  • class 绑定的语法格式:v-bind:class='表达式':class='表达式',其中的表达式有以下几种:
    • 字符串::class='activeClass'
    • 对象::class='{active:isActive, error:hasError}'
    • 数组::class=['active', 'error']需要加上单引号,否则是获取 data 中的值
  • style 绑定的语法格式::style={color:activeColor, fontSize: fontSize+'px'}activefontSizedata 中的属性
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        .active {
            color: green;
        }

        .delete {
            background-color: red;
        }

        .error {
            font-size: 30px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h3>class 绑定的案例</h3>
        <p :class="activeClass">字符串表达式</p>
        <p :class="{delete: isDelete, error: hasError}">对象表达式</p>
        <p :class="['error', 'delete']">数组表达式</p>

        <h3>style 绑定的案例</h3>
        <p :style="{color: activeColor, fontSize: fontSize + 'px'}">style 绑定方式</p>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    activeClass: 'active',
                    isDelete: true,
                    hasError: false,
                    activeColor: 'red',
                    fontSize: 20
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

06.png

条件渲染

  条件渲染涉及到的指令如下:

  • v-if:是否渲染当前元素,另外还提供了 v-elsev-else-if 指令,实现不同条件的渲染
  • v-show:与 v-if 类似,只是元素始终被渲染并保留在 DOM 中,只是简单切换元素的 CSS 属性 display 来显示或隐藏
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
    <style>
        .box {
            background-color: red;
            width: 100px;
            height: 100px;
        }
    </style>
</head>
<body>
    <div id="app">
        <h3>v-if实现</h3>
        <input type="checkbox" v-model="seen">是否显示
        <div class="box" v-if="seen"></div>
        <p v-else="seen">红色框被隐藏</p>
        <hr>
        <h3>v-show实现</h3>
        <div class="box" v-show="seen"></div>
        <hr>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    seen: true
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

07.gif

v-ifv-show 比较

  • 什么时候元素被渲染
    • v-if:如果初始条件为假,则什么也不做;每当条件为真时,都会重新渲染条件元素
    • v-show: 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
  • 使用场景选择
    • v-if 有更高的切换开销

    • v-show 有更高的初始渲染开销

  因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行后条件很少改变,则使用 v-if 较好。

列表渲染

迭代数组

  可以使用 v-for 来迭代数组,其语法如下:v-for="(alias, index) in array"

  • alias: 数组元素迭代的别名
  • index: 数组索引值,从 0 开始(可以省略
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>v-for迭代数组</h3>
        <div v-for="(employee) in employees" :key="employee.id">
            {{employee.id}}. 姓名:{{employee.name}}, 年龄:{{employee.age}}
        </div>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    employees: [
                        {id: 1, name: '张三', age: 12},
                        {id: 2, name: '李四', age: 22},
                        {id: 3, name: '王五', age: 32}
                    ]
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

注意:

  • 使用 key 特殊属性, 它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素,一般指定的 key 值是 id值。
  • 可以使用 of 替代 in

关于数组更新检测

  • 使用以下方法操作数组,可以检测变动:pushpopshiftunshiftsortreverse
  • 使用以下方法需要用新数组替换旧数组:filterconcatslicemap
  • 不能检测以下变动的数组:vm.items[indexOfItem] = newValue,可以通过下面的方法解决:
    • Vue.set(example1.items, indexOfItem, newValue)
    • splice 方法

迭代对象

  可以使用 v-for 来迭代对象,其语法如下:v-for="(value, key, index) in object"

  • value:每个对象的属性值
  • key:每个对象的属性名(可以省略
  • index:索引值(可以省略
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>v-for迭代对象</h3>
        <p v-for="(value, key, index) in person" :key="index">{{key}} - {{value}}</p>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    person: {
                        id: 1,
                        name: 'John',
                        age: 12
                    }
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

注意:

  • 在遍历对象时,是按 Object.keys() 的结果遍历,但不能保证它的结果在不同的 JavaScript 引擎下是顺序一致的
  • 可以使用 of 替代 in

事件处理

事件处理方法

  • 完整格式:v-on:事件名='函数名'v-on:事件名=函数名(参数..)
  • 缩写格式:@事件名='函数名'@事件名=函数名(参数..)@后面没有冒号
  • event:函数中的默认行参,代表原生 DOM 事件;当调用的函数有多个参数传入的时候,需要使用原生的 DOM 事件,可以通过 $event 作为实参传入
  • 作用:用于监听 DOM 事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>事件处理</h3>
        <button @click="errorInfo">Error</button>
        <button @click="warnInfo('Hello', $event)">Warn</button>
    </div>
    <script>
        let app = new Vue({
            methods: {
                errorInfo (event) {
                    alert(event.target.innerHTML);
                },
                warnInfo(msg, event) { 
                    alert(msg + event.target.innerHTML);
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

08.gif

事件修饰符

  • .stop 阻止单击事件继续传播 event.stopPropagation()
  • .prevent 阻止事件默认行为 event.preventDefault()
  • .once 点击事件将只会触发一次
  • .passive 每次事件产生,浏览器都会去查询一下是否有 preventDefault 阻止该次事件的默认动作。我们加上 passive 就是为了告诉浏览器不用查询了,我们没用 preventDefault 阻止默认动作。这里一般用在滚动监听
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>事件修饰符</h3>
        <!-- 下面的代码会阻止 a 标签的默认行为 -->
        <a href="http://www.baidu.com" @click.prevent="info">百度</a>
    </div>
    <script>
        let app = new Vue({
            methods: {
                info () {
                    alert("百度");
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

09.gif

按键修饰符

  • 格式:v-on:keyup.按键名@keyup.案件名
  • 常用按键名:.enter.tab.delete.esc.space.up.down.left.right
  • 可以使用按键的按键码:@keyup.13
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>按键修饰符</h3>
        <input type="text" @keyup.enter="info">
    </div>
    <script>
        let app = new Vue({
            methods: {
                info: function () {
                    alert("回车键");
                },
            },
        }).$mount('#app');
    </script>
</body>
</html>

10.gif

表单数据双向绑定

  双向绑定是指数据变的时候视图也相应改变;同时视图变的时候,数据也跟着改变。v-model 指令用于表单数据的双向绑定,主要针对以下类型:text(文本)textarea(多行文本)radio(单选按钮)checkbox(复选框)select(下拉框)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
    <div id="app">
        <h3>text文本</h3>
        <input type="text" v-model="textModel">
        <p>text的当前文本:{{textModel}}</p>

        <h3>多行文本</h3>
        <textArea v-model="textAreaModel"></textArea>
        <p>多行文本的当前内容:{{textAreaModel}}</p>

        <h3>radio</h3>
        <input type="radio" v-model="gender" value="male">:男
        <input type="radio" v-model="gender" value="female">:女 
        <p>radio当前选择了:{{gender}}</p>

        <h3>checkbox</h3>
        <!-- 单个checkbox 可以绑定 boolean 对象 -->
        <input type="checkbox" v-model="isAll"> 全选 <br>
        <p>是否全选:{{isAll}}</p>

        <!-- 多个的时候可以绑定数组 -->
        <input type="checkbox" v-model="hab" value="football"> 足球
        <input type="checkbox" v-model="hab" value="basketball"> 篮球
        <p>checkbox选择了:{{hab}}</p>

        <h3>select</h3>
        <select v-model="person">
            <option v-for="(person) in persons" :value="person">{{person.name}}</option>
        </select>
        <p>选择了:{{person}}</p>
    </div>
    <script>
        let app = new Vue({
            data() {
                return {
                    textModel: "Hello world",
                    textAreaModel: "Hello Vue",
                    gender: 'male',
                    isAll: false,
                    hab:[],
                    persons : [
                        {id: '1', name: 'John'},
                        {id: '2', name: 'Jack'}
                    ],
                    person: {}
                }
            },
        }).$mount('#app');
    </script>
</body>
</html>

常用表单控件修饰符

  • .lazy 失去焦点同步一次
  • .number 格式化数字
  • .trim 去除首尾空格