文章目录
Vue
初始vue
开发前的配置
1.官网下载vue的依赖安装包,有两个版本,开发版本和测试版本。在 实际开发中使用开发版本,在打包上传的时候使用测试版本。
2.在浏览器中安装其开发者工具插件
案例
<!DOCTYPE html>
<html lang="en">
<head>
<title>初始vue</title>
<!-- 引入Vue -->
<script src="../js/vue.js" type="text/javascript"></script>
</head>
<body>
<!-- 总结
1.想让Vue工作就必须创建Vue的实例,且要传入一个配置对象
2.root容器里的代码依然符合 html规范,只不过混入了一些特殊的Vue语法
3.root里的代码被称为【Vue模板】
4.Vue实例和容器是一一对应的
5.真实开发中只有一个实例,并且会配合着组件一起使用
6.{{xx}}里中的xx要写js表达式,且xx可以自动读取data里的属性
7.一旦data里面的数据发生改变,那么模板中用到该数据的地方也会发生改变
注意区分js表达式和js代码
js表达式:
1. 一个表达式可以产生一个值,可以放在任何一个需要值的地方
(1)a
(2)a+b
const = (3)demo(1)
(4)x === y ? 'a':'b'
js代码:
for()
if(){}
-->
<!-- 创建一个容器 -->
<div id="root">
<h1>hello {{name}} </h1>
</div>
<script type="text/javascript">
// 设置为 false 以阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false
//创建一个vue实例,并且将配置对象传入进去
new Vue({
el:'#root', //el用于指定当前vue为哪个容器服务,值通常为css选择器
data:{
name:'world' //data用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象
}
})
</script>
</body>
</html>
指令语法
<!DOCTYPE html>
<head>
<!-- 引入Vue -->
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 插值语法 -->
<!-- 首先创建一个容器 -->
<div id="root">
<h1>插值语法</h1>
<h2>你好,{{name}}</h2>
<hr>
<h1>指令语法</h1>
<a v-bind:href="url">点我去百度</a>
<a :href="url">点我去百度</a>
</div>
<!-- 创建一个vue对象 -->
<script>
Vue.config.productionTip = false // 设置为 false 以阻止 vue 在启动时生成生产提示
new Vue({
el:'#root' , //#代表了id选择器,el用于指定当前vue为哪个容器服务,值为css的id选择器
data:{
name:'vue',
url:'https://www.baidu.com/',
}
})
</script>
总结
Vue模板的两大类:
- 插值语法
- 功能:用于解析标签体内的内容
- 写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
- 指令语法
- 功能:用于解析标签(包括:标签属性,标签体内容,绑定事件…)
- 举例:v-bind:href = ‘xxx’ 或简写为:href = ‘xxx’ ,xxx同样要写js表达式。且可以直接读取到data中的所有属性
- 备注:Vue中有很多的指令,且形式都是:v-??? 。
单向绑定与双向绑定
Vue中有两种数据绑定方式:
- 单项绑定(v-bind):数据只能从data流向页面
- 双向绑定(v-model): 数据不仅能从data流向页面,还可以从页面流向data。
-
- 备注:
-
- 双向绑定一般都应用在表单类元素上(如:input,select等)
- v-model:value 可以简写为v-model,因为v-model默认收集的就是value的值。
<!-- 创建一个容器 -->
<div id="root">
<!-- 正常写 -->
<!-- 单向绑定:<input type="text" v-bind:value="name">
双向绑定:<input type="text" v-model: value="name"> -->
<!-- 简写 -->
单向绑定:<input type="text" :value="name">
双向绑定:<input type="text" v-model="name">
</div>
<!-- 创建一个vue实例 -->
<script>
new Vue({
el:'#root' , //el用于指定当前vue为哪个容器服务
data:{
name:'vue'
}
})
</script>
el的两种写法
- el:‘#root’,
- v.$mount(‘#root’)
<div id="root">
<h1> 你好,{{name}} </h1>
</div>
<script>
const v = new Vue({
// el:'#root', //第一中写法
data:{
name:'vue'
}
})
v.$mount('#root') //第二中写法,mount的意思有挂载, 这个方法不是实例变量所拥有的,而是构建方法Vue所拥有的
</script>
data的两种写法
- data:{}
- data:function(){}
- 简写: data(){}
<script>
new Vue({
el:'#root',
// data:{
// name:'vue'
// } //目前这种写法没什么问题
// data:function(){
// return {
// name:'vue'
// }
// }
//简写 ,当以后需要使用组件的时候一定要用函数的形式,,这个
data(){
console.log(this) //这个this返回的是Vue的实例变量,如果要用箭头函数写的换话this代表的是windos,后期影响会很大
return{
name:'vue'
}
}
})
</script>
总结
data与el的两种写法
-
el有2种写法
- new Vue时候配置el属性
- 先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值
-
data的2中写法
-
对象式
-
函数式
如何选择:目前那种写法都可以,以后学习到组件的时候,data必须使用函数式
-
-
一个重要的原则:
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了
MVVM模型
总结
MVVM模型
- M:模型(Model):data中的数据
- V:视图(View):模板代码
- VM:视图模型(ViewModel):Vue实例
观察发现:
- data中所有 的属性,最后都出现在了vm身上
- vm身上所有的属性及Vue原型上所有的属性,在Vue模板中都可以直接使用
数据代理Object.defineProperty
<script>
let number = 18
let persion = {
name:'vue'
}
Object.defineProperty(persion,'age',{
//填写配置
// value:number,
// enumerable:true,//控制属性是否可以被枚举
// writable:true, //控制属性是否可以被修改
// configurable:true //控制属性是否可以被删除
//当age被调用时候,就会执行此方法
get(){
return number;
},
//当age被赋值时候,调用set方法
set(value){
number = value;
}
})
//总结,object.defineproperty()添加数据的安全性更高,操作性更强,可变性也强
console.log(Object.keys(persion))
</script>
数据代理小结:
-
Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
-
Vue中数据代理的好处:
更加方便的操作data中的数据
-
基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上 的属性都指定一个getter/setter
在getter/setter内部去操作(读/写)data中对应的属性
图解:
事件处理
总结
事件的基本使用:
- 使用v-on:xxx 或@xxx绑定事件,其中xx是事件名
- 事件的回调需要配置在methods对象中,最终会在vm上
- methids中配置的函数,不要用箭头函数!否则this就不是vm了
- methids中配置的函数,都是被Vue所管理的函数,this的指向是vm或组件实例对象
- @click=‘demo’ 和@click=‘demo($event)’ 效果一致,但后者可以传参
<div id="root">
<h1>你好,{{name}} </h1>
<button v-on:click="showInfo">请点我</button>
<!-- 简写 -->
<button @click="showInfo2(66)">请点我</button>
</div>
<!-- 注意事项,模板里面用到的数据只能在vue实例中调用,对象里面是方法 -->
<script>
new Vue({
el:'#root',
data:{
name:'刘先生'
},
methods:{
showInfo(){
alert('同学你好')
},
showInfo2(a){
console.log(a)
alert('同学你好!')
}
}
})
</script>
事件处理的修饰符:
总结
Vue中的事件修饰符:
- prevent:阻止默认事件(常用)
- stop:阻止事件冒泡(常用)
- once:事件只触发一次(常用)
- capture:使用事件的捕获模式(先从外向内捕获,再从内向外冒泡,一般都是在冒泡的时候执行点击事件)
- self:只有event.target 是当前操作的元素时才触发事件
- passive:事件的默认行为立即执行,无需等待事件回调执行完毕
- 修饰符可以连续写
<body>
<div id="root" @click.capture = 'showInfo2(1)'>
<!-- prevent属性阻止默认事件 -->
<!-- <a href="https://www.baidu.com/" @click.prevent = 'showInfo'> 点击跳着</a> -->
<a @click = 'showInfo(2)'> 点击跳着</a>
</div>
<script>
new Vue({
el:'#root',
data:{
name:'刘先生'
},
methods:{
showInfo(a){
console.log(a)
alert('同学你好')
},
showInfo2(a){
console.log(a)
alert('同学你好!')
}
}
})
</script>
</body>
Vue常用按键别名
-
Vue中常用的按键别名:
回车 ======enter
删除 ========delete
退出=========esc
空格=========spacwe
换行=========tab
上===========up
下===========down
左===========left
右===========right
-
vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
-
系统修饰键(用法特殊):ctrl alt shift meta
- 配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发
- 配合keydown使用:正常触发
-
也可以使用keyCode去指定具体的按键 (不推荐)
-
vue.config.keyCodes 自定义键名 = 键码,可以去定制按键别名
<body>
<div id="root">
<input type="text" placeholder="请输入" @keydown.enter="infor" >
</div>
<script>
new Vue({
el:'#root',
methods:{
infor(e){
console.log(e.target.value)
}
}
})
</script>
</body>
vue计算属性
- 定义:要用的属性不存在,要通过已有属性计算得来
- 原理:底层借助了Objcet.defineproperty()方法提供的getter和setter
- get函数什么时候执行?
- 初次调用的时候会执行一次
- 当依赖的属性发生改变时会被再次调用
- 优势:与methods实现相比,内部由缓存机制(复用)。效率更高,调试方便
- 备注:
- 计算属性最终会出现在vm上,直接读取使用即可
- 如果计算属性要被修改,那必须写set函数去响应修改,且setter中要引起计算所依赖的数据发生改变
三种写法比较
- 通过插值语句
<div id="root">
名: <input type="text" v-model:value="firstName"><br>
姓: <input type="text" v-model:value="lastName"><br>
全名: <span> {{firstName}}-{{lastName}}</span>
</div>
<script>
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
}
})
</script>
- 通过methods
<script>
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
methods:{
fullName(){
return this.firstName + '-' + this.lastName
}
}
})
</script>
- 通过计算属性
<script>
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName:{
//只要fullName方法一被调用,就执行getter
//get什么时候调用? 1. 初次读取fullName时。2.所依赖的数据发生改变时。
get(){
// console.log(this) 此处的this代表vue
return this.firstName + '-' + this.lastName
}
}
}
})
</script>
小结
监视属性watch:
- 当被监视的属性变化时,回调函数自动调用,进行相关操作
- 监视的属性必须存在,才能进行监视
- 监视属性的两种写法:
- new Vue 时传入watch配置
- 通过vm.$watch监视
<div id="root">
<h2>今天 天气很{{info}}</h2>
<button @click="changeMeather" >切换天气</button>
<!-- 当处理的事情很简单的时候可以直接写 -->
<!-- @xxx='yyy' yyy可以写一些简单的语句 -->
<!-- <button @click="isHot = !isHot" >切换天气</button> -->
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHot:true
},
//计算属性
computed:{
info:{
get(){
return this.isHot ? '炎热' : '凉爽'
}
}
},
//方法
methods:{
changeMeather(){
return this.isHot = !this.isHot
}
},
// 不光可以检测data中的属性还可以监测计算属性
// 方法一================================
// watch:{
// //监测属性变化, xxx:{}这种写法叫配置对象
// isHot:{
// immediate:true,//初始化时,让handler调用一下
// //handler什么时候调用?当ishot发生改变的时。
// handler(newValue,oldValue){
// console.log('isHost被修改了',newValue,oldValue)
// }
// }
// }
//================方法二通过vm实现====================
})
vm.$watch('isHot',{
immediate:true,//初始化时,让handler调用一下
handler(newValue,oldValue){
console.log('isHost被修改了',newValue,oldValue)
}
})
</script>
深度监视
深度监视:
- Vue中的watch默认不监测对象内部值的改变(一层)
- 配置deep:true可以监测对象内部值改变(多层)
备注:
- Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以
- 使用watch时根据数据的具体结构,决定是否采用深度监视
- 箭头函数没有自己的this
<body>
<div id="root">
<h2>今天 天气很{{info}}</h2>
<button @click="changeMeather" >切换天气</button>
<hr>
<h2>a的值是{{numbers.a}}</h2>
<button @click="numbers.a++">点击让a的值加1</button>
<h2>b的值是{{numbers.b}}</h2>
<button @click="numbers.b++">点击让b的值加1</button>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
isHot:true,
numbers:{
a:'1',
b:'1'
} },
//计算属性
computed:{
info:{
get(){
return this.isHot ? '炎热' : '凉爽'
}
}
},
//方法
methods:{
changeMeather(){
return this.isHot = !this.isHot
}
},
watch:{
//监测属性变化, xxx:{}这种写法叫配置对象
isHot:{
immediate:true,//初始化时,让handler调用一下
//handler什么时候调用?当ishot发生改变的时。
handler(newValue,oldValue){
console.log('isHost被修改了',newValue,oldValue)
}
},
// 'numbers.a': {
// handler(){
// console.log("a被监视了")
// }
// }
//需求检测numbers,只要里面的任何一个数据发生改变,
numbers:{
//这样检测的是numbers这个配置对象的地址,即使里面的数据发生改变但地址不变,就监测不到,
//于是这里我们学习深度监测,让其向内继续监测
deep:true, //这个配置项就实现了这个功能
//只要发生改变,就调用
handler(){
console.log('numbers被调用了')
}
}
}
})
</script>
</body>
简写
<script>
methods:{
changeMeather(){
return this.isHot = !this.isHot
}
},
watch:{
//正常写法
// isHot:{
// immediate:true,//初始化时,让handler调用一下
// //handler什么时候调用?当ishot发生改变的时。
// handler(newValue,oldValue){
// console.log('isHost被修改了',newValue,oldValue)
// }
//当只用到handler的时候简写成方法
// isHot(newValue,oldValue){
// console.log('isHost被修改了',newValue,oldValue)
// }
}
})
//使用vm对象简写
vm.$watch('isHot',function(newValue,oldValue){
console.log('isHost被修改了',newValue,oldValue)
})
</script>
用监视属性来改写计算属性
<div id="root">
姓: <input type="text" v-model="firstName"><br>
名: <input type="text" v-model="lastName"><br>
全名: <span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三',
fullName:'张-三'
},
watch:{
firstName(val){
return this.fullName = val + '-' + this.lastName
},
lastName(val){
return this.fullName = this.firstName + '-' + val
}
}
})
</script>
computed和watch之间的区别:
- computed能完成的功能,watch都可以完成
- watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
两个重要 的原则:
- 所被 Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件对象
- 所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等,promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件对象。
绑定样式
绑定class样式
<div id="root">
<!-- 绑定 class样式--字符串写法,适用于:样式的类名不确定,需要动态绑定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定,冥冥中也不确定 -->
<div class="basic" :class="classArr">{{name}}</div>
<!--绑定class样式--对象写法,适用于:要绑定的样式个数确定,名字也确定,但要 动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div>
</div>
<script>
new Vue({
el:'#root',
data:{
name:'天气',
mood:'',
classArr:['a','b','c'],
classObj:{
a:true,
b:true,
}
},
methods: {
changeMood(){
this.mood = ''
}
},
})
</script>
绑定style样式
- 对象里面的key不能瞎写
<div class="basic" :style="styleObj">{{name}}</div>
data:{
styleObj:{
fontSize:'40px'
}
},
条件渲染
-
v-if
写法:
- v-if=‘表达式’
- v-else-if=‘表达式’
- v-else
适用于:切换频率较低的场景
特点:不展示的dom元素直接移除
注意:v-if 可以和v-else-if,v-else 一块使用,但要求结构不能被破坏
-
v-show
写法:v-show=‘表达式’
适用于:切换频率比较高的场景
特点:不展示的dom元素未被移除
-
备注:使用v-if的时,元素可能无法获取到,而使用v-show的时候元素一定能获取到
<div id="root">
<h1 >n 的值为{{n}}</h1>
<!-- 需求1 让标签隐藏 v-show -->
<!-- <h1 v-show="false">n 的值为{{n}}</h1> -->
<button @click="n++">点击让n加1</button>
<!-- 使用v-if,v-else-if,v-else的时候要把标签放在一块形成一个组合来使用 -->
<h2 v-if="n === 1">vue</h2>
<h2 v-else-if="n === 2">java</h2>
<h2 v-else>我权限最大</h2>
<!-- 需求,当n===1的时候让三个标签都显示 -->
<!--相比于div包裹, tempate的优点不影响页面结构,使用完之后 ,就被脱掉了
不能和v-show 一块使用 -->
<template v-if="n === 1">
<h1>111</h1>
<h1>111</h1>
<h1>111</h1>
</template>
列表渲染
<body>
<div id="root">
<h2>人员列表</h2>
<!-- 遍历数组 -->
<ul>
<li v-for="(p,index) in persions" :key="index">
{{p.name}}-{{p.age}} ----{{index}}
</li>
</ul>
<!-- 遍历对象 -->
<ul>
<li v-for="(p,index) in car" ::key="index">
{{index}}----{{p}}
</li>
</ul>
<!-- 遍历字符串 -->
<h2>遍历字符串</h2>
<ul>
<li v-for="(char,index) in str" ::key="index">
{{char}}--{{index}}
</li>
</ul>
<h2>遍历指定次数</h2>
<ul>
<li v-for="(item,index) in 5" :key="index">
{{item}}--{{index}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
persions:[
{name:'张三',age:'18'},
{name:'李四',age:'17'},
{name:'王五',age:'19'}
],
car:{
name:'奥迪a8',
price:'70w'
},
str:'hello'
}
})
</script>
key的作用与原理
场景:在数据前面增加数据的时候,不用使用index作为key的唯一标识,
-
虚拟dom中key的作用:
key是虚拟dom对象的标识,当状态中的数据发生变化时,vue会根据新数据生成新的虚拟 dom
随后vue进行新虚拟dom与旧虚拟dom的差异比较
-
对比规则:
- 旧虚拟dom中找到与新虚拟dom相同的key:
- 若虚拟dom中内容没变,直接使用之前的真实dom
- 若虚拟dom中内容变了,则生成新的真实dom,随后替换掉页面中之前的真实dom
- 旧虚拟dom中未找到与新虚拟dom相同的key,创建新的真实dom,随后渲染到页面。
- 旧虚拟dom中找到与新虚拟dom相同的key:
-
用index作为key可能会引发的问题
-
若对数据进行:逆序添加,逆序删除等破坏顺序操作:
会产生没有必要的真实dom更新===》界面效果没问题,但效率低
-
如果结构中还包含输入类 的dom:
会产生错误dom更新====》界面有问题
-
-
开发中如何选择key?
-
最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号
-
如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,
使用index作为key是没问题的。
列表过滤
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入姓名" v-model="keyWords">
<ul>
<li v-for="(p,index) in filPersions">
{{p.name}}-{{p.age}} -{{p.sex}}
</li>
</ul>
</div>
<script>
// 使用监视属性watch实现
//#region
/* new Vue({
el:'#root',
data:{
keyWords:'',
persions:[
{name:'马冬梅',age:19,sex:'女'},
{name:'周冬雨',age:20,sex:'女'},
{name:'周杰伦',age:21,sex:'男'},
{name:'温兆伦',age:22,sex:'男'}
],
filPersions:[]
},
watch:{
keyWords:{
immediate:true,
handler(val){
this.filPersions = this.persions.filter((p)=>{
return p.name.indexOf(val) !== -1
})
}
}
}
}) */
//#endregion
//使用计算属性来实现
new Vue({
el:'#root',
data:{
keyWords:'',
persions:[
{name:'马冬梅',age:19,sex:'女'},
{name:'周冬雨',age:20,sex:'女'},
{name:'周杰伦',age:21,sex:'男'},
{name:'温兆伦',age:22,sex:'男'}
]
},
computed:{
/* filPersions(){
return this.persions.filter((p)=>{
return p.name.indexOf(this.keyWords) !== -1
})
} */
filPersions:{
get(){
return this.persions.filter((p)=>{
return p.name.indexOf(this.keyWords) !== -1
})
}
}
}
})
</script>
列表排序
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入姓名" v-model="keyWords">
<button @click="sortType=2">升序排列</button>
<button @click="sortType=1">降序排列</button>
<button @click="sortType=0">原顺序</button>
<ul>
<li v-for="(p,index) in filPersions">
{{p.name}}-{{p.age}} -{{p.sex}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
keyWords:'',
sortType:0,
persions:[
{name:'马冬梅',age:19,sex:'女'},
{name:'周冬雨',age:20,sex:'女'},
{name:'周杰伦',age:21,sex:'男'},
{name:'温兆伦',age:22,sex:'男'}
]
},
computed:{
filPersions:{
get(){
const arr = this.persions.filter((p)=>{
return p.name.indexOf(this.keyWords) !== -1
})
if(this.sortType){
arr.sort((p1,p2)=>{
return this.sortType == 1? p2.age - p1.age : p1.age - p2.age
})
}
return arr
}
}
}
})
</script>
vue自身数据监测的原理
<div id="root">
<h2>人员列表</h2>
<button @click="updateMei">点击更新马冬梅的信息</button>
<ul>
<li v-for="(p,index) in persions">
{{p.name}}-{{p.age}} -{{p.sex}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
keyWords:'',
persions:[
{name:'马冬梅',age:19,sex:'女'},
{name:'周冬雨',age:20,sex:'女'},
{name:'周杰伦',age:21,sex:'男'},
{name:'温兆伦',age:22,sex:'男'}
]
},
methods:{
updateMei(){
// this.persions[0].name = '马老师'//x有效
// this.persions[0].age = '50'//x有效
// this.persions[0].sex = '男'//x有效
this.persions[0] = {name:'马老师',age:60,sex:'男'}
}
}
})
</script>
小案例
<script>
// 这只是一个简单的写法案例,vue比这个复杂的多,它不仅可以解析第一层的属性,还可以解析属性包裹着的属性
//通过递归实现
//该案例是没有办法解析里面的属性的
let data = {
name:'叶落',
address:'山东'
}
const obs = new Observer(data)
//准备一个vm对象
let vm = {}
vm._data = data = obs
//先写一个构造方法,监测对象属性的变化,所有我们需要给它传递一个形参对象
function Observer(obj){
//首先把监测对象中的属性形成一个数组
const keys = Object.keys(obj)
//通过Object.defineProperty数据代理
keys.forEach((k)=>{
Object.defineProperty(this,k,{
get(){
return obj[k]
},
set(val){
console.log('${k}被修改了,我要去解析模板,生成新的虚拟dom......我要开始忙了')
return obj[k] = val
}
})
})
}
</script>
总结Vue数据监测
-
vue会监视data中所有层次的数据
-
如何监测对象中的数据?
通过setter实现监视,且要哎new Vue 时就传入要监测的数据
- 对象中后追加的属性,Vue默认不做响应式处理
- 如需给后 添加的属性做响应式,请使用如下api:
- Vue.set(target, propertyName/index, value)
- vm.$set(target,propertName/index,value)
-
如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
- 调用原生对应的方法对数据进行更新
- 重新解析模板,进而更新页面
-
在Vue修改数组中的某个元素一定要用如下方法():
- 使用这些api:push() , pop() , shift() unshift() splice() sort() reverse()
- Vue.set() 或vm.$set()
特别注意:Vue.set() 和vm.$set() 不能给vm或vm的根数据对象添加属性!!!
<div id="root">
<h1>学生信息</h1>
<button @click="student.age++">年龄+1岁</button>
<button @click="addSex">添加性别属性,默认值:男</button>
<button @click="student.sex= '未知'">修改性别</button>
<button @click="addFriend">在列表首位添加一个朋友</button>
<button @click="updateFirstFriend">修改第一个朋友的名字为:张三</button>
<button @click="student.hobby.push('学习')">添加一个爱好</button>
<button @click="updateFirstHobby">修改第一个爱好为:开车</button>
<h3>姓名:{{student.name}}</h3>
<h3>年龄:{{student.age}}</h3>
<h3>爱好:</h3>
<h3 v-if="student.sex">性别:{{student.sex}}</h3>
<ul>
<li v-for="(h,index) in student.hobby" :key="index">
{{h}}
</li>
</ul>
<h3>朋友们:</h3>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} ---{{f.age}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el:'#root',
data:{
student:{
name:'tom',
age:18,
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:18},
{name:'xiao',age:89}
]
}
},
methods:{
addSex(){
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
},
addFriend(){
//操作数组,用到了被vue封装的方法,所有会解析模板,实现响应式
this.student.friends.unshift({name:'liu',age:11})
},
updateFirstFriend(){
this.student.friends[0].name = '张三'
},
updateFirstHobby(){
// this.student.hobby.splice(0,1,'开车')
Vue.set(this.student.hobby,0,'学习')
}
}
})
</script>
收集表单数据
<div id="root">
<!-- ctrl+F 高亮, -->
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="userInfo.account"><br><br>
密码:<input type="password" v-model="userInfo.password"><br><br>
性别:男<input type="radio" name="sex" value="male" v-model="userInfo.sex">
女<input type="radio" name="sex" value="female" v-model="userInfo.sex"><br><br>
年龄:<input type="number" v-model.number="userInfo.age"><br><br>
爱好:抽烟<input type="checkbox" v-model="userInfo.hobby" value="抽烟">
喝酒<input type="checkbox" v-model="userInfo.hobby" value="喝酒">
烫头<input type="checkbox" v-model="userInfo.hobby" value="烫头"><br><br>
所属校区:<select name="" id="" v-model="userInfo.city">
<option value="">请选择校区</option>
<option value="shanghai">上海</option>
<option value="beijing">北京</option>
<option value="chenzhen">深圳</option>
<option value="guangzhou">广州</option>
</select><br><br>
其他信息:<textarea v-model.lazy="userInfo.other"></textarea><br><br>
<input type="checkbox" v-model="userInfo.agree">阅读并同意 <a href="#">《用户协议》</a><br><br>
<button>提交</button>
</form>
</div>
<script>
new Vue({
el:'#root',
data:{
userInfo:{
account:'',
password:'',
sex:'',
age:'',
hobby:[],
city:'',
other:'',
agree:''
}
},
methods:{
demo(){
console.log(JSON.stringify(this.userInfo))
}
}
})
</script>
总结
收集表单数据:
若:
若: 则v-model 受经济的是value值,且要给标签配置value
若:
- 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选, 是布尔值)
- 配置input的value属性:
- v-model的初始值是非数组,那么收集的就是checked
- v-model的初始值是数组,那么收集的就是value组成的数组
备注: v-model 的三个修饰符:
- lazy:失去焦点再收集数据
- number:输入字符串转为有效的数字
- trim:输入首尾空格过滤
过滤器
<div id="root">
<h2>显示格式化后的标签</h2>
<!-- 计算属性实现 -->
<h3>现在的时间是:{{fmtTime}}</h3>
<!-- methods实现 -->
<h3>现在的时间是:{{getFmtTime()}}</h3>
<!-- 过滤器实现 -->
<h3>现在的时间是:{{time | timeFormater}}</h3>
<!-- 需求只要年月日 -->
<!-- 过滤器,第一个参数永远是time , 不管过滤函数有没有括号 -->
<h4>现在的时间是:{{time | timeFormater('YYYY_MM_DD')}}</h4>
<!-- 在过滤的基础上继续过滤 -->
<h4>现在的时间是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}</h4>
</div>
<script>
// 全局过滤器,过滤器可以用于v-bind与插值语法
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
new Vue({
el:'#root',
data:{
time:1621561377603
},
computed:{
fmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
}
},
methods:{
getFmtTime(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss')
}
},
filters:{
//优秀的一点,,形参默认值!!! 这个为局部过滤器
timeFormater:function(value,str='YYYY-MM-DD HH:mm:ss'){
return dayjs(value).format(str)
}
}
})
</script>
总结:
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适合一些简单的逻辑处理)
语法:
- 注册过滤器:Vue。filter(name,callback) 或 new Vue{(filters:{})}
- 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = ‘xxx | 过滤器名’
备注:
-
过滤器也 可以接收额外参数,多个过滤器也可以串联
-
并没有改变原来的数据,是产生新的对应的数据
现在的时间是:{{time | timeFormater('YYYY_MM_DD')}}
现在的时间是:{{time | timeFormater('YYYY_MM_DD') | mySlice}}
### 总结:
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适合一些简单的逻辑处理)
语法:
1. 注册过滤器:Vue。filter(name,callback) 或 new Vue{(filters:{})}
2. 使用过滤器:{{xxx | 过滤器名}} 或 v-bind:属性 = 'xxx | 过滤器名'
备注:
1. 过滤器也 可以接收额外参数,多个过滤器也可以串联
2. 并没有改变原来的数据,是产生新的对应的数据