Vue 介绍

概述 Vue.js作者尤雨溪 本科:室内艺术和艺术史 硕士:美术设计和技术 硕士期间,偶然接触到了 JavaScript。 因为浓烈的兴趣,开发了目前前端三大

概述

Vue.js

作者

尤雨溪

本科:室内艺术和艺术史

硕士:美术设计和技术

硕士期间,偶然接触到了 JavaScript

因为浓烈的兴趣,开发了目前前端三大框架之首的 Vue.js(另外两个分别是 Angular.jsReact.js

他的经历完美的印证了这句话:兴趣是最好的老师。

概念

一款用于构建用户界面的渐进式 JavaScript 框架。

渐进式:Vue渐进式-先使用Vue的核心库,再根据你的需要的功能再去逐渐增加加相应的插件。

采取关注度分离原则(SOC),核心库只关注视图层(名称发音 View 的由来),其他功能由相应插件完成。

  • Axios:页面通信。
  • router:页面跳转。
  • Babel:编译工具,兼容浏览器 ES 版本。
  • WebPack:打包、压缩。

官网

https://cn.vuejs.org/v2/guide/

由于是 Vue 是中国人写的,官方文档很符合中国人的理解逻辑,看起来相对轻松。

Node.js

2009年发布。

一套 JavaScript 运行环境,类似于 JDK。

npm:项目综合管理工具,类似于 Maven。

yarn:npm 的替代方案,类似于 Maven 和 Gradle 的关系。

Node.js 的作者已经声称放弃 Node.js,说是架构做的不好再加上笨重的 node_modules,开始开发全新架构的 Deno(destroy node)。

nvm

nvm 全名 node.js version management,一个 Node.js 的版本管理工具。

通过它可以安装和切换不同版本的 Node.js 。

ElementUI

饿了么推出的基于 Vue 的桌面端组件库。

Vue 2.0 和 3.0 各有对应的组件库。

组件以 el- 开头。

组件查询:https://element.eleme.cn/

环境搭建

  1. 安装 nvm-setup.exe(Node.js 版本管理工具)。
  2. 转到安装目录下(默认目录为 C:\Users\Administrator\AppData\Roaming\nvm)。
  3. 运行命令:nvm install 版本号(安装指定版本的 Node.js)。
  4. 运行命令:nvm use 版本号(使用指定版本的 Node.js)。

部署运行

在项目下运行 npm i

npm i 不仅仅是 npm install 的简写,也存在一定的区别:

npm i 安装的模块无法用 npm uninstall 删除,用 npm uninstall i 才卸载掉。

npm i 会帮助检测与当前 node 版本最匹配的 npm 包版本号,并匹配出来相互依赖的 npm 包应该提升的版本号。

npm intall 安装报错时肯定会出现 npm-debug.log 文件,npm i 不一定。

初始化推荐 npm i,后续安装推荐 npm install

前端项目目录下运行命令

  • npm run dev:普通启动。
  • npm run start:start 执行的就是 dev 的脚本,与上个命令效果一致。
  • npm run start:support:热部署启动,推荐

基础语法

带有前缀 v- 的指令,表示它们是 Vue 提供的特殊特性。

v-bind

绑定元素(单向绑定)。

<body>
    <div id="app"> 
        <h1 v-bind:title="message">标题</h1> 
        <!-- v-bind 指令的简写形式: 冒号(:) --> 
        <h1 :title="message">标题</h1> 
    </div> 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
    <script> 
        new Vue({
            el: '#app', 
            data: { 
                message: '页面加载于 ' + new Date().toLocaleString() 
            } 
        }) 
    </script> 
</body>

v-if

条件判断语句

<body>
    <div id="app"> 
        <!--=== 三个等号在 JS 中表示绝对等于(就是数据与类型都要相等) --> 
        <h1 v-if="type === 'A'">A</h1> 
        <h1 v-else-if="type === 'B'">B</h1> 
        <h1 v-else-if="type === 'C'">C</h1> 
        <h1 v-else>who</h1> 
    </div> 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
    <script> 
        var vm = new Vue({ 
            el: '#app', 
            data: { 
                type: 'A' 
            } 
        }) 
    </script> 
</body>

v-for

循环语句

<body>
    <div id="vue"> 
        <li v-for="item in items"> 
            { { item.message } } 
        </li> 
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script><script> 
        var vm = new Vue({ 
            el: '#app', 
            data: { 
                //数组 
                items: [ 
                    {message: 'Vue.js'}, 
                    {message: 'Node.js'} 
                ] 
            } 
        }); 
    </script> 
</body>

items 是数组,item是数组元素迭代的别名。

这里和 Thymeleaf 的语法十分相似。

v-on

监听事件

<body>
    <div id="app"> 
        <!-- v-on 绑定了 click 事件,并指定了名为 sayHi 的方法 --> 
        <button v-on:click="sayHi">单击</button> 
        <!-- v-on 指令的简写形式 @ --> 
        <button @click="sayHi">单击</button> 
    </div> 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
    <script> 
        var vm = new Vue({ 
            el: '#app', 
            data: { message: 'Hello World' },
            // 方法必须定义在 Vue 实例的 methods 对象中 
            methods: { 
                sayHi: function (event) { 
                    // `this` 在方法里指向当前 Vue 实例 
                    alert(this.message); 
                }
            } 
        }); 
    </script> 
</body>

v-model

双向绑定

数据发生变化的时候,视图跟着变化。

视图发生变化的时候,数据跟着变化。

<body>
    <div id="app"> 
        <!-- v-bind:value只能进行单向的数据渲染 --> 
        <input type="text" v-bind:value="searchMap.keyWord"> 
        <!-- v-model 可以进行双向的数据绑定 --> 
        <input type="text" v-model="searchMap.keyWord"> 
        <p>绑定数据:{ { searchMap.keyWord } }</p> 
    </div> 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
    <script> 
        new Vue({ 
            el: '#app', 
            data: { 
                searchMap:{ 
                    keyWord: 'kuangshen' 
                } 
            } 
        }) 
    </script> 
</body>

用浏览器打开以上代码可以看到

改变 v-bind 绑定的输入框的值,下方的值不会改变。

改变 v-model 绑定的输入框的值,下方的值会改变。

组件

<body>
    <div id="app"> 
        <ul>
            <my-component-li v-for="item in items" v-bind:item="item"></my-component-li> 
        </ul>
    </div> 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
    <script> 
        // 先注册组件 
        Vue.component('my-component-li', { 
            props: ['item'], 
            template: '<li>Hello { {item} }</li>' 
        }); 
        // 再实例化 
        Vue var vm = new Vue({ 
            el: '#app', 
            data: { 
                items: ["张三", "李四", "王五"] 
            } 
        }); 
    </script> 
</body>

v-bind:item="item":将遍历的 item 项绑定到组件中 props 定义的名为 item 属性上。

= 号左边的 itemprops 定义的属性名,右边的 item 为 item in items 中遍历的 item 项的值。

计算属性

一个能够将计算结果缓存起来的属性。

<body>
    <div id="app"> 
        <!--注意,一个是方法,一个是属性--> 
        <p>调用当前时间的方法:{ {currentTime1()} }</p> 
        <p>当前时间的计算属性:{ {currentTime2} }</p> 
    </div> 
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
    <script> 
        var vue = new Vue({ 
            el: '#app', 
            data: { 
                message: 'Hello Vue' 
            },
            methods: { 
                currentTime1: function () { 
                    return Date.now(); 
                } 
            },
            // 存放计算属性
            computed: { 
                // currentTime2 ,这是一个属性,不是方法 
                currentTime2: function () { 
                    this.message; 
                    return Date.now(); 
                } 
            } 
        }) 
    </script> 
</body>

methods 和 computed 里的东西不能重名。

调用 methods 中的方法需要带括号。

调用 computed 中的属性不需要带括号。

如果在 computed 中的方法值发生了变化,则缓存就会刷新。

调用方法时,每次都需要进行执行,调用计算属性可以将计算结果进行缓存,节约我们的系统开销。

可以将不经常变化的计算结果放入计算属性中。

插槽

举例:制作一个待办事项组件(todo),该组件由待办标题(todo-title)和待办内容(todo-items)组成,但这三个组件又是相互独立的。

定义一个名为 todo 的待办事项组件。

<todo></todo>
<script type="text/javascript"> 
    // 定义一个待办事项的组件 
    Vue.component('todo', { 
        template: '<div>' +
        				'<slot name="todo-title"></slot>' +
        				'<ul>' +
        					'<slot name="todo-items"></slot>' +
    					'</ul>' +
				  '</div>'
    }); 
</script>

定义一个名为 todo-title 的待办标题组件。

<todo-title></todo-title>
<script type="text/javascript"> 
	Vue.component('todo-title', { 
        props: ['title'], 
        template: '<div>{ { title } }</div>' 
    });
</script>

定义一个名为 todo-items 的待办内容组件。

<todo-items></todo-items>
<script type="text/javascript"> 
	Vue.component('todo-items', { 
        props: ['item', 'index'],
        template: '<li>{ {index + 1} }. { {item} }</li>'
    });
</script>

组装

<body>
    <div id="app"> 
        <todo>
            <todo-title slot="todo-title" title="待办标题"></todo-title> 
            <todo-items slot="todo-items" v-for="(item, index) in todoItems" 
                        v-bind:item="item" v-bind:index="index"></todo-items> 
        </todo> 
    </div>
    <script type="text/javascript"> 
		new Vue({ 
            el: '#app', 
            data: { 
                todoItems: ['待办内容1', '待办内容2', '待办内容3'] 
            } 
        })
</script>
</body>

自定义事件

this.$emit('自定义事件名', 参数)

在vue的实例中,增加一个名为 removeTodoItems 的方法

<body>
    <div id="app"> 
        <todo>
            <todo-title slot="todo-title" title="待办标题"></todo-title> 
            <todo-items slot="todo-items" v-for="(item, index) in todoItems" 
                        v-bind:item="item" v-bind:index="index"
                        v-on:remove="removeTodoItems(index)">
            </todo-items> 
        </todo> 
    </div>
    <script type="text/javascript"> 
		new Vue({ 
            el: '#app', 
            data: { 
                todoItems: ['待办内容1', '待办内容2', '待办内容3'] 
            },
            methods: { 
                // 该方法可以被模板中自定义事件触发 
                removeTodoItems: function (index) { 
                    console.log("删除 " + this.todoItems[index] + " 成功"); 
                    // splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目 
                    // 其中 index 为添加/删除项目的位置,1 表示删除的数量 
                    this.todoItems.splice(index, 1); 
                } 
            } 
        })
</script>
</body>

修改 todo-items 待办内容组件的代码,增加一个删除按钮,并且绑定事件。

<todo-items></todo-items>
<script type="text/javascript"> 
	Vue.component('todo-items', { 
        props: ['item', 'index'],
        template: '<li>{ {index + 1} }. { {item} }</li><button @click="remove_component">删除</button>',
        methods: { 
            remove_component: function (index) { 
                // 这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的方式指派 
                this.$emit('remove', index); 
            } 
        }
    });
</script>

调用逻辑

@click="remove_component" ==> this.$emit('remove', index); ==> v-on:remove="removeTodoItems(index)"

路由

主要用于页面跳转。

<div id="app"> 
    <h1>Hello App!</h1> 
    <p>
    	<!-- <router-link> 默认会被渲染成一个 <a> 标签,通过传入 to 属性指定链接 --> 
        <router-link to="/student">学生管理</router-link> 
    </p> 
    <!-- 路由出口,路由匹配到的组件将渲染在这里 -->
    <router-view></router-view> 
</div>
<!--资源导入顺序不能颠倒--> 
<script src="./lib/vue.min.js"></script> 
<script src="./lib/vue-router.min.js"></script>
<script> 
    // 1. 定义(路由)组件。 
    // 复杂的组件也可以从独立的vue文件中引入 
    const Student = { template: '<div>student list</div>' } 
    // 2. 定义路由 
    // 每个路由应该映射一个组件。 
    const routes = [ 
        { path: '/student', component: Student }
    ]
    // 3. 创建 router 实例,然后传 routes 配置 
    const router = new VueRouter({ 
        routes // (缩写)相当于 routes: routes 
    })
    // 4. 创建和挂载根实例,从而让整个应用都有路由功能 
    new Vue({ 
        el: '#app', 
        router 
    }) 
</script>

Axios

由于 Vue.js 是一个视图层框架,所以并不包含 Ajax 的通信功能。

为了解决通信问题,作者单独开发了一个名为 vue- resource 的插件。

不过 2.0 版本以后停止了对该插件的维护并推荐了 **Axios **框架。

Axios 的功能用 jQuery 也可以实现,但因为它操作后台太频繁,更推荐使用 Axios。

创建一个名为 data.json 的文件,放在项目的根目录下。

{ 
    "name": "狂神说Java", 
    "url": "https://blog.kuangstudy.com", 
    "page": 1, 
    "address": { 
        "street": "洪崖洞", 
        "city": "重庆市", 
        "country": "中国" 
    } 
}

编写页面代码

<!DOCTYPE html> 
<html> 
    <head>
        <meta charset="UTF-8"> 
        <title>测试</title> 
    </head> 
    <body> 
        <div id="vue"> 
            <div>名称:{ {info.name} }</div> 
            <div>地址:{ {info.address.country} }-{ {info.address.city} }- { {info.address.street} }</div> 
            <div>
                链接:<a v-bind:href="info.url" target="_blank">{ {info.url} }</a> 
            </div> 
        </div> 
        <!--引入 JS 文件--> 
        <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> 
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script> 
        <script type="text/javascript"> 
            var vm = new Vue({ 
                el: '#vue', 
                data() { 
                    return { 
                        info: { 
                            name: null, 
                            address: { 
                                country: null, 
                                city: null, 
                                street: null 
                            },
                            url: null 
                        }
                    } 
                },
                //钩子函数 
                mounted() { 
                    axios.get('data.json').then(response => (this.info = response.data)); 
                } 
            }); 
        </script> 
    </body> 
</html>

在 data 中的数据结构必须要和 Ajax 响应回来的数据格式匹配。

目录结构

  • buildconfig:WebPack 配置文件
  • node_modules:用于存放 npm install 安装的依赖文件
  • src: 项目源码目录
  • static:静态资源文件
  • .babelrc:Babel 配置文件,主要作用是将 ES6 转换为 ES5
  • .editorconfifig:编辑器配置
  • eslintignore:需要忽略的语法检查配置文件
  • .gitignore:git 忽略的配置文件
  • .postcssrc.js:css 相关配置文件,其中内部的 module.exports 是 NodeJS 模块化语法
  • index.html:首页,仅作为模板页,实际开发时不使用
  • package.json:项目的配置文件
    • name:项目名称
    • version:项目版本
    • description:项目描述
    • author:项目作者
    • scripts:封装常用命令
    • dependencies:生产环境依赖
    • devDependencies:开发环境依赖