「vue基础」新手入门篇(一)

开篇

自从Facebook2013年推出React框架以来,基于UI组件的前端框架越来越流行,主要得益于组件的重用性,数据状态的管理等特性。

谷歌也推出了基于组件的第二代Angular框架,致力于开发全平台应用——Web、移动 Web、移动应用、原生应用和桌面原生应用,其最为核心的特点是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。

后期之秀Vue.js,其作者尤雨溪在谷歌就职时创建并于2014年发布,自发布以来,由于其设计灵活,方便集成到现有项目中,并能轻松构建复杂的应用程序,因此Vuejs大受欢迎,现在成为三大前端主流框架之一。

本篇文章阅读时间预计10分钟。

01

为什么选择Vue?

在你阅读本文时,你一定疑惑为什么选择Vue,以下的几个理由是不是能打动你选择Vue?

1、很容易集成上手 到现有项目。你可以在现有的网站中轻松集成Vue,无需引入新的工具设置复杂的流程,如果你习惯使用jQuery,那你也很容易上手Vue的。

2、基于组件的架构。允许应用程序模块化,组件化,方便快速构建现代化的单页面应用程序(SPA)。

3、生态的完整性。几乎你能想到的插件,你都能在社区里找到。更重要的是,其重要的的库比如路由,状态管理等都是有Vue官方团队进行维护,不像React生态,官方并不是很积极的提供解决方案。

4、 广泛的使用。从国外的GitLab到国内的阿里巴巴,尤其国内越来越多公司的使用,让其成为国内前端必备技能。同时Vue.js成为PHP流行框架Laravel的默认前端库。由于其使用的广泛性,未来会有更多的人去投入到这个框架中,让其生态更加强大,受益最大的就是我们每位开发者。

02

让我们开始行动吧!

首先说明下,通过本篇Vue.js基础知识的学习,笔者将带着大家完成如下图所示的练习:

主要实现以下功能:

  • 完成页面效果的布局

  • 引入Vue框架,实现数据的渲染

  • 点击表头,实现信息按照表头的属性进行排序

引入Vue

为了方便大家快速入门Vue, 本篇文章用最简单的JS文件引入方式来引入Vue框架,下篇文章笔者将详细介绍用构建的方式创建vue项目,如下所示新建一个index.html文件引入Vue文件:

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

注:引入开发版是为了方便我们进行开发和调试,生产环境应该引入vue.min.js版本

接下来我们创建Vue实例,代码如下:

new Vue({
    el: "#main"
});

此段代码的意思就是声明Vue实例,并查找DOM的id等于main的元素,用于接下来的数据内容呈现。

加载数据

为了让上述Vue的实例,加载数据,我们需要提供数据。Vue内提供data属性,用于加载数据源。data属性是响应式的,当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值,并影响UI的显示。

接下来我们在data属性里添加一些数据,在实际的应用场景,你会通过接口请求数据,为了方便演示,我们写死一些数据,示例如下:

new Vue({
    el: "#main",
    data: {
        heading: "前端达人开发部",
        employees: [
            {
                "firstName": "amelia",
                "lastName": "austin",
                "photoUrl": "https://www.qianduandaren.com/demo/vue/img/women/1.jpg",
                "email": "amelia.austin@example.com",
                "phone": "(651)-507-3705",
                "department": "Engineering"
            },
            {
                "firstName": "bobbie",
                "lastName": "murphy",
                "photoUrl": "https://www.qianduandaren.com/demo/vue/img/women/2.jpg",
                "email": "bobbie.murphy@example.com",
                "phone": "(925)-667-7604",
                "department": "Management"
            }
        ]
    }
});

模板语法{{}}

现在我们有了数据,就需要进行界面数据的渲染和呈现,我们需要使用模板语法——一双大括号 ( {{}} ),进行数据绑定。如下段代码所示:

<h1 className="ui center aligned header">{{heading}}h1>

你可以在这双大括号里包含任何有效的JavaScrip代码,如下所示,我们在其包含了一个运算语句:

<div id="app">
    <p>The price is: ¥{{ price * 1.20 }} (inc. VAT)p>
div>
<script>
new Vue({
    el: '#app',
    data: {
        price: 25
    }
});
script>

双括号区域将会显示:

The price is: ¥30 (inc. VAT)

在实例中,界面呈现前执行了JS语句的运算并将值进行显示。

指令

实现更复杂的页面程序,不能只是简简单单的数据呈现,因此Vue的模板语法还包含循环和条件显示的逻辑指令,让我们更好的处理页面展现逻辑。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM。(类似AngularJS的ng-*指令)

1、v-for

前面我们介绍了加载数据的示例,你可能猜到了我们需要使用循环遍历的方式遍历集合用于数据的展现,v-for指令的作用就是遍历数据集合中的每项内容,如下段代码所示:

<tbody>
<tr v-for="employee in employees">
    <td>
        <img src="https://www.qianduandaren.com/demo/vue/img/women/1.jpg"
             className="ui mini rounded image"/>
    td>
    <td>{{employee.firstName}}td>
    <td>{{employee.lastName}}td>
    <td>{{employee.email}}td>
    <td>{{employee.phone}}td>
    <td>{{employee.department}}td>
tr>
tbody>

从上述代码我们可以看出,我们在tr的属性里,添加了v-for指令,其代表在此DOM区域内进行循环,我们在此循环显示了雇员的信息。在这里我们将图片的src属性写死了,下面我们很快会介绍到用新的指令进行替代。

与react一样,在Vue中渲染列表时,强烈建议您为每个元素提供一个唯一的键。这有助于Vue框架在添加和删除元素时进行优化。你可以使用 :key 指令定义唯一的键值:

<tr v-for="user in users" :key="user.id>

如果实在没有唯一的键值,你可以使用数组索引,示例代码如下:

<tr v-for="(employee, index) in employees" :key="index">..tr>

2、v-if

另一个常见的指令就是条件渲染,v-if 只有当data属性或表达式的计算结果为true时,使用该指令才会导致Vue呈现元素,如下段代码所示:

<tbody>
<tr v-for="employee in employees">
    ...
tr>
<tr v-if="employees.length === 0">
    <td colSpan="6">No employees foundtd>
tr>
tbody>

上述代码如果employee为空,则会显示 No employees found 的信息,这对于我们日后调用API加载数据的逻辑处理十分有用。

有v-if指令,自然会有v-else-if指令处理更复杂的条件处理,如下段代码所示:

<tbody>
<tr v-for="employee in employees"> ...tr>
<tr v-if="isLoadingData">
    <td colSpan="6"><img src="spinner.gif"/>td>
tr>
<tr v-else-if="employees.length === 0">
    <td colSpan="6">No employees foundtd>
tr>
tbody>

从上述代码中,我们加入了一个 isLoadingData 属性,这在我们动态加载数据的逻辑处理十分有用,因为是异步加载数据涉及网络延迟等问题,数据加载前需要有个信息提示用户数据正在加载中。

3、v-bind

有时候,你需要将数据绑定到html元素的属性上,例如url上的href属性,img的src属性。

还记得我们上面的例子,我们渲染数据时把img属性写死了,现在我们可以使用v-bind指令进行数据绑定,代码如下:

<img v-bind:src="employee.photoUrl" className="ui mini rounded image"/>

除了上述写法外,我们可以用更简短的语法,只需要在属性前使用:前缀即可,代码如下:

<img :src="employee.photoUrl" class="ui mini rounded image" />

4、v-model

Vue还支持表单双向绑定的概念,允许我们通过表单输入动态更改数据的内容,如下段代码所示:

<div id="app">
    <input v-model="text" placeholder="edit me">
        <p>Text is: {{ text }}p>
div>
<script>
    new Vue({
    el: '#app',
    data: {
    text: 'Good golly, Miss Molly'
}
});
script>

从上面的示例中,v-model指令将数据绑定到表单输入框内,我们更改输入框的值,p标签区域的内容也随之改变。

5、v-on

我们可以使用v-on:绑定事件监听器,事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。

如下段代码所示,逻辑简单,点击按钮,将数据heading的属性更改为Hello World,我们实现了内联语句的绑定:

<button v-on:click="heading = 'Hello World!'">Click Mebutton>

除了使用 v-on:click 语法外,我们可以使用更短的语法进行绑定——@click, 在上面的例子我们实现了数据内容的更改,我们还可以绑定用户自定义方法,如下段代码所示:

js部分:

new Vue({
    el: "#main",
    data: {
        status: ""
    },
    methods: {
        updateStatus(event) {
            const buttons = ['left', 'middle', 'right'];
            this.status = `You clicked the ${buttons[event.button]} button.`;
        }
    }
});

Html部分:

<div id="main">
    <button @mousedown="updateStatus" @contextmenu.prevent="">Toggle Me!button>
<p>{{ status }}p>
div>

上述代码,我们将mousedown事件绑定了updateStatus方法,用于帮助用户确定是点击了鼠标左键还是右键,同时我们添加了第二个事件监听contextmenu.prevent,用来阻止鼠标右键默认的上下文菜单行为。类似的还有其它常见事件修饰符:

  • .stop:阻止事件冒泡。

  • .prevent:阻止浏览器默认行为,比如页面滚动等。

  • .capture:翻转事件传播方向,本来事件是按照最内元素到外元素执行的,叫事件冒泡,.capture正好相反,让元素从外到内传播事件。

  • .self:元素只在绑定的元素上执行。

  • .once:绑定的事件只执行一次,之后失效。

Methods

Vue对象里专门有Methods的属性,方便我们自定义相关的方法,并在模板里很容易的调用,正如上个示例,我们是这样定义方法的:

methods: {
    updateStatus(event) {
        const buttons = ['left', 'middle', 'right'];
        this.status = `You clicked the ${buttons[event.button]} button.`;
    }
}

Computed

有时候你需要自定义相关的方法监听计算模板中的数据并进行相应,如果你想避免不必要的方法开销,你可以使用Vue的“计算属性”方案。

一个计算属性其实就是一个函数,用来缓存和返回数据。其函数依赖一个数据项,数据项发生改变,其函数就要重新运算,进行新的数据输出。

为了实践这个属性,我们在数据项里增加一个排序字段属性,如下所示:

data: {
    heading: "Staff Directory",
        sortBy: "firstName"
    employees: [
        ...
    ]
}

接下来,我们在标题列里添加点击处理事件,以便更改sortBy的属性,如下段代码所示:

<tr>
    <th>Avatarth>
    <th @click="sortBy = 'firstName'">First Nameth>
<th @click="sortBy = 'lastName'">Last Nameth>
<th @click="sortBy = 'email'">Emailth>
<th @click="sortBy = 'phone'">Phoneth>
<th @click="sortBy = 'department'">Departmentth>
tr>

最后,让我们在Vue属性中,添加一个计算属性,该属性根据键值进行数据排序,如下段代码所示:

computed: {
    sortedEmployees() {
        return this.employees.sort((a, b) => a[this.sortBy].localeCompare(b[this.sortBy]))
    }
}

接下来我们更改v-for区域的代码,将我们的计算属性添加进去,示例代码如下:

<tr v-for="(employee, index) in sortedEmployees" :key="index">
...
tr>

由于Vue语句提供的语法糖,输出数据sortedEmployees被缓存,当sortBy属性改变时,sortedEmployees的值将会重新计算。

03

最终完成后的代码

基于前面的知识内容,我们最终完成的index.html代码如下,你可以点击原文链接预览效果(请在pc端预览):

html>
lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue新手入门篇(一)title>
    <link rel="stylesheet" href="https://www.qianduandaren.com/demo/vue/css/semantic.min.css">
    <style>
        h1.ui.center.header {
            margin-top: 3em;
        }
    style>
head>
<body>
<main id="main">
    <h1 class="ui center aligned header">{{ heading }}h1>
    <div class="ui container">
        <table class="ui celled table">
            <thead>
            <tr>
                <th>Avatarth>
                <th @click="sortBy = 'firstName'">First Nameth>
                <th @click="sortBy = 'lastName'">Last Nameth>
                <th @click="sortBy = 'email'">Emailth>
                <th @click="sortBy = 'phone'">Phoneth>
                <th @click="sortBy = 'department'">Departmentth>
            tr>
            thead>
            <tbody>
            <tr v-for="(employee, index) in sortedEmployees" :key="index">
                <td>
                    <img :src="employee.photoUrl" class="ui mini rounded image" />
                td>
                <td>{{ employee.firstName }}td>
                <td>{{ employee.lastName }}td>
                <td>{{ employee.email }}td>
                <td>{{ employee.phone }}td>
                <td>{{ employee.department }}td>
            tr>
            tbody>
            <tfoot>
            <tr>
                <th colspan="6">th>
            tr>
            tfoot>
        table>
    div>
main>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>
    new Vue({
        el: "#main",
        data: {
            heading: "前端达人开发部",
            sortBy: 'department',
            employees: [
                {
                    "firstName": "amelia",
                    "lastName": "austin",
                    "photoUrl": "https://www.qianduandaren.com/demo/vue/img/women/1.jpg",
                    "email": "amelia.austin@example.com",
                    "phone": "(651)-507-3705",
                    "department": "Engineering"
                },
                {
                    "firstName": "bobbie",
                    "lastName": "murphy",
                    "photoUrl": "https://www.qianduandaren.com/demo/vue/img/women/2.jpg",
                    "email": "bobbie.murphy@example.com",
                    "phone": "(925)-667-7604",
                    "department": "Management"
                },
                {
                    "firstName": "kristin",
                    "lastName": "terry",
                    "photoUrl": "https://www.qianduandaren.com/demo/vue/img/women/3.jpg",
                    "email": "kristin.terry@example.com",
                    "phone": "(021)-544-1184",
                    "department": "Sales"
                },
                {
                    "firstName": "brandon",
                    "lastName": "griffin",
                    "photoUrl": "https://www.qianduandaren.com/demo/vue/img/men/1.jpg",
                    "email": "brandon.griffin@example.com",
                    "phone": "(509)-317-9506",
                    "department": "Management"
                },
                {
                    "firstName": "tammy",
                    "lastName": "gibson",
                    "photoUrl": "https://www.qianduandaren.com/demo/vue/img/women/4.jpg",
                    "email": "tammy.gibson@example.com",
                    "phone": "(815)-727-0663",
                    "department": "Support"
                },
            ]
        },
        computed: {
            sortedEmployees() {
                return this.employees.sort((a, b) => a[this.sortBy].localeCompare(b[this.sortBy]));
            }
        }
    });
script>
body>

本篇文章的内容就到这里,接下来给大家留个作业题(答案将在下期文章进行公布),基于本文的例子,我们增加一个输入框,实现雇员信息的检索功能(输入雇员的全名或名字的部分内容,显示信息结果)。在下篇文章里,我将继续介绍如何工程化的构建Vue项目和Vue相关的工具,敬请期待。

专注分享当下最实用的前后端技术。关注全栈学习笔记,与我一起学习进步!

长按关注"全栈学习笔记"