Vue 是我接触的第一个前端框架,所以必须要认真学学,记录一下学到的知识点。
Vue 的特点
- 遵循 MVVM 模式
- 代码简洁,体积小,运行效率高,适合PC/移动端的开发
- 只关注 UI ,当然也可以引入 vue 插件或其他第三方开源库
HelloVue
第一个 vue demo
<body>
<div id="app">
<h2>{{msg}}</h2>
</div>
<!-- 引入 vue.js 文件 -->
<script src="../js/vue.js"></script>
<script>
// 创建一个 Vue 的实例对象
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
}
})
</script>
</body>
- 首先在 JS 中先创建一个 Vue 的实例对象
el
表示需要操作的 Element 节点,它的值是一个CSS选择器data
中存放的是数据,它是一个对象,它可以存放任意类型的值
运行后在界面上输出了
MVVM 模式
- 第一个 M 指的是 Model(模型) ,它本质上就是 数据对象
data
- 第一个 V 指的是 View(视图) ,它就是我们的模板页面
- VM 指的是 ViewModel(视图模型) ,它本质上一个 Vue 的
实例对象
,所以我们一般创建的时候都是这样创建的。
// vm 就是 Vue 对象的实例
const vm = new Vue({
el:'#app',
data:{ // model
...
}
})
在VM (视图模型) 中有两个东西,一个是 DOM Listeners (DOM 监听),一个是 Data Bindings (数据绑定)
DOM Listeners 会监听页面的变化,如果发生改变了,就会通知 model
Data Bindings 可以直接把内存中的数据(data 中的数据)显示到视图层,也就是我们的模板页面上
模板语法
1. 模板的理解:
动态的html页面
包含了一些JS语法代码
大括号表达式
指令(以v-开头的自定义标签属性)
2. 双大括号表达式
语法: {{exp}}
功能: 向页面输出数据
可以调用对象的方法
3. 指令一: 强制数据绑定
功能: 指定变化的属性值
完整写法:
v-bind:xxx='yyy' //yyy会作为表达式解析执行
简洁写法:
:xxx='yyy'
4. 指令二: 绑定事件监听
功能: 绑定指定事件名的回调函数
完整写法:
v-on:click='xxx'
简洁写法:
@click='xxx'
- 双大括号表达式
{{ 显示data中的数据 }}
- 强制数据绑定
- 绑定事件监听
<!-- 双大括号表达式 -->
<div id="app">
<h2>1. 双大括号表达式</h2>
<p>{{ message }}</p> <!-- 大括号表达式 -->
<p>{{ message.toUpperCase() }}</p> <!-- 转换成大写 -->
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
message: 'i want you',
}
})
</script>
<h2>2. 指令一: 强制数据绑定</h2>
<img v-bind:src="imgURL"> <!-- 基本语法 -->
<img :src="imgURL" alt=""> <!-- 简写 -->
<script type="text/javascript">
new Vue({
el: '#app',
data: {
imgURL: 'https://cn.vuejs.org/images/logo.png'
}
})
</script>
<h2>3. 指令二: 绑定事件监听</h2>
<button v-on:click="test">基本语法</button> <!-- 基本语法 -->
<button @click="test2">简写</button> <!-- 简写 -->
<script type="text/javascript">
new Vue({
el: '#app',
data: {
message: 'i want you'
imgURL: 'https://cn.vuejs.org/images/logo.png'
},
methods: { // 方法写到这里
test() {
alert('绑定事件监听!')
},
test2() {
alert('我是简写')
}
}
})
</script>
计算属性和监视
1. 计算属性
在computed属性对象中定义计算属性的方法
在页面中使用{{方法名}}来显示计算的结果
2. 监视属性:
通过通过vm对象的$watch()或watch配置来监视指定的属性
当属性变化时, 回调函数自动调用, 在函数内部进行计算
3. 计算属性高级:
通过getter/setter实现对属性数据的显示和监视
计算属性存在缓存, 多次读取只执行一次getter计算
getter: 对应属性的 get 方法
setter: 对应属性的 set 方法
<div id="app">
姓: <input type="text" placeholder="First Name" v-model="firstName"><br>
名: <input type="text" placeholder="Last Name" v-model="lastName"><br>
<!--fullName1是根据fistName和lastName计算产生-->
姓名1(单向): <input type="text" placeholder="Full Name1" v-model="fullName1"><br>
姓名2(单向): <input type="text" placeholder="Full Name2" v-model="fullName2"><br>
姓名3(双向): <input type="text" placeholder="Full Name3" v-model="fullName3"><br>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el: '#app',
data: {
firstName: 'A',
lastName: 'B',
fullName2: 'A B'
},
computed: { // 计算属性 , 计算属性会缓存数据
// 在首次初始化的时候执行 / 相关的数据发生了改变的时候自动执行 (firstName,lastName)
fullName1: function () {
console.log('function()')
// 这里的 this 是 vm 对象,也就是 vue 的实例对象
return this.firstName + ' ' + this.lastName
},
// 使用计算属性来实现数据的双向绑定
fullName3: {
// 获取
get() {
return this.firstName + ' ' + this.lastName
},
// 设置,当属性值发生改变时回调,更新相关的属性数据(firstName,lstName)
set(value) { // value 就是 fullName3 的最新属性值
var names = value.split(' ')
this.firstName = names[0]
this.lastName = names[1]
}
}
},
watch: { // 监视方式1 (配置监视)
// 当 firstName 的值发生变化的时候调用
firstName: function (value) {
// 这里的 this 是 vm 对象,也就是 vue 的实例对象
this.fullName2 = value + ' ' + this.lastName
}
}
})
// 监视的方式2
vm.$watch('lastName', function (value) {
// 这里的 this 也是 vue 的实例对象 vm
this.fullName2 = this.firstName + ' ' + value
})
</script>
运行效果
class 与 style 绑定
1. 理解
在应用界面中, 某个(些)元素的样式是变化的
class/style绑定就是专门用来实现动态样式效果的技术
2. class绑定: :class='xxx'
xxx是字符串
xxx是对象 { class:布尔值,class:布尔值 }
xxx是数组
3. style绑定
:style="{ color: activeColor, fontSize: fontSize + 'px' }"
其中activeColor/fontSize是data属性
<!-- 样式 -->
<style>
.aClass {
color: red;
}
.bClass {
color: green;
}
.cClass {
font-size: 30px;
}
</style>
<!-- 结构 -->
<div id="app">
<h2>1. class绑定: :class='xxx'</h2>
<p class="cClass" :class="a">xxx是字符串</p>
<p :class="{aClass:isA,bClass:isB}">xxx是对象</p>
<p :class="['bClass','cClass']">xxx是数组</p>
<h2>2. style绑定</h2>
<p :style="{color: activeColor, fontSize: fontSize + 'px'}">style 样式绑定</p>
<!-- 点击按钮以后修改 p 的样式 -->
<button @click="updated">点我更换样式</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
a: 'aClass',
isA: true,
isB: false,
activeColor: 'pink',
fontSize: 20
},
methods: {
updated() {
this.a = 'bClass'
this.isA = false
this.isB = true
this.activeColor = 'green'
this.fontSize = 30
}
}
})
</script>
条件渲染
1. 条件渲染指令
v-if : 在内存中把标签移出
v-else
v-show : 通过display样式来控制元素的显示和隐藏
2. 比较v-if与v-show
如果需要频繁切换 v-show 较好
<div id="app">
<p v-if="ok">成功了</p>
<p v-else>失败了</p>
<p v-show="ok">入职成功</p>
<p v-show="!ok">入职失败</p>
<button @click="ok = !ok">切换</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
ok: true
}
})
</script>
列表渲染
1. 列表显示
数组: v-for / index
对象: v-for / key
2. 列表的更新显示
删除item
替换item
<div id="app">
<h2>测试: v-for 遍历数组</h2>
<ul>
<li v-for="(p,index) in persons" :key="index">{{index}}----{{p.name}}----{{p.age}}
---- <button @click="deletePerson(index)">删除</button>
---- <button @click="updatePerson(index,{name:'Dog',age:20})">更新</button>
</li>
</ul>
<h2>测试: v-for 遍历对象</h2>
<ul>
<li v-for="(value,key) in persons[1]" :key="key">
{{value}}---{{key}}
</li>
</ul>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
// vue 本身只是监视了 Persons 的改变,没有监视 数组内部的改变
// vue 重写了数组中一系列改变数组内部的方法(先调用原生的,更新界面)---> 数组内部改变,界面自动变化
new Vue({
el: '#app',
data: {
persons: [{
name: '孙悟空',
age: 18
},
{
name: '猪八戒',
age: 23
},
{
name: '沙和尚',
age: 30
},
{
name: '唐僧',
age: 25
},
{
name: '观音菩萨',
age: 30
}
]
},
methods: {
deletePerson(index) {
// 删除 Persons 中指定 index 的 Person
this.persons.splice(index, 1)
},
updatePerson(index, newP) {
// 删除 Persons 中指定 index 的 Person
// 用 splice 方法可以实现增删改
this.persons.splice(index, 1, newP)
}
},
})
</script>
实现功能
列表的过滤和排序
<div id="app">
<input type="text" v-model="searchName">
<ul>
<li v-for="(item, index) in filterPersons" :key="index">
{{index}}---{{item.name}}---{{item.age}}
</li>
</ul>
<button @click="setOrderType(1)">年龄升序</button>
<button @click="setOrderType(2)">年龄降序</button>
<button @click="setOrderType(0)">原本顺序</button>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
searchName: '',
orderType: 0, // 0 表示原本顺序
persons: [{
name: 'ATom',
age: 24
},
{
name: 'ABom',
age: 17
},
{
name: 'Asiner',
age: 30
},
{
name: 'Ajeer',
age: 25
},
{
name: 'Acolor',
age: 32
}
]
},
computed: { // 使用 计算属性
filterPersons() {
// 1. 取出相关的数据
const {
searchName,
persons,
orderType
} = this
let fPersons // 最终需要显示的数组
// 2. 对 persons 进行过滤 , 然后赋值给 fPersons
fPersons = persons.filter(p => p.name.indexOf(searchName) !== -1)
// 排序
if (orderType !== 0) {
// 自定义排序规则
fPersons.sort(function (p1, p2) {
// 1 代表升序 ,2 代表降序 ,0 代表原本顺序
if (orderType === 2) {
return p2.age - p1.age
} else {
return p1.age - p2.age
}
})
}
return fPersons
}
},
methods: {
setOrderType(orderType) {
this.orderType = orderType
}
},
})
</script>
事件绑定
1. 绑定监听:
v-on:xxx="fun"
@xxx="fun"
@xxx="fun(参数)"
默认事件形参: event
隐含属性对象: $event
2. 事件修饰符:
.prevent : 阻止事件的默认行为 event.preventDefault()
.stop : 停止事件冒泡 event.stopPropagation()
3. 按键修饰符
.keycode : 操作的是某个keycode值的健
.enter : 操作的是enter键
<div id="app">
<h2>1. 绑定监听</h2>
<button @click="test1">btn01</button>
<button @click="test2(msg)">btn02</button>
<button @click="test3($event)">btn03</button>
<button @click="test4(msg,$event)">btn04</button>
<h2>2. 事件修饰符</h2>
<!-- 停止事件冒泡 -->
<div style="width: 200px;height: 200px; background-color: greenyellow;" @click="test5">
<div style="width: 100px;height: 100px; background-color: goldenrod;" @click.stop="test6"></div>
</div>
<!-- 阻止事件的默认行为 -->
<a href="http://www.baidu.com" @click.prevent="test7">去百度</a>
<h2>3. 按键修饰符</h2>
<input type="text" @keyup.13="test8">
<input type="text" @keyup.enter="test8">
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
msg: 'a message'
},
methods: {
test1() {
alert('test1')
},
test2(msg) {
alert(msg)
},
test3(event) {
alert(event.target.innerHTML)
},
test4(msg, event) {
alert(msg + ' ' + event.target.innerHTML)
},
test5() {
alert('test5')
},
test6() {
alert('test6')
},
test7() {
alert('test7')
},
test8(event) {
alert(event.target.value)
}
},
})
</script>
表单输入绑定
1. 使用v-model(双向数据绑定)自动收集数据
text/textarea
checkbox
radio
select
<div id="demo">
<form action="/xxx" @submit.prevent="handleSubmit">
<span>用户名: </span>
<input type="text" v-model="username"><br>
<span>密码: </span>
<input type="password" v-model="password"><br>
<span>性别: </span>
<input type="radio" id="female" v-model="sex" value="女">
<label for="female">女</label>
<input type="radio" id="male" v-model="sex" value="男">
<label for="male">男</label><br>
<span>爱好: </span>
<input type="checkbox" id="basket" value="basket" v-model="likes">
<label for="basket">篮球</label>
<input type="checkbox" id="foot" value="foot" v-model="likes">
<label for="foot">足球</label>
<input type="checkbox" id="pingpang" value="pingpang" v-model="likes">
<label for="pingpang">乒乓</label><br>
<span>城市: </span>
<select v-model="cityId">
<option value="">未选择</option>
<option v-for="(city, index) in allCitys" :key="index" :value="city.id">{{city.name}}</option>
</select><br>
<span>介绍: </span>
<textarea rows="10" v-model="desc"></textarea><br><br>
<input type="submit" value="注册">
</form>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#demo',
data: {
username: '',
password: '',
sex: '女',
likes: ['foot'],
allCitys: [{
id: 1,
name: 'beijing'
},
{
id: 2,
name: 'shanghai'
},
{
id: 3,
name: 'sandong'
},
],
cityId: '',
desc: ''
},
methods: {
handleSubmit() {
console.log(this.username, this.password, this.sex, this.likes, this.allCitys, this.cityId, this.desc)
}
},
})
</script>
Vue 对象的生命周期
1. vue对象的生命周期
1). 初始化显示
* beforeCreate()
* created()
* beforeMount()
* mounted()
2). 更新状态
* beforeUpdate()
* updated()
3). 销毁vue实例: vm.$destory()
* beforeDestory()
* destoryed()
2. 常用的生命周期方法
created()/mounted(): 发送ajax请求, 启动定时器等异步任务
beforeDestory(): 做收尾工作, 如: 清除定时器
<div id="app">
<button @click="destoryVM">destory vm</button>
<p v-show="isShow">小明爱吃肉</p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
isShow: true
},
// 初始化阶段
beforeCreate() {
console.log('beforeCreate()')
},
created() {
console.log('created()')
},
beforeMount() {
console.log('beforeMount()')
},
mounted() { //初始化显示之后,立即调用 一次
console.log('mounted()')
this.intervalId = setInterval(() => { // 箭头函数
console.log('===')
this.isShow = !this.isShow
}, 1000);
},
// 更新阶段
beforeUpdate() {
console.log('beforeUpdate()')
},
updated() {
console.log('updated()')
},
// 死亡阶段
beforeDestroy() { // 死亡之前调用 一次
console.log('beforeDestroy()')
// 清除定时器
clearInterval(this.intervalId)
},
destroyed() {
console.log('destroyed()')
},
methods: {
// 按钮的点击事件
destoryVM() {
//
this.$destroy()
}
},
})
</script>
Vue 过渡和动画
过渡
1. vue动画的理解
操作css的trasition或animation
vue会给目标元素添加/移除特定的class
2. 基本过渡动画的编码
1). 在目标元素外包裹<transition name="xxx">
2). 定义class样式
1>. 指定过渡样式: transition
2>. 指定隐藏时的样式: opacity/其它
3. 过渡的类名
xxx-enter-active: 指定显示的transition
xxx-leave-active: 指定隐藏的transition
xxx-enter: 指定隐藏时的样式
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade2-enter-active {
transition: opacity 3s, transform 1s;
}
.fade2-leave-active {
transition: opacity 1s, transform 3s;
}
.fade2-enter,
.fade2-leave-to {
opacity: 0;
transform: translate(20px);
}
</style>
<div id="test">
<button @click="isShow=!isShow">togger</button>
<transition name="fade">
<p v-show="isShow">hello</p>
</transition>
</div>
<div id="test2">
<button @click="isShow=!isShow">togger</button>
<transition name="fade2">
<p v-show="isShow">hello</p>
</transition>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
new Vue({
el: '#test',
data() {
return {
isShow: true
}
},
})
new Vue({
el: '#test2',
data() {
return {
isShow: true
}
},
})
</script>
Animation
<style>
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
<body>
<div id="example-2">
<button @click="show = !show">Toggle show</button><br>
<transition name="bounce">
<p v-if="show" style="display: inline-block">Lorem ipsum</p>
</transition>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script>
new Vue({
el: '#example-2',
data: {
show: true
}
})
</script>
</body>
过滤器
1. 理解过滤器
功能: 对要显示的数据进行特定格式化后再显示
注意: 并没有改变原本的数据, 可是产生新的对应的数据
2. 编码
1). 定义过滤器
Vue.filter(filterName, function(value[,arg1,arg2,...]){
// 进行一定的数据处理
return newValue
})
2). 使用过滤器
<div>{{myData | filterName}}</div>
<div>{{myData | filterName(arg)}}</div>
<!--需求: 对当前时间进行指定格式显示-->
<div id="test">
<h2>显示格式化的日期时间</h2>
<p>{{date}}</p>
<p>完整版:{{date | dateString}}</p>
<p>年月日:{{date | dateString('YYYY-MM-DD')}}</p>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<!-- 时间格式化的js库 -->
<script type="text/javascript" src="https://cdn.bootcss.com/moment.js/2.22.1/moment.js"></script>
<script>
// 自定义过滤器,通过 Vue 的函数对象
Vue.filter('dateString', function (value, format = 'YYYY-MM-DD HH:mm:ss') { // 形参默认值
return moment(value).format(format)
})
new Vue({
el: '#test',
data: {
date: new Date(),
},
})
</script>