在 MVVM 之前,开发人员从后端获取需要的数据模型,然后要通过 DOM 操作 Model 渲染到 View 中。而后当用户操作视图,我们还需要通过 DOM 获取 View 中的数据,然后同步到Model 中。
而 MVVM 中的 VM 要做的事情就是把 DOM 操作完全封装起来,开发人员不用再关心 Model和 View 之间是如何互相影响的:
把开发人员从繁琐的 DOM 操作中解放出来,把关注点放在如何操作 Model 上。
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不
同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上
手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库
结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
官网:https://cn.vuejs.org/
参考:https://cn.vuejs.org/v2/guide/
Git 地址:https://github.com/vuejs
尤雨溪,Vue.js 创作者,Vue Technology 创始人,致力于 Vue 的研究开发。
官网文档提供了 3 中安装方式:
这边采用第三种方式
1、新建文件夹 hello-vue,并使用 vscode 打开
2、使用 vscode 控制台,npm install -y;项目会生成 package-lock.json 文件,类似于 maven 项目的 pom.xml 文件。
3、使用 npm install vue,给项目安装 vue;项目下会多 node_modules 目录,并且在下面有一个 vue 目录。
在 hello.html 中,我们编写一段简单的代码。h2 中要输出一句话:xx 非常帅
。前面的xx
是要渲染的数据。
页面代码
<body>
<div id="app">
<h1>{{name}},非常帅!!!h1>
div>
<script src="./node_modules/vue/dist/vue.min.js">script>
<script>
let vm = new Vue({
el:"#app",
data:{
name: "张三"
}
});
script>
body>
h2
元素中,我们通过{{name}}的方式,来渲染刚刚定义的 name 属性。打开页面查看效果:
更神奇的在于,当你修改 name 属性时,页面会跟着变化:
我们对刚才的案例进行简单修改:
<body>
<div id="app">
<input type="text" v-model="num">
<h2>
{{name}},非常帅!!!有{{num}}个人为他点赞。
h2>
div>
<script src="./node_modules/vue/dist/vue.js">script>
<script>
// 创建 vue 实例
let app = new Vue({
el: "#app", // el 即 element,该 vue 实例要渲染的页面元素
data: { // 渲染页面需要的数据
name: "张三",
num: 5
}
});
script>
body>
双向绑定:
效果:我们修改表单项,num 会发生变化。我们修改 num,表单项也会发生变化。为了实时观察到这个变化,我们将 num 输出到页面。我们不需要关注他们为什么会建立起来关联,以及页面如何变化,我们只需要做好数据和视图的关联即可( MVVM )
给页面添加一个按钮:
<body>
<div id="app">
<input type="text" v-model="num">
<button v-on:click="num++">点赞button>
<h2>
{{name}},非常帅!!!有{{num}}个人为他点赞。
h2>
div>
<script src="./node_modules/vue/dist/vue.js">script>
<script>
// 创建 vue 实例
let app = new Vue({
el: "#app", // el 即 element,该 vue 实例要渲染的页面元素
data: { // 渲染页面需要的数据
name: "张三",
num: 5
}
});
script>
body>
v-on
指令绑定点击事件,而不是普通的onclick
,然后直接操作 num简单使用总结:
每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的:
let app = new Vue({
});
在构造函数中传入一个对象,并且在对象中声明各种 Vue 需要的数据和方法,包括:
等等
接下来我们一 一介绍。
每个 Vue 实例都需要关联一段 Html 模板,Vue 会基于此模板进行视图渲染。
我们可以通过 el 属性来指定。
例如一段 html 模板:
<div id="app">
div>
然后创建 Vue 实例,关联这个 div
let vm = new Vue({
el: "#app"
})
这样,Vue 就可以基于 id 为app
的 div 元素作为模板进行渲染了。在这个 div 范围以外的部
分是无法使用 vue 特性的。
当 Vue 实例被创建时,它会尝试获取在 data 中定义的 所有属性, 用于视图的渲染,并且监视data 中的属性变化,当 data 发生改变,所有相关的视图都将重新渲染,这就是“ 响应式“系统。
html:
<div id="app">
<input type="text" v-model="name" />
div>
JS:
let vm = new Vue({
el: "#app",
data: {
name: "刘德华"
}
})
input
的值Vue 实例中除了可以定义 data 属性,也可以定义方法,并且在 Vue 实例的作用范围内使用。
Html:
<div id="app">
{{num}}
<button v-on:click="add">加button>
div>
JS:
let vm = new Vue({
el: "#app",
data: {
num: 0
},
methods: {
add: function () {
// this 代表的当前 vue 实例
this.num++;
}
}
})
什么是指令?
v-
前缀的特殊特性。例如我们在入门案例中的 v-on,代表绑定事件。
1 )、 花括号
格式:{{表达式}}
说明:
2 )、插值闪烁
使用{{}}方式在网速较慢时会出现问题。在数据未加载完成时,页面会显示出原始的{{}}
,加载完毕后才显示正确数据,我们称为插值闪烁。我们将网速调慢一些,然后刷新页面,试试看刚才的案例:
3 )、v-text 和 v-html
可以使用 v-text 和 v-html 指令来替代{{}}
说明:
示例:
<div id="app">
v-text:<span v-text="hello">span> <br />
v-html:<span v-html="hello">span>
div>
<script src="./node_modules/vue/dist/vue.js">script>
<script>
let vm = new Vue({
el: "#app",
data: {
hello: "大家好
"
}
})
script>
效果:
并且不会出现插值闪烁,当没有数据时,会显示空白或者默认数据。
html 属性不能使用双大括号形式绑定,我们使用 v-bind 指令给 HTML 标签属性绑定值;而且在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。
1)绑定 class
<div class="static" v-bind:class="{ active: isActive, 'text-danger'
: hasError }">
div>
<script>
let vm = new Vue({
el: "#app",
data: {
isActive: true,
hasError: false
}
})
script>
2 )、绑定 style
v-bind:style
的对象语法十分直观,看着非常像 CSS,但其实是一个 JavaScript 对象。style属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,这种方式记得用单引号括起来) 来命名。
例如:font-size–>fontSize
<div id="app" v-bind:style="{ color: activeColor, fontSize: fontSiz
e + 'px' }">div>
<script>
let vm = new Vue({
el: "#app",
data: {
activeColor: 'red',
fontSize: 30
}
})
script>
结果:
3 )、绑定其他任意属性
<div id="app" v-bind:style="{ color: activeColor, fontSize: fontS
ize + 'px' }"
v-bind:user="userName">
div>
<script>
let vm = new Vue({
el: "#app",
data: {
activeColor: 'red',
fontSize: 30,
userName: 'zhangsan'
}
})
script>
效果:
<div id="app" user="zhangsan" style="color: red; font-size: 30px;">div>
效果:
4)、v-bind 缩写
<div id="app" :style="{ color: activeColor, fontSize: fontSize +
'px' }"
:user="userName">
div>
刚才的 v-text、v-html、v-bind 可以看做是单向绑定,数据影响了视图渲染,但是反过来就不行。接下来学习的 v-model 是双向绑定,视图(View)和模型(Model)之间会互相影响。既然是双向绑定,一定是在视图中可以修改数据,这样就限定了视图的元素类型。目前v-model 的可使用元素有:
基本上除了最后一项,其它都是表单的输入项。
示例:
<div id="app">
<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 />
<h1>
你选择了:{{language.join(',')}}
h1>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
language: []
}
})
script>
CheckBox
对应一个 model 时,model 的类型是一个数组,单个 checkbox 值默认是boolean 类型text
和textarea
默认对应的 model 是字符串select
单选对应字符串,多选对应也是数组效果:
1、基本用法
v-on 指令用于给页面元素绑定事件。语法: v-on:事件名=“js 片段或函数名”
示例:
<div id="app">
<button v-on:click="num++">点赞button>
<button v-on:click="decrement">取消button>
<h1>有{{num}}个赞h1>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
num: 100
},
methods: {
decrement() {
this.num--; //要使用 data 中的属性,必须 this.属性名
}
}
})
script>
另外,事件绑定可以简写,例如v-on:click='add'
可以简写为@click='add'
2 、事件修饰符
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue.js 为 v-on
提供了 事件修饰符。修饰符是由点开头的指令后缀来表示的。
.stop
:阻止事件冒泡到父元素.prevent
:阻止默认事件发生.capture
:使用事件捕获模式.self
:只有元素自身触发事件才执行。(冒泡或捕获的都不执行).once
:只执行一次<div id="app">
<button v-on:contextmenu.prevent="num++">点赞button>
<br />
<button v-on:contextmenu="decrement($event)">取消button>
<br />
<h1>有{{num}}个赞h1>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
num: 100
},
methods: {
decrement(ev) {
// ev.preventDefault();
this.num--;
}
}
})
script>
效果:右键“点赞”,不会触发默认的浏览器右击事件;右键“取消”,会触发默认的浏览器右击事件)
3 、按键修饰符
在监听键盘事件时,我们经常需要检查常见的键值。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
<input v-on:keyup.13="submit">
记住所有的 keyCode
比较困难,所以 Vue 为最常用的按键提供了别名:
<input v-on:keyup.enter="submit">
<input @keyup.enter="submit">
全部的按键别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
4 、组合按钮
可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。
.ctrl
.alt
.shift
<input @keyup.alt.67="clear">
<div @click.ctrl="doSomething">Do somethingdiv>
遍历数据渲染页面是非常常用的需求,Vue 中通过 v-for 指令来实现。
1、遍历数组
语法:v-for=“item in items”
示例:
<div id="app">
<ul>
<li v-for="user in users">
{{user.name}} - {{user.gender}} - {{user.age}}
li>
ul>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
users: [
{ name: '柳岩', gender: '女', age: 21 },
{ name: '张三', gender: '男', age: 18 },
{ name: '范冰冰', gender: '女', age: 24 },
{ name: '刘亦菲', gender: '女', age: 18 },
{ name: '古力娜扎', gender: '女', age: 25 }
]
},
})
script>
效果:
2 、数组角标
在遍历的过程中,如果我们需要知道数组角标,可以指定第二个参数:语法:v-for="(item,index) in items"
示例:
<div id="app">
<ul>
<li v-for="(user, index) in users">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
li>
ul>
div>
效果:
3、 、 遍历对象
v-for 除了可以迭代数组,也可以迭代对象。语法基本类似
语法:
v-for=“value in object”
v-for="(value,key) in object"
v-for="(value,key,index) in object"
示例:
<div id="app">
<ul>
<li v-for="(value, key, index) in user">
{{index + 1}}. {{key}} - {{value}}
li>
ul>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let vm = new Vue({
el: "#app",
data: {
user: { name: '张三', gender: '男', age: 18 }
}
})
script>
效果:
4 、Key
用来标识每一个元素的唯一特征,这样 Vue 可以使用“就地复用”策略 有效的提高渲染的
效率。
示例:
<ul>
<li v-for="(item,index) in items" :key=”index”>li>
ul>
<ul>
<li v-for="item in items" :key=”item.id”>li>
ul>
最佳实践:
如果 items 是数组,可以使用 index 作为每个元素的唯一标识
如果 items 是对象数组,可以使用 item.id 作为每个元素的唯一标识
1 、基本用法
v-if,顾名思义,条件判断。当得到结果为 true 时,所在的元素才会 被渲染。
v-show,当得到结果为 true 时,所在的元素才会被显示。
语法:v-if=" 布尔表达式", v-show=" 布尔表达式",
示例:
<div id="app">
<button v-on:click="show = !show">点我呀button>
<br>
<h1 v-if="show">
看到我啦?!
h1>
<h1 v-show="show">
看到我啦?!show
h1>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
show: true
}
})
script>
2 、与 v-for 结合
当 v-if 和 v-for 出现在一起时,v-for 优先级更高。也就是说,会先遍历,再判断条件。
修改 v-for 中的案例,添加 v-if:
<ul>
<li v-for="(user, index) in users" v-if="user.gender == '女'">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
li>
ul>
效果:只显示女性
v-else 元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别。
示例:
<div id="app">
<button v-on:click="random=Math.random()">点我呀
button><span>{{random}}span>
<h1 v-if="random >= 0.75">
看到我啦?!v-if >= 0.75
h1>
<h1 v-else-if="random > 0.5">
看到我啦?!v-else-if > 0.5
h1>
<h1 v-else-if="random > 0.25">
看到我啦?!v-else-if > 0.25
h1>
<h1 v-else>
看到我啦?!v-else
h1>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
random: 1
}
})
script>
1、计算属性(computed)
某些结果是基于之前数据实时计算出来的,我们可以利用计算属性。来完成,示例:
<div id="app">
<ul>
<li>西游记:价格{{xyjPrice}},数量:
<input type="number" v-model="xyjNum">li>
<li>水浒传:价格{{shzPrice}},数量:
<input type="number" v-model="shzNum">li>
<li>总价:{{totalPrice}}li>
ul>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
xyjPrice: 56.73,
shzPrice: 47.98,
xyjNum: 1,
shzNum: 1
},
computed: {
totalPrice(){
return this.xyjPrice*this.xyjNum + this.shzPrice*this.shzNum;
}
},
})
script>
效果:只要依赖的属性发生变化,就会重新计算这个属性
2、侦听(watch)
watch 可以让我们监控一个值的变化。从而做出相应的反应,示例:
<div id="app">
<ul>
<li>西游记:价格{{xyjPrice}},数量:
<input type="number" v-model="xyjNum">li>
<li>水浒传:价格{{shzPrice}},数量:
<input type="number" v-model="shzNum">li>
<li>总价:{{totalPrice}}li>
{{msg}}
ul>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
let app = new Vue({
el: "#app",
data: {
xyjPrice: 56.73,
shzPrice: 47.98,
xyjNum: 1,
shzNum: 1,
msg:""
},
computed: {
totalPrice(){
return this.xyjPrice*this.xyjNum + this.shzPrice*th
is.shzNum;
}
},
watch: {
xyjNum(newVal, oldVal){
if(newVal >= 3){
this.msg = "西游记没有更多库存了";
this.xyjNum = 3;
}else{
this.msg = "";
}
}
}
})
script>
效果:
3、过滤器(filters)
过滤器不改变真正的data
,而只是改变渲染的结果,并返回过滤后的版本。在很多不同的
情况下,过滤器都是有用的,比如尽可能保持 API 响应的干净,并在前端处理数据的格式。
示例:展示用户列表性别显示男女
<body>
<div id="app">
<table>
<tr v-for="user in userList">
<td>{{user.id}}td>
<td>{{user.name}}td>
<td>{{user.gender===1? "男":"女"}}td>
tr>
table>
div>
body>
<script src="../node_modules/vue/dist/vue.js">script>
<script>
let app = new Vue({
el: "#app",
data: {
userList: [
{ id: 1, name: 'jacky', gender: 1 },
{ id: 2, name: 'peter', gender: 0 }
]
}
});
script>
1、局部过滤器
注册在当前 vue 实例中,只有当前实例能用
let app = new Vue({
el: "#app",
data: {
userList: [
{ id: 1, name: 'jacky', gender: 1 },
{ id: 2, name: 'peter', gender: 0 }
]
},
// filters 定义局部过滤器,只可以在当前 vue 实例中使用
filters: {
genderFilter(gender) {
return gender === 1 ? '男~' : '女~'
}
}
});
<td>{{user.gender | genderFilter}}td>
2 、全局过滤器
// 在创建 Vue 实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
return value.charAt(0).toUpperCase() + value.slice(1)
})
任何 vue 实例都可以使用: {{user.name | capitalize}}
过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:和 双花括号插值和 v-bind表达式
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。在 vue 里,所有的 vue 实例都是组件
我们通过 Vue 的 component 方法来定义一个全局组件。
<div id="app">
<counter>counter>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script type="text/javascript">
// 定义全局组件,两个参数:1,组件名称。2,组件参数
Vue.component("counter", {
template: '',
data() {
return {
count: 0
}
}
})
let app = new Vue({
el: "#app"
})
script>
定义好的组件,可以任意复用多次:
<div id="app">
<counter>counter>
<counter>counter>
<counter>counter>
div>
组件的 data属性必须是函数!
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝;
官网解释:https://cn.vuejs.org/v2/guide/components.html#data-%E5%BF%85%E9%A1%BB%E6%98%AF%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0
一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着 Vue 的加载而加载。因此,对于一些并不频繁使用的组件,我们会采用局部注册。我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:
const counter = {
template: '',
data() {
return {
count: 0
}
}
};
然后在 Vue 中使用它:
let app = new Vue({
el: "#app",
components: {
counter: counter // 将定义的对象注册为组件
}
})
简写:
let app = new Vue({
el: "#app",
components: {
counter // 将定义的对象注册为组件
}
})
每个 Vue 实例在被创建时都要经过一系列的初始化过程 :创建实例,装载模板,渲染模板等等。Vue 为生命周期中的每个状态都设置了钩子函数(监听函数)。每当 Vue 实例处于不同的生命周期时,对应的函数就会被触发调用。生命周期:你不需要立马弄明白所有的东西。
示例
<body>
<div id="app">
<span id="num">{{num}}span>
<button v-on:click="num++">赞!button>
<h2>
{{name}},非常帅!!!有{{num}}个人点赞。
h2>
div>
body>
<script src="../node_modules/vue/dist/vue.js">script>
<script>
let app = new Vue({
el: "#app",
data: {
name: "张三",
num: 100
},
methods: {
show() {
return this.name;
},
add() {
this.num++;
}
},
beforeCreate() {
console.log("=========beforeCreate=============");
console.log("数据模型未加载:" + this.name, this.num);
console.log("方法未加载:" + this.show());
console.log("html 模板未加载:
" + document.getElementById("num"));
},
created: function () {
console.log("=========created=============");
console.log("数据模型已加载:" + this.name, this.num);
console.log("方法已加载:" + this.show());
console.log("html 模板已加载:
" + document.getElementById("num"));
console.log("html 模板未渲染:
" + document.getElementById("num").innerText);
},
beforeMount() {
console.log("=========beforeMount=============");
console.log("html 模板未渲染:
" + document.getElementById("num").innerText);
},
mounted() {
console.log("=========mounted=============");
console.log("html 模板已渲染:
" + document.getElementById("num").innerText);
},
beforeUpdate() {
console.log("=========beforeUpdate=============");
console.log("数据模型已更新:" + this.num);
console.log("html 模板未更新:
" + document.getElementById("num").innerText);
},
updated() {
console.log("=========updated=============");
console.log("数据模型已更新:" + this.num);
console.log("html 模板已更新:
" + document.getElementById("num").innerText);
}
});
script>
全局安装 webpack
全局安装 vue 脚手架
vue init webpack appname:vue 脚手架使用 webpack 模板初始化一个 appname 项目
项目的 package.json 中有 scripts,代表我们能运行的命令
npm start = npm run dev:启动项目
npm run build:将项目打包
运行流程
Vue 单文件组件模板有三个部分;
<template>
<div class="hello">
<h1>{{ msg }}h1>
div>
template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
script>
<style scoped>
h1, h2 {
font-weight: normal;
}
style>
Template:编写模板
Script:vue 实例配置
Style:样式
文件–>首选项–>用户代码片段–>点击新建代码片段–取名 vue.json 确定
{
"生成 vue 模板": {
"prefix": "vue",
"body": [
"",
"",
"",
"",
"",
""
],
"description": "生成 vue 模板"
}
}
1、安装 element-ui: npm i element-ui
2、在 main.js 中引入 element-ui 就可以全局使用了。
import ElementUI from ‘element-ui’
import ‘element-ui/lib/theme-chalk/index.css’
Vue.use(ElementUI)
3、将 App.vue 改为 element-ui 中的后台布局
4、添加测试路由、组件,测试跳转逻辑
(1) 、参照文档 el-menu 添加 router 属性
(2) 、参照文档 el-menu-item 指定 index 需要跳转的地址