vue学习(一)
一.vue简介
1.1MVVM
项目结构经历的三个阶段:
后端 MVC :可以理解为单体结构,流程控制是由后端控制器来完成
前端 MVC :前后端分离开发,后端只负责接收响应请求
MVVM是MVC的增强版,实质上和MVC没有本质区别,只是代码的位置变动而已
MVVM 前端请求后端接口,后端返回数据,前端接收数据,并将接收到的数据设置为 “VM”,HTML 从 vm 取值
- M model 数据模型,指的是后端接口返回的数据
- V view 视图
- VM ViewModel 视图模型 数据模型与视图之间的桥梁,后端返回的 model 转换前端所需的 vm,视图层可以直接从 vm 中提取数据
二.vue入门
2.1 vue 的引入
- 离线引用:下载 vue 的 js 文件,添加到前端项目,在网页中通过 script 标签引用 vue.js 文件
- CDN 引用:直接使用在线 CDN 的方式引入
2.2案例
文本:数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:{{message}}
- 创建一个 HTML 文件
- 引入 vue.js 文件
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
三. vue 的语法
3.1基本类型数据和字符串
<div id="app-2">
{{code}}
从 0 开始: {{message}}
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-2',
data: {
code: 1_3_3,
message: 'Hello World!'
}
})
</script>
3.2对象类型数据
支持 ognl 语法
学号:{{stu.stuNum}}
姓名:{{stu.stuName}}
性别:{{stu.stuGender}}
年龄:{{stu.stuAge}}
3.3 条件 v-if
v-if : 用来控制切换一个元素是否显示 (底层控制是 DOM 元素,操作 DOM)
注:在浏览器中网页打开这个文件 F12,从标签上可以看到没有 stu.stuGender == ‘F’ 对应的元素。即条件不成立,网页不会渲染该 DOM,连标签都不会有。
3.4 循环 v-for
v-for 指令基于一个数组来渲染一个列表。
在 v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。
3.5 绑定标签属性 v-bind
- v-bind:属性名 缩写::属性名
3.6 表单标签的双向绑定 v-model
- 只能使用在表单输入标签
- v-model:value 可以简写为 v-model
双向绑定:{{message}}
四.vue 实例
每个使用 vue 进行数据渲染的网页文档都需要创建一个 vue 实例 — — ViewModel
钩子函数
为了便于开发者在 vue 实例生命周期的不同阶段进行特定的操作,vue 在生命周期四个阶段的前后分别提供了一个函数,这个函数无需开发者调用,当 vue 实例到达生命周期的指定阶段会自动调用对应的函数。
<div id="app-8">
<label v-once>{{message}}</label><br />
<label>{{message}}</label><br />
<input type="text" v-model="message">
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-8',
data: {
message: 'Hello World!!'
},
beforeCreate: function () {
// 1. data 初始化之前执行,不能操作 data
},
create: function () {
// 2. data 初始化之后执行,模板加载之前,可以修改 / 获取 data 中的值
console.log(this.message);
// this.message = 'Hello World!! create()';
},
beforeMount: function () {
// 3. 模板加载之后,数据初始渲染(挂载)之前,可以修改 / 获取 data 中的值
// this.message = 'Hello World!! beforeMount';
},
mounted: function () {
// 4. 数据初始渲染(挂载)之后,可以对 data 中的变量进行修改,但是不会影响 v-once 的渲染
// this.message = "Hello World!! mounted";
},
beforeUpdate: function () {
// 5. 数据渲染之后,当 data 中的数据发生变化触发重新渲染,渲染之前执行此函数
console.log("---" + this.message);
this.message = 'Hello World!! beforeUpdate';
},
update: function () {
// 6. data 数据被修改之后,重新渲染到页面之后
// this.message = "Hello World!! update";
},
beforeDestroy: function () {
// 7. 实例销毁之前
},
destroy: function () {
// 8. 实例销毁之后
}
})
</script>
五.计算属性和侦听器
5.1 计算属性
data 中的属性可以通过声明获得,也可以通过在 computed 计算属性的 getter 获得
特性:计算属性所依赖的属性值发生变化会影响计算属性的值同时发生变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app-9">
<input type="text" v-model="message1"><br />
<input type="text" v-model="message2"><br />
{{message3}}
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-9',
data: {
message1: 'Hello',
message2: 'World'
},
computed: {
message3: function () {
return this.message1 + this.message2;
}
}
})
</script>
</body>
</html>
5.2 侦听器
侦听器,就是 data 中属性的侦听器,当 data 中的属性值发生变化就会触发侦听器函数的执行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app-10">
<input type="text" v-model="message1"><br />
<input type="text" v-model="message2"><br />
{{message3}}
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-10',
data: {
message1: 'Hello',
message2: 'World',
message3: 'Hello World'
},
watch: {
message1: function () {
this.message3 = this.message1 + this.message2;
},
message2: function () {
this.message3 = this.message1 + this.message2;
}
}
})
</script>
</body>
</html>
六.class 与 style 绑定
6.1 class 绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.my-style1 {
width: 200px;
height: 100px;
background: orange;
}
.my-style2 {
border-radius: 10px;
}
.my-style3 {
width: 200px;
height: 100px;
background: black;
}
</style>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app-11">
<!-- 如果 message1 为 true, 就加载 my-style1,如果 message2 为 true, 就加载 my-style2 -->
<div :class="{'my-style1': message1, 'my-style2' : message2}">
</div><hr />
<!-- 为 class 属性加载多个样式名 -->
<div :class="[booleanValue1, booleanValue2]">
</div><hr />
<!-- 如果 message3 为 true, 则 class = 'my-style3',否则 class = 'my-style1'
如果在三目运算中使用样式名则需要加单引号,不加单引号则表示从 data 变量中获取样式名
-->
<div :class="[message3 ? 'my-style3' : 'my-style1']">
</div>
<div :class="[message1 ? booleanValue1 : booleanValue3]"></div>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-11',
data: {
message1: true,
message2: true,
message3: true,
booleanValue1: "my-style1",
booleanValue2: "my-style2",
booleanValue3: "my-style3"
}
})
</script>
</body>
</html>
6.2 style 绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.js"></script>
</head>
<body>
<div id="app-12">
<!-- 当使用 v-bind 绑定内联样式时:
1. 使用 {} 定义 style 样式,才能获取 data 的值, {} 要遵循 JSON 格式
2. {} 中不在使用 style 样式属性名 “font-size”, 而要使用对应的 js 属性名
border-style-width --- borderStyleWidth
-->
<div v-bind:style="{color: colorName, fontSize: fontsize + 'px' }">
Hello World!
</div>
<!-- 我们可以直接为 style 属性绑定一个 data 中定义好的内联样式的字符串 -->
<div v-bind:style="myStyle1">
Hello World!!
</div>
<!-- 我们可以直接为 style 属性绑定一个 data 中定义好的内联样式的对象 -->
<div v-bind:style="myStyle2">
Hello World!!!
</div>
<!-- 我们可以在同一个 style 属性通过数组引用多个内联样式的对象 -->
<div v-bind:style="[myStyle2, myStyle3]">
Hello World!!!!
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-12',
data: {
colorName: "yellow",
fontsize: "40",
myStyle1: "color: orange; font-size: 50px",
myStyle2: {
color: "blue",
fontSize: "60px"
},
myStyle3: {
textShadow: "orange 3px 3px 5px"
}
}
})
</script>
</body>
</html>
七.条件与列表渲染
7.1 条件渲染
条件判断语句:
- v-if
- v-else-if
- v-else
7.1.1 v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
7.1.2 v-else
v-else 指令来表示 v-if 的“else 块”
7.1.3 v-else-if
<div id="app-13">
分数 {{code}}
对应的等级:
<h3 v-if="code >= 90">优秀</h3>
<h3 v-else-if="code >= 80">良好</h3>
<h3 v-else-if="code >= 70">中等</h3>
<h3 v-else-if="code >= 60">及格</h3>
<h3 v-else>挂科</h3>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-13',
data: {
code: 85
}
})
</script>
7.1.4 v-show
v-show :同样用于根据条件展示元素。
从功能上 v-show 与 v-if 作用是相同的,只是渲染过程有区别。
7.2 列表渲染
编码过程中,发现网页出现报错:
Uncaught Error: Bootstrap’s JavaScript requires jQuery at bootstrap.min.js:6
解决方法:在引进JQuery文件时,将其放在 bootstrap 前面即可。
八.事件处理
- 在使用 vue 进行数据渲染时,如果使用原生 js 事件绑定 (例如 onclick),如果需要获取 vue 实例中的数据并传参则需要通过拼接来完成
- vue 提供了 v-on 指令用于绑定各种事件 (v-on:click),简化了从 vue 取值的过程,但是触发的方法需要定义在 vue 实例的 methods 中
- v-on:click 可以简写为 @click
8.1 使用 JS 函数传值
<button class="btn btn-danger" v-on:click="doDelete(s.stuNum,s.stuName)">删除</button>
<script type="text/javascript">
var vm = new Vue({
el: '#app-15',
data: {
stu: [
{
stuNum: "10010",
stuImg: "img/1.jpg",
stuName: "Tom",
stuGender: "M",
stuAge: 20
}
]
},
methods: {
doDelete: function (sNum, sName) {
alert("---delete:" + sNum + " " + sName)
}
}
})
</script>
8.2 使用 dataset 对象传值
<button class="btn btn-success" @click="doUpdate" :data-snum="s.stuNum"
:data-sname="s.stuName" :data-simg="s.stuImg">修改</button>
<script type="text/javascript">
var vm = new Vue({
el: '#app-15',
data: {
stu: [
{
stuNum: "10010",
stuImg: "img/1.jpg",
stuName: "Tom",
stuGender: "M",
stuAge: 20
}
]
},
methods: {
doUpdate: function (event) {
// 如果 v-on 绑定的 js 函数没有参数,调用的时候可以省略 (), 同时可以给 js 函数一个 event 参数(事件对象)
// 1. event 表示触发当前函数的事件
// 2. event.srcElement 表示发生事件的元素 --- 修改按钮
// 3. event.srcElement.dataset 表示按钮上绑定的数据集 (data-开头的属性)
alert("---update:");
let stu = event.srcElement.dataset;
}
}
})
</script>
8.3 混合使用
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法
<button class="btn btn-danger" v-on:click="doDelete(s.stuNum,s.stuName, $event)" :data-simg="s.stuImg">删除</button>
<script type="text/javascript">
var vm = new Vue({
el: '#app-15',
data: {
stu: [
{
stuNum: "10010",
stuImg: "img/1.jpg",
stuName: "Tom",
stuGender: "M",
stuAge: 20
}
]
},
methods: {
doDelete: function (sNum, sName, event) {
alert("---delete:" + sNum + " " + sName)
console.log(event.srcElement.dataset)
}
}
})
</script>
8.4 事件修饰符
修饰符是由点开头的指令后缀来表示的。
当使用 v-on 进行事件绑定的时候,可以添加特定后缀,设置事件触发的特性
常用的事件修饰符:
- stop
- prevent
- capture
- self
- once
- passive
prevent 用来阻止标签的默认行为
<div id="app-16">
<form action="https://www.baidu.com">
<!-- 此处不加 .prevent ,网页会跳转到 https://www.baidu.com -->
<button type="submit" class="btn btn-success" @click.prevent="test">修改</button>
</form>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-16',
data: {},
methods: {
test: function (event) {
alert("--test");
}
}
})
</script>
stop 阻止事件冒泡
self 设置只能自己触发事件(子标签不能触发)
<div id="app-16">
<!-- .prevent 示例 -->
<form action="https://www.baidu.com">
<!-- 此处不加 .prevent ,网页会跳转到 https://www.baidu.com -->
<button type="submit" class="btn btn-success" @click层="test">修改</button>
</form>
<!-- .stop 示例 .self 示例:只能点击自己触发 -->
<div style="width: 200px; height: 200px; background: red;" @click.self="outside">
<div style="width: 100px; height: 100px; background: yellow;" @click="inside">
<!-- 此处加了 .stop , 网页的外层 div 父标签不会触发 -->
<button @click.stop="itself">test stop 修饰符</button>
</div>
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-16',
data: {},
methods: {
test: function (event) {
alert("--test");
},
inside: function () {
alert("--inside");
},
outside: function () {
alert("--outside");
},
itself: function () {
alert("--itself");
}
}
})
</script>
once 限定事件只能触发一次
<!-- .once 示例:test()方法只执行一次, -->
<form action="https://www.baidu.com">
<!-- 加了 .prevent,第一次点击执行 test(),默认跳转被阻止, 第二次点击按钮,直接跳转, test()不执行 -->
<button type="submit" class="btn btn-success" @click.prevent.once="test">修改</button>
</form>
8.5 按键修饰符
按键修饰符:针对键盘事件的修饰符,限定哪个按键会触发事件
常用的按键修饰符:
- enter
- tab
- delete (捕获“删除”和“退格”键)
- esc
- space
- up
- down
- left
- right
enter 只有在 key 是 Enter 时调用(触发 enter 按键之后触发事件)
<div id="app-17">
<input type="text" @keyup.enter="test">
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app-17',
data: {},
methods: {
test: function () {
alert("enter松开触发")
}
}
})
</script>
8.6 系统修饰符
示例:CTRL + J 触发事件
<div id="app-17">
<input type="text" @keyup.ctrl.j="test">
</div>
<script type="text/javascript">
Vue.config.keyCodes.j = 74
var vm = new Vue({
el: '#app-17',
data: {},
methods: {
test: function () {
alert("enter松开触发")
}
}
})
</script>
常用的修饰符:
- ctrl
- alt
- shift
- metawindows 键
九.表单输入绑定
表单输入绑定,即双向绑定:就是能够将 vue 实例的 data 数据渲染到表单输入视图 (input extareaselect),
也能够将输入视图的数据同步到 vue 实例的 data中。
十.组件
10.1 组件介绍及示例
组件,就是讲通用的 HTML 模块进行封装 —— 可复用的 Vue 实例
10.1.1 组件注册
将通用的 HTML 模块封装注册到 vue 中
自定义组件 my-components.js:
Vue.component('header-button', {
template: `<div style="width: 100%; height: 80px; background: salmon">
<table width="100%">
<tr>
<td width="200" align="right" valign="middle">
<img src="img/1.jpg" height="80" />
</td>
<td>
<label style="color: deepskyblue; font-size: 32px; font-family: 'Adobe 楷体 Std R'; margin-left: 30px">
登录
</label>
</td>
</tr>
</table>
</div>`
});
10.1.2 组件引用
- 定义组件需要依赖 vue.js,在引用自定义组件 js 文件要先引用 vue.js
- 组件的引用必须在 vue 实例 el 指定的容器中 ,即要在Vue实例范围内
10.2 组件注册
10.2.1 自定义组件的结构
- Vue.component() 注册组件
- data 定义组件的模板渲染的数据
- template 组件的 HTML 模块(HTML 标签 CSS 样式)
- methods 定义组件中的标签事件中绑定的 JS 函数
10.2.2 组件的封装
- 将模板中的 css 样式提取出来,单独封装到 css 文件存储在 css 目录
- 将模板中的图片存储在 img 目录
- 将定义组件的 js 文件和 vue 文件存放到 js 目录
在编码过程中学到,Vue 中同一个 DOM 元素绑定多个点击事件:可以使用逗号分隔。
10.3 组件通信
vue 实例本身就是一个组件(模板就是 el 指定容器,data 就是组件数据,methods 就是组件的事件函数)
在 vue 实例指定的 el 容器中引用的组件称为子组件,当前 vue 实例就是父组件
注:子组件按钮模板不能触发父组件的方法,子组件的按钮可以触发子组件的方法。
10.3.1 父传子
vue 实例引用组件的时候,传递数据到引用的组件中
通过组件的属性实现父组件传递数据到子组件
10.3.2 子传父 – 使用 props 属性动态传递参数
通过子组件的按钮“调用”父组件的函数,通过函数传值
10.3.3 总结
父组件通信子组件
- props: 子组件通过props获取定义父组件传递的自定义属
- this.$refs: 引用子组件
- this.$children: 父组件childrens属性,存储着所有的子组件
子组件通信父组件(或根组件)
- this. e m i t :子组件通过 emit: 子组件通过 emit:子组件通过emit访问父组件传递的自定义事件
- this.$parent: 访问父组件
- this.$root: 访问根组件。根组件root就是new Vue({el: “#app”}); 中的el元素
10.4 组件插槽
当我们自定义 vue 组件时,允许组件中的部分内容在调用组件时进行定义 —— 插槽
- 在自定义组件时通过 slot 标签在组件的模板中定义插槽
my-components-bar-slot.js:
Vue.component('header-bar', {
data: function() {
return {
title: "三国 -- √"
}
},
template: `<div class="divStyle">
<table class="tableStyle">
<tr>
<td width="200" align="right" valign="middle">
<img src="img/1.jpg" class="logoImg" />
</td>
<td>
<label class="nameStyle">
登录人: {{name}}
</label>
</td>
<td>
<slot></slot>
</td>
<td>
<button @click="childMethod">组件按钮点击次数</button>
</td>
</tr>
</table>
</div>`,
props: ["name"],
methods: {
childMethod: function () {
this.$emit("my-event", this.title);
}
}
});