修饰符
修饰符是由 . 点 开头的指令后缀
事件修饰符
.prevent
阻止超链接默认行为
.stop
阻止事件传播
.capture
添加事件监听器时使用事件捕获模式,即内部元素触发的时间先在此处理器,然后再交由内部元素进行处理
.self
只当在 event.target 是当前元素自身时触发处理函数,即事件不是从内部元素触发的
表单修饰符
v-model.trim
去空格
v-model.number
转数值类型
v-model.lazy
在“change”时而非“input”时更新,即点击确定后再更新,不是即时更新
键盘事件
@keyup
修饰符事例
<div id="app">
<div class="c1">
<a :href="url" @click.prevent="onConfirm">百度</a><!--阻止a标签默认跳转事件-->
<p>{{username}}</p>
<form :action="url" @submit.prevent="onSubmit"><!--阻止表单默认提交事件-->
<input type="text" v-model.trim="password"><!--去掉密码前后空格-->
<input type="text" v-model.lazy="username"><!--懒-->
<button type="submit">确定</button>
</form>
</div>
<div class="c2">
<ul @click="onClickUl">
<li @click.stop="onClickLiOne">元素一</li><!--阻止事件传播-->
</ul>
</div>
<div class="c3">
<input type="text" placeholder="请输入数量" v-model.number="num">
<button @click="getInputValue">获取值</button>
</div>
</div>
<script src="../lib/vue.global.js"></script>
<script>
const { createApp } = Vue
createApp({
data() {
return {
message: 'vue修饰符',
url: 'http://www.baidu.com',
num:'',
password:'',
username:''
}
},
methods: {
onConfirm() {
// event.preventDefault() //阻止默认行为
alert('helloworld')
},
onSubmit() {
alert('submit提交事件')
},
onClickLiOne(){
alert('click li one')
// event.stopPropagation()
},
onClickUl(){
alert('click ul ')
},
getInputValue(){
console.log('num: ',this.num, typeof this.num);
}
},
}).mount('#app')
</script>
计算属性computed
定义成方法形式使用,本质上是一个属性
一定有返回值,返回值是计算属性值
依赖于响应式属性, 当响应式属性值变化自动重新计算
计算属性特点: 缓存数据
计算属性会缓存计算的结果,获取计算属性值先从缓存中获取,只有依赖的响应式属性变化时才重新计算
默认只读,若要可写,写成对象形式,设置getter setter方法
computed:{ isBooks(){ //默认只读值 isBooks()是computed方法中定义的计算属性
return value // 必须要有'return'值
//计算属性方法体中,用到响应式属性,只要数据变化,计算属性自动重新执行
} }
<div id="app">
<h2>作者{{author.name}}是否出版本书籍?</h2>
<p>已出版本书籍 显示yes否则显示no</p>
<h3>出版本书籍情况: <span>{{ isBooks }}</span></h3> //isBooks是computed中的计算属性
<h3>{{fullName}}</h3>
<button @click="updateIsBooks">确定</button>
</div>
<script src="../lib/vue.global.js"></script>
<script>
const { createApp } = Vue
const app =createApp({
data() {
return {
author: {
name: 'John Doe',
books: ['javascript高级编程', 'css入门', 'vue3高级编程'],
},
firstName:'Doe'
}
},
methods: {
updateIsBooks(){
this.isBooks = 'no'
this.fullName = '张三'
console.log(this.isBooks);
}
},
computed:{
isBooks(){
console.log('计算属性值');
return this.author.books.length>0?'Yes':'No'
},
// 定义成geter seter形式
fullName:{
get(){
console.log('get >>>');
return this.firstName //获取依赖的属性值
},
set(value){
console.log('value ',value)
this.firstName = value //改变依赖的属性的值
}
}
}
}).mount('#app')
</script>
使用computed完成总价的计算
<div id="app">
<table class="y-table">
<tr>
<th>序号</th>
<th>名称</th>
<th>价格</th>
<th>数量</th>
<th>总价</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in list">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.price}}</td>
<td>
<input type="text" value="-" />
<input type="text" v-model="item.num" />
<input type="text" value="+" />
</td>
<td>{{ item.price * item.num }}</td>
<td><a href="javascript:void(0)">删除</a></td>
</tr>
</table>
<h2>商品总价:{{total}}</h2> <!--total是计算属性-->
<!-- Form 表单 -->
<form class="y-form">
<div class="y-form-item">
<label for="id">序号:</label>
<input type="text" class="y-input-parmary" />
</div>
<div class="y-form-item">
<label for="name">书名:</label>
<input type="text" class="y-input-parmary" />
</div>
<div class="y-form-item">
<label for="price">价格:</label>
<input type="text" class="y-input-parmary" />
</div>
<div class="y-form-item">
<label for="num">数量:</label>
<input type="text" class="y-input-parmary" />
</div>
<div class="y-form-item">
<a href="#" class="y-btn-primary">添加</a>
</div>
</form>
</div>
<script src="../lib/vue.global.js"></script>
<script>
const { createApp } = Vue
const vm = createApp({
data() {
return {
list: [
{ id: 1001, name: 'vue高级编程', price: 88.88, num: 2 },
{ id: 1002, name: 'react高级编程', price: 98.48, num: 1 },
{ id: 1003, name: 'js高级编程', price: 68.08, num: 3 },
],
}
},
methods: {},
computed: {
total() {
let totalPrice = this.list.reduce((previus, current) => previus + current.price * current.num,0)
return totalPrice.toFixed(2)
},
},
}).mount('#app')
</script>
侦听属性 watch
侦听Vue 实例上data中的数据和一些非DOM元素改变
可以获取数据改变前的值和改变后的值
const { createApp } = Vue
const app = createApp({
data() {
return {
username: 'jack',
}
},
//侦听器 响应式属性
watch: {
username(newValue, oldValue) { //改变前的值,改变后的值
console.log('newValue ', newValue, ' oldValue ', oldValue)
},
},
}).mount('#app')
侦听属性搜索事例
<div id="app">
<input type="text" placeholder="请输入搜索内容" v-model.lazy="keyword" />
</div>
<script src="../lib/vue.global.js"></script>
<script src="../lib/axios.min.js"></script>
<script>
const { createApp } = Vue
const app = createApp({
data() {
return {
keyword: '',
}
},
//侦听器 响应式属性
watch: {
keyword(newValue, oldValue) {
axios({
method: 'get',
url: 'https://api.yuguoxy.com/api/shop/search',
params: {
keyword:newValue,
},
}).then(res => {
console.log(res.data)
})
},
},
}).mount('#app')
</script>
immediate 选项
默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项。
immediate:true 立即侦听
停止观察
watch函数接收两个参数,然后函数执行以后,会返回一个WatchStopHandle(停止观察的处理器)对象
const stopWatchCallback = watch(
// 第一个参数是要监听的数据
firstValue,
// 第二个参数是监听的处理函数
// 处理函数的参数:第一个参数是当前值,第二个参数为更新前的值
function(newValue, oldValue) {
second.list = Array(5).fill().map((_, i) => {
return {
id: newValue + i,
name: newValue + '课程' + i,
value: newValue + i
}
})
}
)
stopWatchCallback()//调用执行
deep 选项
如果侦听对象的属性,就要使用deep深度侦听才能获取到对象的属性,下方data的keyword是单个字符串就不需要deep,user是对象就需要。
<div id="app">
<input type="text" placeholder="请输入搜索内容" v-model.lazy="keyword" />
</div>
<script src="../lib/vue.global.js"></script>
<script src="../lib/axios.min.js"></script>
<script>
const { createApp } = Vue
const app = createApp({
data() {
return {
keyword: '衣',
user: {
name: 'jack',
age: 18,
},
}
},
//侦听器 响应式属性
watch: {
keyword: {
handler(newValue) {
axios({
method: 'get',
url: 'https://api.yuguoxy.com/api/shop/search',
params: {
keyword: newValue,
},
}).then(res => {
console.log(res.data)
})
},
immediate: false, // 立刻侦听 为true是立即监听
},
// 侦听对象属性值变化,开启深度侦听
user: {
handler(newValue) {
console.log('newValue >>>> ',newValue)
},
deep:true // 深度侦听
},
// 侦听user对象age属性
'user.age':{
handler(newValue){
console.log('user.age >>> ',newValue);
}
}
},
}).mount('#app')
computed 和 watch区别[面试]
watch可以取代computed,watch更多是响应数据,但是和computed相比性能会降低,并且watch不会有返回结构,需要单独定义变量来进行缓存。
computed不能取代watch,watch是观察一个值的变化,再去执行一个业务,这业务可以是异步甚至没有返回值
生命周期
vue实例从开始创建->数据初始化->挂载->渲染->更新->渲染->销毁 所经过的一系列过程统称为生命周期,强调的是一个时间段。简单说就是创建->挂载->更新->销毁四个阶段,每个阶段都有之前和之后,共八个生命周期。
生命周期是一个过程,是指虚拟dom的生命周期,更新生命周期只有当一个值绑定到虚拟dom,以后的更新,才会触发。created赋值不会二次渲染,mounted赋值会二次渲染
生命周期函数:是由 vue 框架提供的内置函数,会伴随着生命周期,自动按次序执行
注: 生命周期强调的是时间段,生命周期函数强调的是时间点
生命周期函数的分类
1.创建期间的生命周期钩子函数
beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好
**created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板。赋值不会造成二次渲染。
2.挂载期间的生命周期钩子函数
beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
**mounted[操作vue生命周期节点]:此时,已经将编译好的模板,挂载到了页面指定的容器中显示,操作节点,会造成二次渲染,但可以获取到dom元素。
创建和挂载生命周期只会在组件初始化的时候执行一次,后边的所有操作都是更新生命周期
3.更新期间的生命周期函数
beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
updated:更新生命周期只有当一个值绑定到虚拟dom,以后的更新,才会触发。实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了
4.销毁期间的生命周期函数
beforeUnmount:实例销毁之前调用。在这一步,实例仍然完全可用。这个生命周期可以获取虚拟dom所以常用
Unmounted:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。卸载生命周期常用于事件解绑、定时器销毁、大数据销毁等业务
const { createApp } = Vue
const app = createApp({
data() {
return {
message: '生命周期',
}
},
methods: {
test() {
console.log('test')
},
},
//beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
beforeCreate() {
console.log('beforeCreate :', this.message)
},
//实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
created() {
console.log('created :', this.message)
},
//此时已经完成了模板的编译,但是还没有挂载到页面中
beforeMount() {
console.log('beforeMount :',)
},
//此时,已经将编译好的模板,挂载到了页面指定的容器中显示
mounted() {
console.log('mounted :', document.querySelector('h2'))
},
//状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
beforeUpdate() {
console.log('beforeUpdate >>>>');
},
//实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
updated() {
console.log('updated >>>>');
},
//实例销毁之前调用。在这一步,实例仍然完全可用。
beforeUnmount(){
console.log('beforeUnmount >>>>');
},
//实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
unmounted(){
console.log('unmounted >>>>');
}
}).mount('#app')
生命周期事例
<div id="app">
<table class="y-table">
<tr>
<th>序号</th>
<th>名称</th>
<th>图片</th>
<th>价格</th>
<th>分类</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in list">
<td>{{item.id}}</td>
<td>{{item.shop}}</td>
<td><img :src="item.picture" alt="" /></td>
<td>¥{{item.price}}</td>
<td>{{ item.categoryname }}</td>
<td><a href="javascript:void(0)">删除</a></td>
</tr>
</table>
</div>
<script src="../lib/vue.global.js"></script>
<script src="../lib/axios.min.js"></script>
<script>
const { createApp } = Vue
const app = createApp({
data() {
return {
list: [], //商品数组
}
},
methods: {
/**
* 获取商品列表
*/
async getProductList() {
let res = await axios({
method: 'get',
url: 'https://api.yuguoxy.com/api/shop/list',
})
const { resultCode, resultInfo } = res.data
if (resultCode == 1) {
let list = resultInfo.list
this.list = list
}
},
},
created() {
this.getProductList()
},
}).mount('#app')
</script>
.y-table {
text-align: center;
margin: 100px auto;
}
.y-table img {
width: 100px;
height: 100px;
}