JS 流行框架(一):Vue

JS 流行框架(一):Vue

Vue 介绍

Vue.js 是一套构建用户界面的框架,不仅容易上手,而且可以和第三方库组合使用,学习框架可以提高开发效率,发展历程:

  1. 原生 JavaScript
  2. jQuery
  3. 模板引擎
  4. Vue / React / Angular

Vue、Angular 和 React 一起被称为前端三大框架,Vue 由国人编写,且在 Vue 中包含了 Angular 和 React 的许多优点

框架是一套完整的解决方案,如果项目必须更换框架,那么必须重构项目,库(插件)仅提供某个功能,如果某个库无法完成需要,那么可以很容易切换到其它库以实现需求

Vue 的优势如下:

  1. 通过数据驱动界面更新,不使用 DOM 来更新界面,在开发时,我们只需要关注如何获取和处理数据即可,Vue 可以自动将数据渲染到模板中(界面上)
  2. 组件化开发,我们可以将网页拆分成若干个独立的组件编写,以后可以将封装好的组件组装成一个完整的网页

基本使用

  1. 下载 Vue.js

Vue2.7.10 版本 下载地址

  1. 导入 Vue.js
<script src="./js/vue.js"></script>
  1. 创建一个元素
<div id="app">{
  
  { name }}</div>
  1. 创建一个 Vue 实例、关联元素、数据
/* 创建一个 Vue 实例 */
let vue = new Vue({
   
   
    el: "#app", /* 关联元素 */
    data: {
   
        /* 数据 */
        name: "Reyn Morales"
    }
});

数据绑定

Vue 是基于 MVVM 设计模式实现的,MVVM 设计模式由 3 部分组成:

  • Model(M)
    • 数据模型
    • 相当于 Vue 实例
  • View(V)
    • 视图
    • 相当于被 Vue 实例关联的元素
  • View-Model(VM)
    • 视图-数据模型(关联视图与数据模型的桥梁)
    • 相当于 Vue 实例中的 data 属性

MVVM 设计模式最大的特点是支持数据的双向传递,即可以将数据从 View 通过 View-Model 传递到 Model 中,也可以将数据从 Model 通过 View-Model 传递到 View 中

单向

Vue 默认情况下仅支持数据的单向绑定:Model -> View-Model -> View,当 Vue 实例中的 data 属性中的数据发生变化时,被 Vue 实例所关联的元素中的相应内容也随之改变

双向

Vue 在被关联的元素为 input、textarea 和 select 时可以通过 v-model 指令实现数据的双向绑定,示例如下:

<div id="app">
    <input type="text" v-model="content">
</div>
<script>
    let vue = new Vue({
     
     
        el: "#app",
        data: {
     
     
            content: "Reyn Morales"
        }
    })
</script>

上述示例中,若 input 元素中的内容发生变化时,与之关联的 Vue 实例中 data 属性下的 content 属性的内容也随之改变,此情形可以通过 Vue 调试工具(vue-js-devtools)观察,v-model 本质上是一个自定义属性,凡是具有此属性的表单元素将自动忽略 value、checked、selected 等属性的初始值,总是以 Vue 实例中相关的数据作为来源

常用指令

指令即为 Vue 内部定义的某些自定义属性,通过这些自定义属性可以实现某些功能,例如 v-model 属性可以在表单相关元素上实现数据的双向绑定,以下内容是 Vue 预定义的其它指令

v-once

指令 v-once 的作用是让绑定此指令的元素中的数据只被渲染一次,之后不再随着数据的变化而改变,示例如下:

  • HTML
<div id="app">
    <p v-once>原始数据:{
  
  { number }}</p>
    <p>当前数据:{
  
  { number }}</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        number: 521
    }
});

上述示例中,如果通过 Vue 调试工具修改 number 的数值,那么随之改变的只有 “当前数据” 所在行中的插值,“原始数据” 所在行中的插值不再改变

v-cloak

默认情况下,Vue 的简易渲染流程如下所示:

  1. 渲染原始元素(未绑定数据)
    2. 拷贝原始元素、加载 Vue 实例中关联的元素中的数据到拷贝元素中
    3. 将绑定数据之后的拷贝元素替换原始元素

由于在替换原始元素之前,Vue 将显示模板内容(未绑定数据的原始元素),所以如果用户的网速较慢或网页性能较差,那么用户将看到模板内容

指令 v-cloak 的作用是让绑定此指令的元素在未绑定数据之前隐藏,直到绑定数据之后再显示,示例如下:

  • CSS
[v-cloak] {
   
   
    display: none
}
  • HTML
<div id="app">
    <p v-cloak>{
  
  { name }}</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        name: "Reyn Morales"
    }
});

v-text

指令 v-text 的作用是替换绑定此指令的元素的内容,不解析 HTML 代码,类似于 JavaScript 中的 innerText,示例如下:

  • HTML
<div id="app">
    <p v-text="name">填充内容</p>
    <p v-text="msg">填充内容</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        name: "Reyn Morales",
        msg: "<span>Never Give Up!</span>"
    }
});

v-html

指令 v-html 的作用是替换绑定此指令的元素的内容,解析 HTML 代码,类似于 JavaScript 中的 innerHTML,示例如下:

  • HTML
<div id="app">
    <p v-html="name">填充内容</p>
    <p v-html="msg">填充内容</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        name: "Reyn Morales",
        msg: "<span>Never Give Up!</span>"
    }
});

v-if

指令 v-if、v-else-if 和 v-else 的作用是条件渲染,类似于 JavaScript 中的 if-else 语句,当条件表达式的结果为真实渲染此元素,否则就不渲染此元素,示例如下:

  • HTML
<div id="app">
    <p v-if="score >= 90">优秀</p>
    <p v-else-if="score > 70">良好</p>
    <p v-else-if="score > 60">及格</p>
    <p v-else>不及格</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        score: 88
    }
});

如果使用 v-if 指令,那么通过调试工具查看页面结构时,凡是条件表达式为 false 的元素压根就不会被渲染出来,上述示例中,v-if 相关的取值可以是模型中的数据,也可以是一个表达式,此外,必须注意的是:

  • 指令 v-else 不能单独出现
    • 指令 v-if、v-else-if 和 v-else 之间不能出现任何内容

v-show

指令 v-show 的作用类似于指令 v-if,都可以用于条件渲染,区别在于前者将元素隐藏,后者将元素删除,示例如下:

  • HTML
<div id="app">
    <p v-show="show">被显示的元素</p>
    <p v-show="hidden">被隐藏的元素</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        show: true,
        hidden: false
    }
});

上述示例中,如果通过调式工具查看页面结构时,如果条件表达式的结果为 false,那么元素将被动态赋予 style 属性以通过 display 样式控制元素的显示和隐藏

v-for

指令 v-for 类似于 JavaScript 中的 for…in 循环,可以根据遍历的对象渲染若干个元素,指令 v-for 可以遍历的对象有数组、字符串、数字和实例,示例如下:

  • HTML
<div id="app">
    <h3>遍历数组</h3>
    <ul>
        <li v-for="(value, index) in people">{
  
  { index }} --- {
  
  { value }}</li>
    </ul>

    <h3>遍历数字</h3>
    <ul>
        <li v-for="(value, index) in 10">{
  
  { index }} --- {
  
  { value }}</li>
    </ul>

    <h3>遍历字符串</h3>
    <ul>
        <li v-for="(value, index) in 'Reyn'">{
  
  { index }} --- {
  
  { value }}</li>
    </ul>

    <h3>遍历实例</h3>
    <ul>
        <li v-for="(value, key) in info">{
  
  { key }} --- {
  
  { value }}</li>
    </ul>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        people: ["reyn", "jane", "lily", "jack"],
        info: {
   
   
            name: "Reyn Morales",
            age: 21,
            gender: "male",
            addr: "sxu"
        }
    }
});

Vue 中的 v-for 实际上可以嵌套循环,示例如下:

  • HTML
<div id="app">
    <ul v-for="(obj, index) in userInfo">
        <h3>User {
  
  { index + 1 }}</h3>
        <li v-for="(value, key) in obj">{
  
  { key }} --- {
  
  { value }}</li>
    </ul>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        userInfo: [
            {
   
   
                name: "Reyn",
                age: 21,
                gender: "male"
            },
            {
   
   
                name: "Jane",
                age: 20,
                gender: "female"
            },
            {
   
   
                name: "Jack",
                age: 23,
                gender: "male"
            }
        ]
    }
});

必须注意的是,v-for 为了提升性能,在更新已渲染过的元素列表时,将采用 “就地复用” 的策略,正是由于此策略在某些时刻将导致数据出现混乱,示例如下:

  • HTML
<div id="app">
    <form>
        <input type="text" v-model="newName">
        <input type="submit" value="新增" @click.prevent="insertPerson">
    </form>
    <ul>
        <li v-for="(person, index) in people">
            <input type="checkbox">
            <span>{
  
  { index }} --- {
  
  { person.name }}</span>
        </li>
    </ul>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        newName: "",
        people: [
            {
   
   
                name: "reyn"
            },
            {
   
   
                name: "lily"
            },
            {
   
   
                name: "jack"
            }
        ]
    },
    methods: {
   
   
        insertPerson: function () {
   
   
            let newPerson = {
   
    name: this.newName };
            this.people.unshift(newPerson);
            this.newName = "";
        }
    }
});

在上述示例中,若选中名称为 lily 的复选框,然后再表单中新增一个名称为 jhon 的数据,那么此时被选中的数据将不再是 lily,而是 reyn,出现此现象的原因在于,通过指令 v-for 渲染若干元素时,在每添加一个元素时,将检查缓存中是否存在此格式的元素,若存在,那么将 “就地复用” 此元素,将此旧元素渲染到界面上,若不存在,那么将创建一个新的元素,并将此新元素渲染到网页上,由于每添加一个元素时,指令 v-for 格式化原界面上的内容,并重新根据缓存中已存在的数据渲染,所以在添加第一条数据时(jhon),指令 v-for 将采用缓存中原本渲染 reyn 的元素,渲染 reyn 时将采用缓存中原本渲染 lily 的元素,由于此元素之前被选中,所以新渲染的 reyn 也自然被选中,依次类推,渲染 lily 时将采用缓存中原本渲染 jack 的元素,而在渲染 jack 时,缓存中已经没有元素可以使用了,所以将在缓存中创建一个新的元素用来渲染 jack

解决此问题的方案也很简单,为每个元素绑定一个独一无二的 key 值即可,在渲染时,指令 v-for 除了将匹配元素格式之外,也将比较被渲染的元素和缓存中的元素的 key 是否相同,如此一来就不会出现缓存和界面上元素匹配混乱的情况了,示例如下:

  • HTML
<div id="app">
    <form>
        <input type="text" v-model="newName">
        <input type="submit" value="新增" @click.prevent="insertPerson">
    </form>
    <ul>
        <li v-for="(person, index) in people" v-bind:key="person.id">
            <input type="checkbox">
            <span>{
  
  { index }} --- {
  
  { person.name }}</span>
        </li>
    </ul>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        newName: "",
        people: [
            {
   
   
                id: 1,
                name: "reyn"
            },
            {
   
   
                id: 2,
                name: "lily"
            },
            {
   
   
                id: 3,
                name: "jack "
            }
        ],
        globalID: 4,
    },
    methods: {
   
   
        insertPerson: function () {
   
   
            let newPerson = {
   
    id: this.globalID++, name: this.newName };
            this.people.unshift(newPerson);
            this.newName = "";
        }
    }
});

必须注意的是,通过指令 v-bind 为元素的 key 属性绑定值时,一定不能使用指令 v-for 循环中的 index 索引,原因在于循环中的 index 索引都是动态生成的,且每次循环都是从 0 开始,如此并不能解决匹配混乱的问题

v-bind

不论是 Vue 中的插值,还是 v-text、v-html 指令,都用于为元素内容绑定数据,而指令 v-bind 则用于为元素属性绑定数据,示例如下:

  • HTML
<div id="app">
    <input v-bind:type="inputType">
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        inputType: "text"
    }
});

实际上,v-bind 指令可以简写为 :,且属性值可以是一个 JavaScript 表达式,示例如下:

  • HTML
<div id="app">
    <input v-bind:type="inputType" :maxlength="maxLen + 3">
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        inputType: "text",
        maxLen: 7
    }
});

必须注意的是,对于元素的 class 或 style 属性而言,v-bind 的格式比较特殊

class

通过指令 v-bind 为元素的 class 属性添加类名时,必须将每个类名以单引号包裹并将所有类名放在一个数组中才能保证类名来自于 style 元素而非 Vue 实例的数据模型,示例如下:

  • CSS
.size {
   
   
    font-size: 100px;
}

.color {
   
   
    color: red;
}

.bg-color {
   
   
    background-color: skyblue;
}
  • HTML
<div id="app">
    <p :class="['size', 'color', 'bg-color']">Reyn Morales</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app"
});

此外,通过 v-bind 为 class 属性绑定类名时可以通过三目运算符或实例对象实现是否绑定类名的功能,示例如下:

  • HTML
<div id="app">
    <p :class="['size', { 'color': true }, isActive ? 'bg-color' : '']">Reyn Morales</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        isActive: false
    }
});

实际上,上述示例的样式可以通过 Vue 实例中的数据模型实现,示例如下:

  • HTML
<div id="app">
    <p :class="styleObj">Reyn Morales</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        styleObj: {
   
   
            'size': true,
            'color': true,
            'bg-color': false
        }
    }
});
style

通过指令 v-bind 为元素的 style 属性添加样式时,必须将每个属性及其取值以键值对的形式放在一个实例中,属性值必须被单引号包裹,若属性名称中具有连字符,那么此属性名称也必须被单引号包裹,示例如下:

  • HTML
<div id="app">
    <p :style="{ color: 'red', 'font-size': '100px' }">Reyn Morales</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app"
});

实际上,可以直接将 Vue 中的一个保存样式代码的实例传递给 style 属性,示例如下:

  • HTML
<div id="app">
    <p :style="styleObj">Reyn Morales</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        styleObj: {
   
   
            color: 'red',
            'font-size': '100px',
            'background-color': 'blue'
        }
    }
});

如果样式代码被保存到多个实例中,那么可以将所有实例以数组的形式传递给 style 属性,示例如下:

  • HTML
<div id="app">
    <p :style="[style1, style2]">Reyn Morales</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        style1: {
   
   
            color: 'pink',
        },
        style2: {
   
   
            'font-size': '100px',
            'background-color': 'skyblue'
        }
    }
});

v-on

指令 v-on 用于为元素绑定事件监听,示例如下:

  • HTML
<div id="app">
    <button v-on:click="myFn">{
  
  { content }}</button>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        content: "Click Me!"
    },
    methods: {
   
   
        myFn: function () {
   
   
            console.log("Reyn Morales");
        }
    }
});

上述示例中,必须注意的是,事件名称不用写为 onclick,此外,所有事件函数都必须写在 Vue 实例的 methods 属性中

实际上,v-on 指令可以简写为 @,且可以向回调函数传递参数,示例如下:

  • HTML
<div id="app">
    <button @click="myFn('Reyn Morales', $event)">{
  
  { content }}</button>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        content: "Click Me!"
    },
    methods: {
   
   
        myFn: function (name, event) {
   
   
            console.log(name);
            console.log(event);
            console.log(this.content);
        }
    }
});

上述示例中,必须注意的是,$event 即为事件对象,此外,在事件回调函数中可以通过 this 访问 Vue 实例数据模型中的数据

此外,Vue 中通过 v-on 修饰符处理常见的诸如事件冒泡、事件捕获等问题

修饰符
事件

我们可以通过事件修饰符快速实现关闭事件冒泡、开启事件捕获、阻止元素默认行为等功能

.once

不论事件被如何触发,均只调用一次回调函数,示例如下:

  • HTML
<div id="app">
    <button @click.once="myFn">Click Me!</button>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        myFn: function () {
   
   
            console.log("Hello World!");
        }
    }
});
.prevent

阻止元素默认行为,类似于调用 event.preventDefault(),示例如下:

  • HTML
<div id="app">
    <a href="https://yingxinlau.blog.youkuaiyun.com/" @click.prevent="myFn">我的博客</a>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        myFn: function () {
   
   
            console.log("Hello World!");
        }
    }
});
.stop

阻止事件冒泡,类似于调用 event.stopPropagation(),示例如下:

  • CSS
.grand {
   
   
    width: 300px;
    height: 300px;
    background-color: red;
}

.father {
   
   
    width: 200px;
    height: 200px;
    background-color: orange;
}

.son {
   
   
    width: 100px;
    height: 100px;
    background-color: yellow;
}
  • HTML
<div id="app">
    <div class="grand" @click="gFn">
        <div class="father" @click="fFn">
            <div class="son" @click.stop="sFn"></div>
        </div>
    </div>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        gFn: function () {
   
   
            console.log("Grand");
        },
        fFn: function () {
   
   
            console.log("Father");
        },
        sFn: function () {
   
   
            console.log("Son");
        }
    }
});
.self

如果以此修饰符修饰 v-on 指令,那么事件只有被绑定此事件的元素触发时才有效,通过事件冒泡或事件捕获的触发无效,示例如下:

  • HTML
<div id="app">
    <div class="grand" @click="gFn">
        <div class="father" @click.self="fFn">
            <div class="son" @click="sFn"></div>
        </div>
    </div>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        gFn: function () {
   
   
            console.log("Grand");
        },
        fFn: function () {
   
   
            console.log("Father");
        },
        sFn: function () {
   
   
            console.log("Son");
        }
    }
});
.capture

开启事件捕获,示例如下:

  • HTML
<div id="app">
    <div class="grand" @click.capture="gFn">
        <div class="father" @click.capture="fFn">
            <div class="son" @click.capture="sFn"></div>
        </div>
    </div>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        gFn: function () {
   
   
            console.log("Grand");
        },
        fFn: function () {
   
   
            console.log("Father");
        },
        sFn: function () {
   
   
            console.log("Son");
        }
    }
});
按键

我们可以通过按键修饰符快速实现监听某个特定按键所触发的事件

预定义

Vue 预定的按键修饰符如下所示:

  • enter
    • tab
    • delete
    • esc
    • space
    • up
    • down
    • left
    • right

示例如下:

  • HTML
<div id="app">
    <input type="text" @keyup.enter="myFn">
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        myFn: function () {
   
   
            alert("输入完毕");
        }
    },
});
自定义

有时预定义按键修饰符并不能满足我们的所有需求,此时可以自定义修饰符,示例如下:

  • HTML
<div id="app">
    <input type="text" @keyup.113="myFn">
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        myFn: function () {
   
   
            alert("输入完毕");
        }
    },
});

上述示例中,修饰符 113 是键盘上 F2 键所对应的数字,实际上可以通过 Vue.config.keyCodes 全局配置以提升代码的可读性,示例如下:

  • HTML
<div id="app">
    <input type="text" @keyup.f2="myFn">
</div>
  • JavaScript
Vue.config.keyCodes.f2 = 113;
let vue = new Vue({
   
   
    el: "#app",
    methods: {
   
   
        myFn: function () {
   
   
            alert("输入完毕");
        }
    },
});

计算属性

实际上,在 View 的插值中可以书写 JavaScript 表达式,示例如下:

  • HTML
<div id="app">
    <p>{
  
  { msg.split("").reverse().join("") }}</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        msg: "Reyn Morales"
    }
});

上述示例中,在被关联元素的插值中实现了将字符串翻转之后显示的业务逻辑,虽然以此形式可以实现业务逻辑,不过存在很多弊端 —— 编码和维护效率低下,为了解决此问题,Vue 提供了计算属性,示例如下:

  • HTML
<div id="app">
    <p>{
  
  { reverseMsg }}</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        msg: "Reyn Morales"
    },
    computed: {
   
   
        reverseMsg: function () {
   
   
            return this.msg.split("").reverse().join("");
        }
    }
});

上述示例中,必须注意的是,虽然 reverseMsg 以函数的形式编写,但是在 Vue 实例中它本质上是一个计算属性,所以在插值中使用时不能写 () 以调用此函数,实际上,通过方法也可以实现此功能,示例如下:

  • HTML
<div id="app">
    <p>{
  
  { myFn() }}</p>
</div>
  • JavaScript
let vue = new Vue({
   
   
    el: "#app",
    data: {
   
   
        msg: "Reyn Morales"
    },
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值