第2章 vue基础语法

2019-09-26  本文已影响0人  yangsg

1. 简介

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统,区别于JQuery的DOM树操作,Vue更多的是将数据与DOM进行双向绑定。
Vue另一个重要概念是组件,它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。一个组件本质上是一个拥有预定义选项的一个 Vue 实例。


组件树

2. Vue.js安装与引入

Vue可以通过操作npm来进行进行脚手架方式安装,详细请见本系列第一章内容第1章 基于vscode的vue开发环境搭建,如果是初学者,也可以直接在HTML文件中通过常规的js方式引入Vue.js文件

对于制作原型或学习,可以这样使用最新版本

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

对于生产环境,推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>

如果你使用原生 ES Modules,也有一个兼容 ES Module 的构建文件

<script type="module">
  import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.esm.browser.js'
</script>

也可以在Vue官网上下载Vue的js文件至本地进行引入

官网相关连接和介绍

3. Vue实例

每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的

var vm = new Vue({
  // 选项
})

需要注意的是,Vue中的参数是一个json类型数据,请注意它的格式
当一个 Vue 实例被创建时,它将 data 对象中的所有的属性加入到 Vue 的响应式系统中。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。

// 我们的数据对象
var data = { a: 1 }

// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
  data: data
})

// 获得这个实例上的属性
// 返回源数据中对应的字段
vm.a == data.a // => true

// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2

// ……反之亦然
data.a = 3
vm.a // => 3

当这些数据改变时,视图会进行重渲染。


双向绑定原理

这里唯一的例外是使用 Object.freeze(),这会阻止修改现有的属性,也意味着响应系统无法再追踪变化。

<script>
var obj = {
  foo: 'bar'
}

Object.freeze(obj)

new Vue({
  el: '#app',
  data: obj
})
</script>
<div id="app">
  <p>{{ foo }}</p>
  <!-- 这里的 `foo` 不会更新! -->
  <button v-on:click="foo = 'baz'">Change it</button>
</div>

下面是Vue实例的生命周期,随着深入学习,会理解各个部分的进行时机。


Vue生命周期

4. 模板语法

4.1 文本渲染

vue提供了其他几种常见的文本渲染方式:

<div id="demo">
 <div>{{message0}}</div>
 <div v-text="message1"></div>
 <div v-html="message2"></div>
 <div v-once>{{message3}}</div>
 <div v-pre>{{message4}}</div>
</div>  
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message0: "普通文本渲染1",
        message1: "<b>普通文本渲染2</b>",
        message2: "<b>HTML文本渲染</b>",
        message3: "<b>静态插值渲染</b>",
        message4: "原文本渲染"
    }
})
</script>

运行结果


运行结果
4.2 属性绑定

属性绑定使用v-bind:属性名完成,也可以使用语法糖省略v-bind,直接使用:属性名完成。其主要绑定方式有以下几种

<div id="demo">
    <div v-bind:title="message">{{message}}</div>
    <div :title="message">{{message}}</div>
</div>  
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message: '这是一些测试文本'
    }
})
</script>

<div id="demo">
    <div v-bind:class="{btext:sepText,aurora:!showGround}">{{message}}</div>
    <div v-bind:class="{btext:sepText,aurora:showGround}">{{message}}</div>
    <div v-bind:class="styleEffect">{{message}}</div>
</div>  
<style type="text/css">
    div{
        width:200px;
        height: 80px;
    }
    .btext{
        color: darkorange;/*橙黄文字颜色*/
    }
    .aurora{
        background-color: darkturquoise;/*青蓝背景颜色*/
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message: '这是一些测试文本',
        sepText: true,
        showGround: false,
        styleEffect:{
            'btext':false,
            'aurora': true
        }   
    }
})
</script>

运行结果:


运行结果

解析运行的HTML:


解析运行的HTML
<div id="demo">
    <div :class="[sepText,showGround]">{{message}}</div>
</div>  
<style type="text/css">
    div{
        width:200px;
        height: 80px;
    }
    .btext{
        color: darkorange;
    }
    .aurora{
        background-color: darkturquoise;
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message: '这是一些测试文本',
        sepText: 'btext',
        showGround: 'aurora',
    }
})
</script>

运行结果:


运行结果

解析运行的HTML:


解析运行的HTML
<div id="demo">
    <div :class="[isBgA ? bgColorA : bgColorB]">{{message}}</div>
</div>  
<style type="text/css">
    div{
        width:200px;
        height: 80px;
    }
    .california{
        background-color: darkorange;
    }
    .aurora{
        background-color: darkturquoise;
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message: '这是一些测试文本',
        bgColorA: 'california',
        bgColorB: 'aurora',
        isBgA: true
    }
})
</script>

运行结果:

运行结果
解析运行的HTML:
解析运行的HTML
更改isBgA的值为false,背景颜色会切换为样式aurora
css属性 原生JS vue
color color color
background-color backgroundColor backgroundColor
<div id="demo">
    <div :style="{color:tcolor, backgroundColor: bcolor}">{{message}}</div>
</div>  
<style type="text/css">
    div{
        width:200px;
        height: 80px;
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message: '这是一些测试文本',
        tcolor: 'darkorange',
        bcolor: 'darkturquoise'
    }
})
</script>

运行结果:


运行结果

解析运行的HTML:


解析运行的HTML
4.3 事件处理
<div id="demo">
    <button type="button" v-on:click="mymethod1">{{counter1}}</button>
    <button type="button" @click="mymethod2">{{counter2}}</button>
</div>
<script type="text/javascript">
    var demo = new Vue({
        el: "#demo",
        data:{
            counter1:0,
            counter2:100
        },
        methods:{
            mymethod1(){
                this.counter1++;
            },
            mymethod2(){
                this.counter2--;
            }
        }
    });
</script>

运行结果:点击按钮时会增加和减少数字


运行结果
事件修饰符 功能
stop 阻止后续的事件捕获和事件冒泡
prevent 阻止默认事件
once 一次性事件
<div id="demo">
    默认事件:<button type="button" v-on:click="mymethod1">{{counter1}}</button><br>
    <div @click="changeTextColor">
        阻止事件捕获和事件冒泡:
        <span :style="{color: [isTC ? colorA : colorB]}">颜色</span>
        <button v-on:click="mymethod2">non-stop:{{counter2}}</button>
        <button v-on:click.stop="mymethod3">stop:{{counter3}}</button>
    </div>
    阻止默认事件:<a href="http://www.baidu.com" @click.prevent="mymethod4">{{counter4}}</a><br>
    一次性事件:<button type="button" @click.once="mymethod5">{{counter5}}</button><br>
</div>
<script type="text/javascript">
    var demo = new Vue({
        el: "#demo",
        data:{
            counter1:0,
            counter2:0,
            counter3:0,
            counter4:0,
            counter5:0,
            colorA: "blue",
            colorB: "red",
            isTC: true
        },
        methods:{
            mymethod1(){
                this.counter1++;
            },
            mymethod2(){
                this.counter2++;
            },
            mymethod3(){
                this.counter3++;
            },
            mymethod4(){
                this.counter4++;
            },
            mymethod5(){
                this.counter5++;
            },
            changeTextColor(){
                this.isTC = !this.isTC;
            }
        }
    });
</script>

运行结果:


运行结果
鼠标修饰符 功能
left 左键
middle 滚轮
right 右键
<div id="demo">
    <button @click.right="rightMethod" @click.middle="middleMethod" @click="leftMethod">{{message}}</button>
</div>
<script type="text/javascript">
    var demo = new Vue({
        el: "#demo",
        data:{
            message: '请点击'
        },
        methods:{
            rightMethod(){
              this.message = '鼠标右键';
            },
            middleMethod(){
              this.message = '鼠标滚轮';
            },
            leftMethod(){
              this.message = '鼠标左键';
            }
        }
    });
</script>

运行结果:分别使用鼠标左键,滚轮和右键点击按钮


运行结果
按键修饰符 功能
enter 回车键
tab Tab键
delete “退格键”或“删除键”
esc Esc键
space 空格键
up ↑键
down ↓键
left ←键
right →键
<div id="demo">
    <button v-on:keyup.enter="enter">{{message1}}</button>
    <button @keyup.tab="tab">{{message2}}</button>
    <button @keyup="show($event)">{{message3}}</button>
</div>
<script>
    var demo = new Vue({
        el:'#demo',
        data:{
            message1: "hello",
            message2: "hello",
            message3: "hello"
        },
        methods:{
            enter(){
                this.message1 = 'enter';
            },
            tab(){
                this.message2 = 'tab';
            },
            show(e){
                this.message3 = e.keyCode;
            }
        }
    })
</script> 

运行结果:使各个按钮分别获得焦点后依次触发键盘按键测试结果


4.4 条件指令

v-if的用法时当值为true时进行渲染,当值为false时,页面中不会进行渲染。

<div id="demo">
    <div v-if="showInfo">{{message1}}</div>
    <div v-if="hideInfo">{{message2}}</div>
</div>  
<style type="text/css">
    #demo{
        width:200px;
        height: 80px;
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message1: '这是显示的文本',
        message2: '这是隐藏的文本',
        showInfo: true,
        hideInfo: false
    }
})
</script>

运行结果:显示“这是显示的文本”,更改showInfo和hideInfo的值可以看到不同结果

与v-if形成互斥条件

<div id="demo">
    <div v-if="showInfo">{{message1}}</div>
    <div v-else>{{message2}}</div>
</div>  
<style type="text/css">
    #demo{
        width:200px;
        height: 80px;
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message1: '这是显示的文本',
        message2: '这是隐藏的文本',
        showInfo: false
    }
})
</script>
</body>

运行结果:显示“这是隐藏的文本”,更改showInfo的值可以看到不同结果

多个条件互斥条件,相当于if...else if...else

<div id="demo">
    <div v-if="vtype == 1">{{message1}}</div>
    <div v-else-if="vtype == 2">{{message2}}</div>
    <div v-else>{{message3}}</div>
</div>  
<style type="text/css">
    #demo{
        width:200px;
        height: 80px;
    }
</style>
<script>
var demo = new Vue({
    el:"#demo",
    data:{
        message1: '这是文本1',
        message2: '这是文本2',
        message3: '这是文本3',
        vtype:1
    }
})
</script>

运行结果:显示“这是文本1”,更爱vtype的值可以看到不同结果

v-show也是根据条件展示元素的指令。带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 是简单地切换元素的 CSS 属性display来控制元素的显示和隐藏 。

<div id="demo">
        <p v-show="message">message</p>
        <p v-show="infor">infor</p>
    </div>
    <script>
        var demo1 = new Vue({
            el:'#demo',
            data:{
                message:true,
                infor:false
            }
        })
    </script> 
页面运行源码

也就说,虽然第二个p元素没有显示出来,但是页面渲染时是存在的,只是多了一个隐藏属性。

通过上面的例子,我们可以发现两者的不同:
(1) v-if是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
(2) v-if是惰性的,只有当条件为true时才会渲染,如果条件为false则什么都不做
(3) v-if有很高的切换开销,适用于条件不太容易改变的时候
v-show不管条件是true还是false都会进行渲染。并且只是简单地基于 CSS 进行切换
(4) v-show有很高的初始渲染开销,适用于非常频繁地切换

4.5 循环指令

value 是遍历得到的属性值,key 是遍历得到的属性名,index 是遍历次序,这里的 key/index 都是可选参数,这个指令其实可以写成 v-for="value in xxx"

<div id="demo">
    <ul>
        <li v-for="value in object">
            {{ value }}
        </li>
    </ul>
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {

            object: {
                firstName: 'John',
                lastName: 'Doe',
                age: 30
            }
        }
    })
</script>

运行结果:


运行结果
<div id="demo">
    <div v-for="(value, key,index) in object">
        {{ index }} : {{ key }} : {{ value }}
    </div>
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {

            object: {
                firstName: 'John',
                lastName: 'Doe',
                age: 30
            }
        }
    })
</script>

运行结果


运行结果
4.6 方法,计算属性和侦听器

在vue中处理复杂的逻辑的时候,我们经常使用计算属性,方法和侦听器。

<div id="demo" @click="getFullName">
    {{fullName}}
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            firstName: 'Monkey',
            middleName: 'D',
            lastName: 'Luffy',
            fullName: '请点击',
        },
        methods: {
            getFullName: function(){
                this.fullName = this.firstName + "."+this.middleName+"."+this.lastName;
            }
        }
    })
</script>

运行结果:点击后文字变为“Monkey.D.Luffy”

computed被称为计算属性,通常用于多个数据的值影响某一个数据时。
与methods不同的是计算属性是根据依赖关系进行缓存的计算,并且只在需要的时候进行更新。

<div id="demo">
    {{fullName}}
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            firstName: 'Monkey',
            middleName: 'D',
            lastName: 'Luffy',
        },
        computed: {
            fullName: function(){
                return this.firstName + "."+this.middleName+"."+this.lastName;
            }
        }
    })
</script>

运行结果:页面显示“Monkey.D.Luffy”。
fullName属性是由firstName,middleName和lastName三者组成的

<div id="demo">
    company:{{company}}<br>
    emp1:{{emp1}}<br>
    emp2:{{emp2}}<br>
    <input type="button" @click="changeCompany" value="点我" />
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            company: '乡村爱情',
            emp1: '乡村爱情-赵四',
            emp2: '乡村爱情-刘能'
        },
        methods:{
            changeCompany: function (){
                this.company = '东北F2';
            }
        },
        watch: {
            company: function(newCompany){
                this.emp1 = newCompany+ '-赵四';
                this.emp2 = newCompany+ '-刘能';
            }
        }
    })
</script>

运行结果:点击按钮后切换两位emp的名字前缀。
此时两个数据emp1和emp2全部依赖于数据company


4.7 表单绑定

v-bind实现了数据的单向绑定,将vue实例中的数据同元素属性值进行单向绑定.vue也支持数据双向绑定,这时使用v-model在控件上实现数据的双向绑定。

<div id="demo">
    输入:<input type="text" v-model="message"><br>
    <div>{{message}}</div>      
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            message: ''
        }
    })
</script>

运行结果:文本框输入内容会自动显示在其下方的div
控制台更改demo.message的值,文本框中的内容也会改变

指令 特点
v-model 类似oninput事件
v-model.lazy 类似onblur事件
<div id="demo">
    输入1:<input type="number" v-model.number="message1"><br>
    输入2:<input type="number" v-model="message2"><br>
    <div>内容1:{{message1}},类型:{{mess1type}}</div>        
    <div>内容2:{{message2}},类型:{{mess2type}}</div>        
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            message1: 0,
            message2: 0
        },
        computed:{
            mess1type: function(){
                return typeof(this.message1);
            },
            mess2type: function(){
                return typeof(this.message2);
            }
        }
    })
</script>

运行结果


运行结果
<div id="demo">
        <input v-model.trim="mess3">
        <p>mess3 is :{{ mess3 }}</p>
</div>
<script>
        var demo = new Vue({
            el:'#demo',
            data:{
                mess3:''
            },
        })
</script>

运行结果


运行结果
4.8 过滤器

在vue2.0以前的版本中vue内置的过滤器,但是因为缺乏纯JavaScript的灵活性,在vue2.0版本中已经删除了内置过滤器,所以需要自己注册过滤器。
可以定义本地(在某一个template里面定义filter)过滤器,或者定义全局(global)过滤器。如果定义了一个全局过滤器,它必须在Vue实列之前声明。

<div id="demo">
    {{message1 | showTime}}<br>
    {{message2 | showTime}}<br>
</div>
<script>
    Vue.filter("showTime", function (value){
        return value+"["+new Date()+"]";
    });
    var demo = new Vue({
        el: '#demo',
        data: {
            message1: "你好",
            message2: "测试"
        }
    })
</script>

运行结果:


运行结果

本地过滤器存储在vue组件中,作为filters属性中的函数,我们可以注册多个过滤器存储在其中。

<div id="demo">
    {{message}}<br>
    {{message | reverse}}<br>
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            message: "这是一段测试文本"
        },
        filters:{
            reverse:function (value){
                value = value.toString();
                return value.split('').reverse().join('');
            }
        }
    })
</script>

运行结果


运行结果

过滤器除了单独使用之外,我们还可以对过滤器进行串联使用,也可以在v-bind中使用过滤器,语法与{{format}}中的语法一致。

<div id="demo">
    {{message}}<br>
    {{message | reverse}}<br>
    {{message | length}}<br>
    {{message | reverse | length}}<br>
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            message: "这是一段测试文本"
        },
        filters:{
            reverse:function (value){
                value = value.toString();
                return value.split('').reverse().join('');
            },
            length: function(value){
                value = value.toString();
                return "文本\""+value+"\"的长度:"+value.length;
            }
        }
    })
</script>

运行结果:


运行结果
<div id="demo">
    {{message}}<br>
    {{message | test(1,2)}}<br>
    {{message | test(2,3)}}<br>
</div>
<script>
    var demo = new Vue({
        el: '#demo',
        data: {
            message: 5
        },
        filters:{
            test:function (value, x, y){
                value = Number(value);
                return value*x*y;
            }
        }
    })
</script>

运行结果


运行结果
<div id="demo">
    <input type="text" v-model="msg | currencyDisplay"><br>
    <span>{{msg}}</span>
</div>
<script>
    Vue.filter('currencyDisplay', {
        // model -> view
        // 在更新 `<input>` 元素之前格式化值
        read: function(val) {
            return '¥' + val.toFixed(2);
        },
        // view -> model
        // 在写回数据之前格式化值
        write: function(val, oldVal) {
            var number = +val.replace(/[^\d.]/g, '');
            return isNaN(number) ? 0 : parseFloat(number.toFixed(2));
        }
    })
    var demo = new Vue({
        el:"#demo",
        data: {
            msg:1024
        }
    })
</script>

4.9 自定义指令

除了核心功能默认内置的指令外,vue也允许用户注册自定义指令。虽然在vue2.0中,代码复用和抽象的主要形式是组件,但是有些情况下,仍需要对普通DOM元素进行底层操作,这个时候就需要用到自定义指令。

<div id="demo">
    <div>{{message}}</div>
    <div v-red>{{message}}</div>
</div>
<script>
    Vue.directive('red', function (el){
        el.style.color = 'red';
    })      
    var demo = new Vue({
        el:"#demo",
        data: {
            message:"测试文本"
        }
    })
</script>

运行结果


运行结果

传参前需要保证传参的值在vue的data中有声明,调用时需要通过data.value的方式调出具体的值。

<div id="demo">
    <div>{{message}}</div>
    <div v-color='red'>{{message}}</div>
    <div v-color='blue'>{{message}}</div>
</div>
<script>
    Vue.directive('color',{
        bind: function(el, c) {
            el.style.color = c.value;
        }
    })
    var demo = new Vue({
        el: "#demo",
        data: {
            message: "测试文本",
            red: 'red',
            blue: 'blue'
        }
    })
</script>
指令 特点
bind 每当指令绑定到元素上的时候,会立即执行且只执行一次
inserted 元素插入到DOM中的时候,会执行inserted函数且只执行一次
updated 当VNode更新的时候,会执行updated,可能会触发多次
<div id="demo">
    输入1:<input type="text" v-model="message"><br>
    输入2:<input type="text" v-model="message" v-focus><br>
</div>
<script>
    Vue.directive('focus',{
        inserted: function(el) {
            el.focus();
        }
    });
    var demo = new Vue({
        el: "#demo",
        data: {
            message: "测试文本"
        }
    })
</script>

运行结果


输入2进入页面时获得焦点
上一篇下一篇

猜你喜欢

热点阅读