# Vue第一天
# 1. vue初始/创建vue实例对象
让vue工作, 就必须创建一个vue实例 且要传入一个配置对象
box容器的代码依然符合html规范 只是混入了特殊vue语法
box容器里的代码称为: Vue模板
vue实例和容器是一一对应的
{xxx} 中要写js表达式 且xxx可自动读取data中所有属性
一旦data中数据改变 页面用到的数据也会自动更新
<div class="box">
<!-- 3. {{对象名}} 为插件表达式 插入vue实例数据 -->
<h1>Hello, {{name.toUpperCase()}} {{age}}</h1>
</div>
// 1. 设置为false 以阻止vue在启动时生成生产提示
Vue.config.productionTip = false
// 最好在配置调整好后 在继续写Vue代码
// 2. 创建vue实例 {} 是配置对象
new Vue({
el: '.box', // el是指定当前vue实例为哪个容器服务 值为css选择器
data: { // data是存储数据的 为指定容器使用
name: '小城故事xc',
age: 18
}
})
# 2. vue的模板/指令语法
# Vue模板语法有2大类:
# 1. 插值语法
- 功能: 用于解析标签体内容
- 写法: {xxx} 中要写js表达式 且xxx可自动读取data中所有属性
- 多级对象这样写: {all.name}
# 2. 指令语法
- 功能: 用于解析标签(包括: 标签属性、内容、绑定事件)
- 举例: <a v-bind:href="xx" 或简写为 :href="xx">
- 且可以直接读取到data中所有属性
- vue中有很多的指令, 且形式都是: v-???
<div class="box">
<h1>插值语法</h1>
<h2>你好, {{name}}</h2>
<hr>
<h1>指令语法</h1>
<a v-bind:href="url" v-bind:x="age">百度搜索</a>
<!-- 简写指令 -->
<a :href="url" :x="age">{{all.name}}</a>
</div>
new Vue({
el: '.box',
data: {
name: 'jack',
url: 'https://baidu.com',
age: 18,
all: {
name: '小城故事'
}
}
})
# 3. vue的单项/双项数据绑定
- Vue有2中数据绑定方式:
- 单选数据绑定(v-bind): 数据只能从data流向页面
- 双选数据绑定(v-model): 数据不仅能从data流向页面, 还可从页面流向data
- 双向绑定一般应用在表单类元素上(input、select...)
- v-model:value 可简写为v-model 因为默认收集的就是value值
<div class="box">
<!-- 普通写法 -->
单项数据绑定: <input type="text" v-bind:value="name"><br>
双项数据绑定: <input type="text" v-model:value="name"><br>
<!-- 简写 -->
单项数据绑定: <input type="text" :value="name"><br>
双项数据绑定: <input type="text" v-model="name">
<!-- 下面代码是错误的 v-model只能应用在表单元素上(输入类元素) -->
<!-- <h2 v-model:x="name">你好</h2> -->
</div>
new Vue({
el: '.box',
data: {
name: '小城故事'
}
})
# 4. el和data的两种写法
# 1. el有两种写法:
- new Vue时候配置el属性
- 先创建vue实例, 再通过vm.$mount('#root')指定el的值
# 2. data有两种写法: 1. 对象式 2.函数式
- 目前哪种写法都可以, 但组件化必须使用函数式, 否则报错
- 原则: 由Vue管理的函数, 一定不要写箭头函数, 写了this就不是vue实例了
let v = new Vue({
// el: '.box',
data:function () { // data函数式写法
console.log(this) // 指向vue实例对象
return {
name: '小城故事'
}
}
})
// 01. el的两种写法
// 1. 第一种写法: el: '.box'
// 2. 第二种写法: $mount
console.log(v)
// 配合定时器使用
setTimeout(() => {
v.$mount('.box')
}, 500)
// 02. data的两种写法
// 1. 第一种写法: 对象式 data: {}
// 2. 第二种写法: 函数式 组件化会用到
# 5. Vue的MVVM的模型
- M(模型): data中的数据
- V(视图): 模板代码
- VM(视图模型): Vue实例
- data中所有属性, 最后都出现在vm身上
- vm身上所有属性 及vue原型上所有属性, 在vue模板中都可以直接使用
<div class="box">
<h1>你好, {{name}}</h1>
<h4>测试一下: {{1+1}}</h4>
<h4>测试一下: {{$options}}</h4>
<h4>测试一下: {{$emit}}</h4>
</div>
let vm = new Vue({
el: '.box',
data: {
name: '小城故事'
}
})
console.log(vm)
# 6. Object.defineProperty数据代理方法
- defineProperty(对象名, '添加的值') 可以为对象添加属性值
- 但添加的对象不能被遍历
- 数据代理: 当读取obj的age属性时, get函数会被调用, 且返回值是age的值
- 数据劫持: 当修改obj的age属性时, set函数会被调用, 且会收到修改的具体指
let num = 18
let obj = {
name: '小城'
}
Object.defineProperty(obj, 'age', {
// value: 18,
// enumerable: true, // 控制属性是否可以枚举 默认false
// writable: true, // 控制属性是否可以被修改 默认false
// configurable: true, // 控制属性是否可以被删除 默认false
// 数据代理 当读取obj的age属性时, get函数会被调用, 且返回值是age的值
get() {
console.log('你读取了age属性')
return num
},
// 数据劫持 当修改obj的age属性时, set函数会被调用, 且会收到修改的具体指
set(value) {
console.log('你修改了age属性, 且值为', value)
return num = value
}
})
console.log(obj)
console.log(Object.keys(obj))
# 7. 理解数据代理
- 数据代理: 通过一个对象代理对另一个对象中属性的操作(读/写)
- 可通过obj1访问和修改obj的属性
let obj = {x: 10}
let obj1 = {y: 20}
Object.defineProperty(obj1, 'x', {
get() {
return obj.x
},
set(value) {
obj.x = value
}
})
console.log(obj)
console.log(obj1)
# 8. vue中的数据代理
- Vue中的数据代理: 通过vm对象来代理data对象属性的操作(读/写)
- Vue数据代理的好处: 更加方便的操作data中的数据
- 基本原理:
- 通过Object.defineProperty()把data对象中所有属性添加到vm上
- 为每个添加到vm上的属性, 都指定一个getter/setter方法
- 在getter/setter内部去操作(读/写)data中对应的属性
- vm中的data就是Vue实例对象中的_data属性
<div class="box">
<h1>你好, {{name}}</h1>
</div>
let vm = new Vue({
el: '.box',
data: {
name: '小城故事'
}
})
console.log(vm)
# 9. vue的事件绑定
- 使用v-on:xxx 或 @xxx 绑定事件, 其中xxx是事件名
- 事件的回调需要配置在methods对象中, 最终会在vm上
- methods中配置的函数, 不要用箭头函数, 否则this就不是vm
- methods中配置的函数, 都是被Vue所管理的函数, this指向是vm或组件实例对象
- @click='show' 和 @click='show($event)' 作用一致, 但后者可以传参
<div class="box">
<h1>你好, {{name}}</h1>
<button v-on:click="show">点击我啊</button>
<!-- 简写 -->
<button @click="show">点击我啊 (不带传参)</button>
<button @click="show1($event, 666)">点击我啊 (带传参)</button>
</div>
el: '.box',
data: {
name: '小城故事'
},
methods: {
show(e) {
console.log(e.target)
console.log(this) // 指向vm实例对象
alert('你好')
},
show1(event, number) {
console.log(event, number)
alert(`你好, ${number}`)
}
}
})
# 10. vue的事件修饰符
<div class="box">
<h3>你好, {{name}}</h3>
<!-- 1. 阻止事件默认行为(常用) -->
<a href="https://baidu.com" @click.prevent="show">点我提示信息</a>
<!-- 小技巧: 修饰符可以连续写入: 阻止默认行为和阻止冒泡 -->
<a href="https://baidu.com" @click.prevent.stop="show">修饰符可以连续写入</a>
<!-- 2. 阻止事件冒泡(常用) -->
<div class="demo" @click="show">
<button @click.stop="show">阻止事件冒泡</button>
</div>
<!-- 3. 事件只触发一次(常用) -->
<button @click.once="show">点我只触发一次</button>
<!-- 4. 使用事件的捕获模式 -->
<div class="demo1" @click.capture="show1(1)">
使用事件的捕获模式
<div class="demo2" @click="show1(2)">
使用事件的捕获模式
</div>
</div>
<!-- 5. 只有e.target是当前操作的元素时才触发事件 -->
<div class="demo" @click.self="show">
<button @click="show">e.target阻止事件冒泡</button>
</div>
<!-- 6. 事件的默认行为立即执行, 无需等待事件回调完成 -->
<ul @wheel.passive="show2">
<li>1</li>
<li>2</li>
</ul>
</div>
new Vue({
el: '.box',
data: {
name: '小城故事'
},
methods: {
show(e) {
// e.preventDefault() vue里这样写: prevent
// e.stopPropagation() vue里这样写: stop
alert('你好')
},
show1(msg) {
console.log(msg)
},
show2() {
for (let i = 0; i <= 100000; i++) {
console.log(1)
}
console.log('累坏了')
}
}
})
# 11. vue的键盘事件
- Vue中常用的按键别名: enter、delete、esc、space、tab、up、down、left、right
- Vue未提供别名按键, 可使用按键原始的key值去绑定, 但注意短横线命名(caps-lock)
- CapsLock是个特殊事件, 要写成caps-lock才行
- 系统修饰键(用法特殊): ctrl、alt、shift、meta
- 配合keyup使用: 按下修饰键的同时, 按下其他键, 事件才会触发
- 配合keydown使用: 正常触发事件
- 可定制按键别名: Vue.config.keyCodes.自定义键名 = 键码
- 使用keyCode指定具体按键(不推荐)
<div class="box">
<h2>你好, {{name}}</h2>
<input type="text" placeholder="按下回车提示" @keyup.enter="show">
<!-- Ctrl虽然可配合其他键使用,但如果只能Ctrl+Y才能触发后面得.Y -->
<input type="text" placeholder="按下回车提示" @keyup.ctrl.y="show">
</div>
new Vue({
el: '.box',
data: {
name: '小城'
},
methods: {
show(e) {
// if (e.key !== 'Enter') return
console.log(e.target.value)
}
}
})
# 12. 姓名案例-插值语法实现
<div class="box">
姓: <input type="text" v-model="name"> <br><br>
名: <input type="text" v-model="names"> <br><br>
全名: <span>{{name.slice(0, 3)}} - {{names}}</span>
</div>
new Vue({
el: '.box',
data: {
name: '张',
names: '三'
}
})
# 13. 姓名案例-methods属性实现
- data数据发生变化, vue模板会重新解析一遍
- vue模板里如果调用函数了, 函数也会被插值语法调用
<div class="box">
姓: <input type="text" v-model="name"> <br><br>
名: <input type="text" v-model="names"> <br><br>
全名: <span>{{fn()}}</span>
</div>
new Vue({
el: '.box',
data: {
name: '张',
names: '三'
},
methods: {
fn() {
console.log('fn函数被调用了')
return this.name + '-' + this.names
}
}
})
# 14. 姓名案例-计算属性实现
- 定义: 要用的属性不存在, 要通过已有属性计算得来
- 原理: 底层借助Object.defineProperty方法提供getter/setter
- get函数什么时候执行? (1) 初次读取时会执行一次 (2) 当依赖的数据发生改变会被再次调用
- 优势: 与methods实现相比: 内部有缓存机制, 效率更高, 调试方便
- 计算属性最终会出现在vm上, 直接读取使用即可
- 如果计算属性要被修改, 那必须要set函数去响应修改, 且set中要引起计算时依赖的数据发生改变
<div class="box">
姓: <input type="text" v-model="name"> <br><br>
名: <input type="text" v-model="names"> <br><br>
全名: <span>{{fullname}}</span> <br><br>
全名: <span>{{fullname}}</span> <br><br>
全名: <span>{{fullname}}</span>
</div>
let vm = new Vue({
el: '.box',
data: {
name: '张',
names: '三'
},
computed: {
fullname: {
// get作用: 当读取fullname时, get会被调用, 且返回值作为fullname的值
get() {
console.log('get被调用了')
console.log(this) // 指向vm实例 vue把get的this指向了vm
return this.name + '-' + this.names
},
// set什么时候调用: 当fullname被修改时调用
set(value) {
console.log(value)
let arr = value.split('-')
this.name = arr[0]
this.names = arr[1]
}
}
}
})
console.log(vm)
# 15. 姓名案例-计算属性简写实现
只有考虑读取, 不考虑修改才能用简写方式
<div class="box">
姓: <input type="text" v-model="name"> <br><br>
名: <input type="text" v-model="names"> <br><br>
全名: <span>{{fullname}}</span>
</div>
let vm = new Vue({
el: '.box',
data: {
name: '张',
names: '三'
},
computed: {
// 1. 简写
fullname() {
console.log('get被调用了')
return this.name + '-' + this.names
}
// 2. 完整写法
// fullname: {
// get() {
// console.log('get被调用了')
// return this.name + '-' + this.names
// }
// }
}
})