Vue是什么
Vue是一套用于构建用户界面的渐进式JavaScript框架。作者尤雨溪。
官网:
Vue.js - The Progressive JavaScript Framework | Vue.js
Vue.js - 渐进式 JavaScript 框架 | Vue.js
IDE:Visual Studio Code或WebStorm
Vue的特点
渐进式:Vue可以自底向上逐层的应用:简单应用只需一个轻量小巧的核心库;复杂应用可以引入各式各样的Vue插件。
组件化:页面某个模块对应的html、css、js可以封装成一个vue文件,提高了代码复用率,且易于维护。
声明式编码:无需操作DOM,提高开发效率。
DOM复用:使用虚拟DOM + Diff算法,尽量复用DOM。
MVVM
MVVM(Model-View-ViewModel)是脱胎于MVC的架构模式,其核心ViewModel提供对视图View和数据Model的双向数据绑定,保证它们的数据一致性:
使用DOM Listeners将View层DOM元素的变化更新到Model层;
使用Directives(指令)将Model层的变化更新到View层DOM元素。
前后端技术栈对比
语言 | 框架 | 工具 | 项目构建 | 依赖管理 | |
前端 | JavaScript:es6,7,8... | JQuery、Vue、React | webstorm,vscode | webpack,gulp | npm |
后端 | Java:jdk8,9,10,11... | Spring、SpringMVC | idea,eclipse | maven,gradle | maven |
安装
官网文档提供了3种安装方式:
- 直接 script 引入本地 vue 文件。需要通过官网下载 vue 文件
https://cn.vuejs.org/v2/guide/installation.html下载:vue.js(开发版)或vue.min.js(生产版)
- 通过 script 引入 CDN 代理。需要联网,生产环境可以使用这种方式
对于制作原型或学习,可以这样使用最新版本:<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
对于生产环境,推荐链接到一个明确的版本号和构建文件:<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
- 通过 npm 安装。这种方式也是官网推荐的方式,需要 nodejs 环境。
- 新建文件夹 hello-vue,并使用 vscode 打开
- 打开vscode终端,使用npm init -y初始化npm,项目下会生成:
package.json文件:用来记录项目信息和项目依赖。
-
- 使用 npm install vue@2安装vue2,项目下会生成:
package-lock.json文件:指定依赖的具体版本,保证开发副本环境一致
node_modules目录:用来存放用包管理工具下载安装的包,该目录下有个子目录vue。
本示例vue2使用npm安装。
Hello World
Vue对象中,用el绑定元素,用data封装数据,用methods封装方法。 视图中,使用模板语法引用模型中的数据或方法。 注意:视图v-on指令中的this指向Window对象,模型methods中的this指向Vue对象。 Chrome安装Vue的开发者工具 Chrome 应用商店直接翻墙安装Vue.js devtools,然后重新vscode代码编辑页面右键-》Open with Live Server,开发者工具上会多出一个“Vue”标签。 注意如果要使用Vue.js devtools,引入的vue脚本应为开发版。 关闭productionTip: | <body> <h1>hello {{getName()}}</h1> |
-
- Directives
内容渲染指令:{{}} / v-text / v-html /v-once
{{}}插值表达式:在元素中的某一位置采用纯文本的方式渲染数据
v-text:将数据采用纯文本方式填充其空元素中
v-html:将数据采用 HTML 语法填充其空元素中
v-once:执行一次性插值,当数据改变时,插值处的内容不会继续更新
插值表达式有插值闪烁问题,解决方法:
首先,在差值语法所在的标签处加上v-cloak指令
然后,在css中设置v-cloak的属性为display为none:
<style type="text/css">[v-cloak]{display: none;}</style>
视图: | 模型: |
v-text:<span v-text="hello"></span> <br /> v-html:<span v-html="hello"></span> | data: { hello: "<h1>大家好</h1>" }, |
属性绑定指令:v-bind:
语法:如<img v-bind:src="...">简写为<img :src="...">
如果绑定的值是null或undefined,那么该属性将从渲染的元素上移除。
如果绑定class属性或style属性,属性对象的key可用驼峰式(camelCase)或烤串式(kebab-case)表示,短横分隔时需加引号。
绑定Class
对象语法:视图表示为对象,模型负责定义是否需要某class
视图: | 模型: | 渲染为: |
<div :class="{ active: isActive, 'text-danger': hasError }"></div> | data: { isActive: true, hasError: false } | <div class="active"></div> |
数组语法:视图表示为数组,模型负责定义class名
视图: | 模型: | 渲染为: |
<div :class="[activeClass, errorClass]"></div> | data: { activeClass: 'active', errorClass: 'text-danger' } | <div class="active text-danger"></div> |
混合写法:视图表示为数组中嵌套对象,模型负责定义class名或是否需要某class
视图: | 模型: | 渲染为: |
<div :class="[{ active: isActive }, errorClass]"></div> | data: { errorClass: 'text-danger', isActive: true } | <div class="active text-danger"></div> |
绑定Style
对象语法:视图表示为对象,模型负责定义style属性值
视图: | 模型: | 渲染为: |
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> | data: { activeColor: "red", fontSize: 30 } | <div style="color: red; font-size: 30px"></div> |
数组语法:视图表示为数组,模型负责定义style对象
视图: | 模型: | 渲染为: |
<div :style="[colorStyle, fontSizeStyle]"></div> | data: { colorStyle: { color: "red" }, fontSizeStyle: { fontSize: "30px" } } | <div style="color: red; font-size: 30px"></div> |
双向绑定指令:v-model
v-model指令用在表单元素(<input>、<select>、<textarea>)和Vue自定义组件(components)中:
文本类型的<input>和<textarea>元素会绑定value属性并侦听input事件
<input type="checkbox">、<input type="radio">和<select>会绑定选中项的value属性并侦听change事件
v-model的修饰符:
.number 自动将用户的输入值转为数值类型
.trim 自动过滤用户输入的首尾空白字符
.lazy 在 chang 时而非 input 时更新
视图: | 模型: |
<input type="checkbox" v-model="language" value="Java" />Java<br /> <input type="checkbox" v-model="language" value="PHP" />PHP<br /> <input type="checkbox" v-model="language" value="Swift" />Swift<br /> <p>你选择了:{{language.join(',')}}</p> | data: { language: [] } |
事件绑定指令: v-on:
v-on:指令用来监听DOM事件,并在事件触发时执行对应的JavaScript。
语法:v-on:<事件名>="<js片段或函数名>"
简写:@<事件名>="<js片段或函数名>"
事件修饰符:
在事件处理程序中调用`event.preventDefault()`或`event.stopPropagation()`是非常常见的需求。尽管我们可以在方法中实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理DOM事件细节。
.prevent 阻止默认行为
.stop 阻止事件冒泡
.capture 使用事件捕获模式(以捕获模式触发当前的事件处理函数)
.once 只执行一次
.self 只有在event.target是当前元素自身时触发事件处理函数(冒泡或捕获的都不执行)
.passive 向浏览器表明了不想阻止事件的默认行为
视图: | 模型: |
<div style="border: 1px solid red; padding: 20px;" @click="sayHellow('外层DIV')"> | methods: { |
按键修饰符:
按键别名:.enter、.tab、.esc、.space、.up、.down、.left、.right、.delete (捕获 Delete 和 Backspace 两个按键)
系统修饰符:.ctrl、.alt、.shift、.meta
准确的修饰符:.exact
视图: | 模型: |
<input type="text" v-model="num" @keyup.up="num+=1" | data: { |
鼠标按键修饰符:
.left、.right、.middle
条件渲染指令(分支渲染指令):v-if / v-else-if / v-else /v-show
v-if:当条件判断为true时,所在的元素才会被渲染。(条件首次为true时所在元素才渲染,条件切换时涉及的元素都会销毁或重建)
v-show:当条件判断为true时,所在的元素才会被显示。(条件无论如何所在元素都会渲染,条件为true时所在元素展示(CSS display))
如果需要频繁切换,使用v-show(无切换开销)
如果在运行时绑定条件很少改变,使用v-if(更低的初始渲染开销)
v-if支持在<template>元素上使用,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个<template>元素。
v-show不支持在<template>元素上使用。
视图: | 模型: |
<button v-on:click="random=Math.random()">点我呀</button> | data: { |
列表渲染指令(循环渲染指令)v-for
使用 v-for 指令基于一个数组来渲染一个列表
v-for渲染数组
语法:(item[, index]) in items
item :元素
index :索引
items :需要遍历的数组
v-for渲染对象
遍历顺序取决于对该对象调用 Object.keys() 的返回值顺序。
语法:(value[, name[, index]]) in object
value :属性值
name :键
index :索引
items :需要循环的对象
通过 key 管理状态:
当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能;
但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能;
此时,需要为每项提供一个唯一的key属性。
key 的注意事项:
key 的类型只能是 Number/String
key 值必须具有唯一性
建议循环的列表有一个属性当 key(该属性的值在此列表中唯一)
不使用索引当 key
建议使用 v-for 指令时一定要指定 key 的值
最佳实践:
如果 items 是数组,可以使用 index 作为:key
如果 items 是对象数组,可以使用 item.id 作为:key
结合v-if有条件遍历:
v-if的优先级比v-for低,所以可以每次迭代时判断是否展示。
视图: | 模型: |
<ul> | data: { |
-
- computed、侦听watch、过滤器filters
计算属性computed
某些属性的值是依赖其他属性值实时计算出来的,我们可以利用计算属性来计算,只要依赖的属性发生变化,就会重新计算这个属性。
示例(暂不考虑精度和负数问题):
侦听watch
watch 可以让我们监控属性值的变化。从而做出相应的反应。
过滤器filters
过滤器不改变真正的`data`,而只是改变渲染的结果,并返回过滤后的版本。在很多不同的情况下,过滤器都是有用的,比如尽可能保持 API 响应的干净,并在前端处理数据的格式。
局部过滤器:注册在当前Vue实例中,只有当前实例能用;
全局过滤器:在创建Vue实例之前定义全局过滤器,所有实例可用。
当全局过滤器和局部过滤器重名时,会采用局部过滤器。
视图中使用管道符号后接过滤器名来过滤属性值:<属性> | <过滤器名>
视图: | 模型: |
<div id="app"> | <script src="./node_modules/vue/dist/vue.js"></script> |
不同的页面可能会有相同的部分,例如相同的头部导航。我们可以将相同的部分做成组件进行复用。 组件与Vue实例: 在 vue 里,所有的 vue 实例都是组件,组件其实也是一个 Vue 实例,因此它在定义时也会接收:data、methods、生命周期函数等,不同的是:
关于组件名: 组件名为多个单词组成时,可使用烤串式命名(kebab-case),也可使用驼峰式命名(CamelCase),驼峰式命名需要脚手架支持 组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。 可以使用name配置项指定组件在开发者工具中呈现的名字(默认展示为大驼峰式)。 关于组件标签: 组件标签可使用自闭包形式,但不用使用Vue脚手架时,会导致后续组件不能渲染。 | <body> |
生命周期是指实例对象从构造函数开始执行(被创建)到被GC垃圾回收销毁的整个存在时期,在生命周期中被自动调用的函数叫作生命周期函数,又叫钩子函数。不同的时期会有不同的钩子函数,可以利用不同时期的钩子函数去完成不同的操作。
生命周期总体流程:创建-》挂载[-》更新]-》销毁
所有生命周期钩子函数的 this 上下文都会自动指向当前调用它的组件实例。注意:避免用箭头函数来定义生命周期钩子,因为如果这样的话你将无法在函数中通过 this 获取组件实例。
生命周期与钩子函数 | 模型与视图 | 钩子函数使用场景 |
new Vue() | ||
初始化默认事件&默认生命周期函数 | ||
beforeCreate() | 不可访问data、methods 真实DOM中变量未赋值 | 可增加一些loading事件 |
初始化数据(注入&校验) | data、methods加载 | |
created() | 可访问data、methods、computed、watch 真实DOM中变量未赋值 无法访问$el | 可结束loading事件,完成一些初始化,实现函数自执行等。 未挂载DOM,若在此阶段进行DOM操作一定要放在Vue.nextTick()的回调函数中。 |
如果未指定el选项,等待调用vm.$mount(el) | ||
如果指定了template选项,将template编译到render函数中,如果未指定template选项,将el父级DOM作为template编译 | 编译template填充data,生成虚拟DOM | |
beforeMount() | 真实DOM中变量未赋值 | |
创建vm.$el并用其替换el所指向的视图 | 虚拟DOM替换真实DOM | |
mounted() | 真实DOM中变量已赋值 可以访问$el、$ref | 开启定时器、发送网络请求、订阅消息、绑定自定义事件 |
挂载完毕 | ||
当data被修改: | ||
beforeUpdate() | data已更新 真实DOM未更新 | |
虚拟DOM重新渲染并应用更新 | data更新到真实DOM | |
updated() | 真实DOM已更新,与data保持一致 | |
当调用vm.$destroy()函数: | ||
beforeDestroy() | 可以访问data、methods、过滤器、指令 | 关闭定时器、取消订阅消息、解绑自定义事件 |
解除绑定、销毁子组件以及自定义事件监听器 | ||
销毁完毕 | ||
destroyed() | 无法访问data、methods、过滤器、指令 |
-
- vue-cli模块化开发
使用Vue脚手架初始化项目
vue-cli俗称Vue脚手架,cli是Command-Line Interface的缩写。
Vue脚手架用于快速生成一个vue的项目模板,作用类似于maven。
全局安装 webpack(以前执行过就不用执行了):
npm install webpack -g
全局安装 vue 脚手架(以前执行过就不用执行了):
npm install -g @vue/cli-init
如果安装时点了鼠标导致安装暂停,按下键盘即可恢复安装。
用 webpack 模板初始化 vue 项目:
vue init webpack <项目名称>
启动 vue 项目:
npm run dev
项目的 package.json 中有 scripts,代表我们能运行的命令。
项目结构
├─build 项目构建(webpack)相关代码
├─config 配置目录
├─node_modules 依赖目录
├─src 源代码
│ ├─assets 存放静态资源
│ ├─components 存放组件
│ ├─router 路由配置
│ │ App.vue 项目入口文件,汇总所有组件
│ └ main.js 项目核心文件
├─static 存放静态资源
├─test 测试目录
│ .xxx文件 一些配置文件,如语法配置、git忽略配置等
│ index.html 首页入口文件
│ package-lock.json 包版本控制文件
│ package.json 应用包配置文件
└ README.md 项目说明文档
运行流程
n 进入页面首先加载 index.html 和 main.js 文件。
n main.js 导入了一些模块【vue、app、router】,并且创建 vue 实例,关联 index.html页面的<div id=”app”>元素。使用了 router,导入了 App 组件。并且使用<App/>标签引用了这个组件
n 第一次默认显示 App 组件。App 组件有个图片和<router-view>,所以显示了图片。
但是由于<router-view>代表路由的视图,默认是访问/#/路径(router 路径默认使用HASH 模式)。在 router 中配置的/是显示 HelloWorld 组件。
n 所以第一次访问,显示图片和 HelloWorld 组件。
n 我们尝试自己写一个组件,并且加入路由。点击跳转。需要使用<router-linkto="/foo">Go to Foo</router-link>标签
Vue 单文件组件
Vue 单文件组件模板有三个部分:
<template>:编写模板
<script>:Vue实例配置
<style>:样式
-
- element-ui快速开发
安装element-ui
npm i element-ui
在 main.js 中引入 element-ui
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
将 App.vue 改为 element-ui 中的后台布局
添加测试路由、组件,测试跳转逻辑
(1) 、参照文档 el-menu 添加 router 属性
(2) 、参照文档 el-menu-item 指定 index 需要跳转的地址