【Vue】一
Vue简介
el和data的两种写法
const v = new Vue({ el: '#root', data: { name: '123' } })
动态指定el容器
console.log(v) setTimeout(()=>{ v.$mount('#root') },1000)
函数式返回data
data: function() { return { name: '123' } }
而不能写成箭头函数,因为箭头函数没有this,下面输出为window而不是vue
data:()=> { console.log(this) return { name: '123' } }
在对象中写明方法也可以简写为
data() { console.log(this) return { name: '123' } }
MVVM模型
M:模型(Model):Data中的数据
V:视图(View):模板代码
VM:视图模型(ViewModel):Vue实例
数据代理
Object.defineProperty方法(对象,新增属性,value)
let number = 18 let person = { name: 'hikaru', sex: 'w', // age: 30 } Object.defineProperty(person, "age", { value: number, enumerable: true, //设置新增属性可以枚举,默认为false writable: true, //设置新增属性可以被修改,默认为false configurable: true //设置新增属性可以被删除,默认为false }) // 两种遍历方法 for (let key in person) { console.log(person[key]) } console.log(Object.keys(person)) console.log(person)
get和set方法
Object.defineProperty(person, "age", { // value: number, enumerable: true, //设置新增属性可以枚举,默认为false // writable: true, //设置新增属性可以被修改,默认为false // configurable: true, //设置新增属性可以被删除,默认为false get() { return number }, set(value) { console.log(value) } })
get在当age被读取时,get函数(getter)就会被调用,且返回值就是age的值
set在当age被修改时,set函数(setter)就会被调用,且参数就是被修改的age值
get set方法与writable、configurable属性重复不能一起写
数据代理实现
通过一个对象实现对另一个对象的读写操作
Vue.config.productionTip = false let obj1 = {x:100} let obj2 = {y:200} Object.defineProperty(obj2, 'x', { get() { return obj1.x }, set(value) { obj1.x = value } })
Vue中的数据代理:通过vm对象来代理data中的数据
vm(vue实体)将model中的data赋值给vm中的_data
数据代理: 将_data中所有的属性通过Object.defineProperty添加到vm中。
vm的data调用getter、setter方法时就会获取修改model中的data。
事件处理 v-on:xxx / @xxx
<div id="root"> <button v-on:click="getInfo1">Info1</button><br/> <button @click="getInfo2($event, 66)">Info2</button><br/> <a href="https://www.baidu.com" @click="changeTarget">baidu</a><br/> </div>
<script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: "#root", methods: { getInfo1() { alert('info1') }, getInfo2(event, number) { console.log(number) }, changeTarget(event) { alert(event.target.href) event.target.href += '/s?wd=vue' } }, }) </script>
只有data中的数据会被数据劫持代理,如果把method加入data也会被数据代理
Vue常用事件修饰符
1 prevent 阻止默认事件
js写法
new Vue({ el: "#root", methods: { getInfo1() { alert('info1') }, getInfo2(event, number) { console.log(number) }, changeTarget(e) { alert(e.target.href) e.preventDefault(); } }, })
Vue写法:@click.prevent
<a href="https://www.baidu.com" @click.prevent="changeTarget">baidu</a><br/>
2 stop 阻止事件向上级冒泡
3 once 事件只触发一次
4 capture 使用事件的捕获模式
5 self 只有event.target是当前操作的元素时才触发事件
<div id="root" @click.prevent.self="getInfo"> <button @click.prevent="getInfo">getInfo</button> </div>
冒泡到root的div时target仍是按钮
<button>getInfo</button>
6 passive 事件的默认行为立即执行,无需等待事件回调执行完毕
键盘事件
@keyup 在按键抬起的时候触发事件
@keydown 在按键按下的时候触发事件
常用按键别名
回车 Enter
删除 Delete
退出 Esc
空格 Spacce
换行 tab 需要配合keydown使用
上 up
下 down
左 left
右 right
<div id="root"> <input type="text" placeholder="输入字符回车后提示" @keyup.enter="getInfo"> </div>
<script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: "#root", methods: { getInfo(e) { console.log(e.key + ', ' + e.keyCode) } } }) </script>
e.key + ', ' + e.keyCode 获取键盘输入字符和字符编码
如回车 Enter 13
计算属性
1 使用插值语法实现
<div id="root"> 姓:<input type="text" v-model="firstName" ><br/> 名:<input type="text" v-model="lastName"><br/> 姓名:{{firstName + lastName}} </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: "#root", data: { firstName: '张', lastName: '三' } }) </script>
2 使用methods实现
<div id="root"> 姓:<input type="text" v-model="firstName" ><br/> 名:<input type="text" v-model="lastName"><br/> 姓名:{{getFullName()}} </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: "#root", data: { firstName: '张', lastName: '三' }, methods: { getFullName() { return this.firstName.slice(0,3) + '-' + this.lastName; } } }) </script>
使用有返回值的方法时必须加括号
3 计算属性 利用已经有的属性计算生成新属性
computed: { fullName: { get() { return this.firstName.slice(0,3) + '-' + this.lastName; }, set() { } } }
底层使用的是Object.defineProperty,方法get在被计算的属性被修改、计算的属性读取时被调用
只有get方法的计算属性的简写形式
computed: { fullName: function(){ return this.firstName.slice(0,3) + '-' + this.lastName; } }
监视属性
两种监视方法
①通过Vue实例化时的watch属性
watch: { firstName: { immediate: true, handler(newValue, oldValue) { console.log(newValue + '=>' + oldValue) } } }
immediate表示在被监视属性初始化时就调用handler
handler方法在被监视属性被修改时就会被调用
②通过vm
vm.$watch('lastName', { immediate: true, handler(newValue, oldValue) { console.log(newValue + oldValue) } })
''为正常写法,不加引号是简写
在只有handler时的简写形式
watch: { firstName(newValue, oldValue) { console.log(newValue + oldValue) } } }) vm.$watch('lastName', function(newValue, oldValue){ console.log(newValue + oldValue) })
深度监视
watch: { firstName: { immediate: true, deep: true, handler(newValue, oldValue) { console.log(newValue + '=>' + oldValue) } } }
深度监视在数据有多层结构时会监视所有的层结构数据,默认为false
与计算属性的比较 需求:延迟显示
watch: { firstName(val) { setTimeout(()=>{ this.fullName = val + this.lastName },1000 ) }, lastName(val) { setTimeout(()=>{ this.fullName = this.firstName + val },1000 ) }
computer可以完成的功能,watch都能完成,反之则不然,如监视属性方便进行异步,而计算属性只能瞬时return
这里使用了箭头函数,但是函数中的this仍为vm,这是因为箭头函数没有自己的this,需要递归向上寻找this,而lastName为普通函数且其this为vm,故箭头函数中的this为vm
箭头函数与普通函数的使用原则
①被Vue管理的函数使用普通函数,这样this指向的是vm实例 或者 组件对象
②所有不被Vue管理的函数,使用箭头函数,这样this指向的是vm实例 或者 组件对象
如:定时器的回调函数、ajax的回调函数、Promise的回调函数等
class与stye的绑定 :class
<body> <div id="root"> <div class="basic" :class="classes" @click="changeMood"> </div> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { classes: 'normal' }, methods: { changeMood() { let choose = Math.floor(Math.random(2) * 3) let moods = ['normal', 'happy', 'sad'] this.classes = moods[choose] } } }) </script>
①字符串写法
②数组写法
new Vue({ el: '#root', data: { classArr: 'normal' }, methods: { changeMood() { let choose = Math.floor(Math.random(2) * 3) let moods = ['normal', 'happy', 'sad'] this.classArr = moods[choose] } } })
③对象写法
data: { classArr: 'normal', classObj: { happy: false, sad: true } },
条件渲染 v-if v-show
v-show=""中的表达式为真时,会为元素添加 style="display: none"
v-if 会直接让元素消失
列表渲染 v-for
遍历数组
<div id="root"> <h2>人员列表</h2> <ul v-for="(emp, index) in employeeList" :key="index"> <li>{{emp.name}}-{{emp.age}}</li> </ul> </div>
new Vue({ el: '#root', data: { employeeList:[ {id: '001', name: '张三', age: 18}, {id: '002', name: '李四', age: 28}, {id: '003', name: '王五', age: 19} ] }, methods: { } })
遍历对象
<div id="root"> <h2>人员列表</h2> <ul v-for="(val, key) in employeeList[0]"> <li>{{val}} - {{key}}</li> </ul> </div>
接收对象的两个值先是value然后再是key
key的工作原理 虚拟DOM对比算法
key设置的属性为遍历对象的唯一标识
代码:
<body> <div id="root"> <h2>人员列表</h2> <ul v-for="(emp, index) in employeeList" :key="index"> <li>{{index}} : {{emp.name}}-{{emp.age}} <input type="text"></li> </ul> <button @click="add">add</button> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { employeeList:[ {id: '001', name: '张三', age: 18}, {id: '002', name: '李四', age: 28}, {id: '003', name: '王五', age: 19} ] }, methods: { add() { const e = {id: '004', name: '老六', age: 30} this.employeeList.unshift(e) } } }) </script>
出现的问题:
原因:
虚拟DOM对比算法,即是在数据发生变化的时候,生成的虚拟DOM会和原来的虚拟DOM依据key值进行比较,如果相同则直接复用原来的DOM结构,否则会生成新的DOM结构
如上图中,key为0的两个DOM比较,发现文本不同但是输入框相同(虚拟DOM不会考虑文本框内的内容),因此会生成新文本“老刘-30”,然后复用原来的输入框。
解决方法
①使用数据中的id作为key值
<ul v-for="(emp, index) in employeeList" :key="emp.id"> <li>{{index}} : {{emp.name}}-{{emp.age}} <input type="text"></li> </ul>
②或者使用不改变原有index顺序的插入方法
methods: { add() { const e = {id: '004', name: '老六', age: 30} this.employeeList.push(e) } }
列表过滤
用watch实现
<body> <div id="root"> <h2>人员列表</h2> <input v-model="keyWord" placeholder="请输入信息"/> <ul v-for="(person, index) in filPersons" :key="index"> <li>{{person.name}}-{{person.age}}</li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { persons:[ {id: '001', name: '马冬梅', age: 18}, {id: '002', name: '周冬雨', age: 28}, {id: '003', name: '周杰伦', age: 19}, {id: '004', name: '温兆伦', age: 17} ], filPersons: [], keyWord: '' }, methods: { }, watch: { keyWord: { immediate: true, handler(val) { this.filPersons = this.persons.filter((p)=>{ return p.name.indexOf(val) !== -1; }) } } } }) </script>
使用计算属性
<body> <div id="root"> <h2>人员列表</h2> <input v-model="keyWord" placeholder="请输入信息"/> <ul v-for="(person, index) in filPersons" :key="index"> <li>{{person.name}}-{{person.age}}</li> </ul> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { persons:[ {id: '001', name: '马冬梅', age: 18}, {id: '002', name: '周冬雨', age: 28}, {id: '003', name: '周杰伦', age: 19}, {id: '004', name: '温兆伦', age: 17} ], keyWord: '' }, methods: { }, computed: { filPersons() { return this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !== -1; }) } } }) </script>
列表排序
computed: { filPersons() { const arr = this.persons.filter((p)=>{ return p.name.indexOf(this.keyWord) !== -1; }) if(this.sortType) { arr.sort((p1, p2) => { return this.sortType === 1 ? p1.age-p2.age : p2.age-p1.age }) } return arr } }
收集表单数据为JSON数据: JSON.stringify
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script type="text/javascript" src="./js/vue.js"> </script> <style> button { margin-left: 2%; } </style> </head> <body> <div id="root"> <form @submit.prevent="submit()"> <label for="userName">账号:</label> <input type="text" id="userName" v-model="userInfo.userName"/><br/><br/> <label for="password">密码:</label> <input type="password" id="password" v-model="userInfo.password"/><br/><br/> <label for="age">年龄:</label> <input type="number" id="age" v-model.number="userInfo.age"/><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="checkbox" value="learning" v-model="userInfo.hobby"> 打游戏<input type="checkbox" value="game" v-model="userInfo.hobby"> 吃饭<input type="checkbox" value="eating" v-model="userInfo.hobby"> <br/><br/> 所属校区 <select v-model="userInfo.school"> <option value="北京">北京</option> <option value="上海">上海</option> <option value="广州">广州</option> <option value="深圳">深圳</option> </select> <br/><br/> 其他信息 <textarea v-model="userInfo.otherText"> </textarea><br/><br/> <input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="#">《用户协议》</a> <br/><br/> <button type="submit">提交</button> </form> </div> </body> <script type="text/javascript"> Vue.config.productionTip = false const vm = new Vue({ el: '#root', data: { userInfo: { userName: '', passWord: '', age: '', sex: 'male', hobby: [], school: '', otherText: '', agree: true } }, methods: { submit() { console.log(JSON.stringify(this.userInfo)) } }, computed: { } }) </script> </html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步