事件及生命周期
学习内容
1、表单v-model
1、1变量取名命名问题
- 绑定输入框数据的时候,尽量和后端要求的数据保持一致
<!-- 定义挂载点 -->
<div id="app">
<!-- <p>账 号:<input type="text" v-model="name"></p>
<p>密 码:<input type="text" v-model="pass"></p> -->
<p>账 号:<input type="text" v-model="user.username"></p>
<p>密 码:<input type="text" v-model="user.password"></p>
<button @click="toReg">注册</button>
</div>
<script>
//实例化vue
new Vue({
//挂载点
el: "#app",
//data:model(数据模型)--页面所需的数据
data: {
//随便定义,后期需要处理成后端对应的数据格式
name: "",
pass: "",
//定义对象,key一定要和后端保持一致,方便后期使用
user: {
username: "",
password: ""
}
},
//methods:方法 需要使用的函数
methods: {
toReg() {
/*
/register
参数:
username:
password
*/
// $.ajax({
// url:"/register",
// data:{
// username:this.name,
// password:this.pass
// }
// })
console.log(this.user);
}
}
})
</script>
1、2 v-model数据绑定
- 单选框:对应radio,需要给input一个value,使用v-model去进行数据绑定
<div class="form-group row">
<label class="col-lg-1">性别</label>
<!-- 对于radio单选框,需要给input设置value属性,再使用v-model去绑定数据 -->
<div class="col-lg-11">
<label class="radio-inline"><input type="radio" name="sex" :value="0" v-model="reg.sex"> 男</label>
<label class="radio-inline"><input type="radio" name="sex" :value="1" v-model="reg.sex"> 女</label>
</div>
</div>
- 多选框:对于checkbox来说,初始值是数组,最后的结果就是数组,如果初始值不是数组,结果就是boolean
<div class="form-group row">
<label class="col-lg-1">爱好</label>
<!-- 对于checkbox多选框,初始值是数组,最后的结果就是数组,如果是其他,结果就是一个boolean -->
<div class="col-lg-11">
<label class="checkbox-inline"><input type="checkbox" :value="1" v-model="reg.hobby">唱歌</label>
<label class="checkbox-inline"><input type="checkbox" :value="2" v-model="reg.hobby">跳舞</label>
<label class="checkbox-inline"><input type="checkbox" :value="3" v-model="reg.hobby">看书</label>
<label class="checkbox-inline"><input type="checkbox" :value="4" v-model="reg.hobby">写代码</label>
</div>
</div>
- 下拉菜单
- 单选:对于下拉菜单,给select绑定v-model,option的内容给用户看,value才是我们想要取到
<div class="form-group row">
<label class="col-lg-1">职业</label>
<!-- 对于下拉列表框, 给select绑定v-model-->
<div class="col-lg-11">
<select class="form-control" v-model="reg.job">
<option value="">--请选择--</option>
<option :value="1">web工程师</option>
<option :value="2">java工程师</option>
<option :value="3">php工程师</option>
<option :value="4">软件测试</option>
<option :value="5">ui设计</option>
</select>
</div>
</div>
- 下拉菜单
- 多选:对应多选下拉,添加multiple属性,初始值给数组
<div class="form-group">
<label>零食</label>
<!-- 对于多选下拉列表框, 设置multiple属性-->
<select class="form-control" multiple v-model="reg.lingshi">
<option value="">--请选择--</option>
<option :value="1">乐事薯片</option>
<option :value="2">绝味鸭脖</option>
<option :value="3">卫龙辣条</option>
<option :value="4">蜜雪冰城</option>
<option :value="5">AD钙奶</option>
</select>
</div>
- 文本域
<div class="form-group">
<label>备注</label>
<textarea class="form-control" rows="3" v-model="reg.des"></textarea>
</div>
<div class="form-group row">
<label class="col-lg-1">同意协议</label>
<div class="col-lg-11">
<input type="checkbox" v-model="reg.isAgree">
</div>
</div>
<button type="button" class="btn btn-primary" :disabled="!reg.isAgree">注册</button>
<script>
//实例化vue
new Vue({
//挂载点
el: "#app",
//data:model(数据模型)--页面所需的数据
data: {
reg:{
name:"",
pass:"",
tel:"",
sex:0,
hobby:[],
job:"",
lingshi:[],
des:"",
isAgree:false
}
},
//methods:方法 需要使用的函数
methods: {}
})
</script>
1、3表单修饰符
- 修饰符就是起修饰作用,通过 . 来调用,都是加在指令的后面
- 注意点:修饰符可以连续调用,如:.self.once
.lazy
语法:指令 .lazy
作用:失去光标才去修改模型中的数据
<!-- .lazy 失去光标才去修改模型中的数据 -->
<input type="text" v-model.lazy="name"><br>
.number
语法:指令 .number
作用:将输入的内容自动转换为number类型,可以配合type="number"使用,约束用户的输入
<!-- .number 将输入的内容自动转换为number类型,可以配合type='number'使用,约束用户的输入 -->
<input type="text" v-model.number="num1"> +
<input type="text" v-model.number="num2"> =
<p>{{num1 + num2 }}</p>
.trim
语法:指令 .trim
作用:失去光标,自动去除前后空格
<!-- .trim : 失去光标的时候,自动去除前后空格 -->
<input type="text" v-model.trim="text">
<p>|+{{text}}+|</p>
<script>
//实例化vue
new Vue({
//挂载点
el:"#app",
//data:model(数据模型)--页面所需的数据
data:{
name:"",
num1:"",
num2:"",
text:""
},
//methods:方法 需要使用的函数
methods:{}
})
</script>
2、事件绑定v-on
2.1 事件绑定及传参
- 例
<!-- 定义挂载点 -->
<div id="app">
<!-- v-on:事件名 = ‘h函数’ 简写@ -->
<button @click="study()">明天自学</button>
<!-- ()可加可不加 -->
<button @click="study">明天自学</button>
<!-- 如果需要传参,必须要加() -->
<button @click="delItem(1)">删除某一项</button>
</div>
<script>
//实例化vue
new Vue({
//挂载点
el:"#app",
//data:model(数据模型)--页面所需的数据
data:{},
//methods:方法 需要使用的函数
methods:{
study(){
console.log("明天学习vue第三天");
},
delItem(n){
console.log("删除"+n+"项");
}
}
})
</script>
2.2 获取事件对象
- 获取事件对象 -event
<!-- 定义挂载点 -->
<div id="app">
<!-- 隐式传递事件对象,函数不加括号的情况下,第一个参数就是event事件对象 -->
<!-- <div @click="clickFun"></div> -->
<!-- 显示传递事件对象,加括号就必须传递event对象 -->
<div @click="clickFun($event,10,20)"></div>
</div>
<script>
//实例化vue
new Vue({
//挂载点
el:"#app",
//data:model(数据模型)--页面所需的数据
data:{},
//methods:方法 需要使用的函数
methods:{
clickFun(event,a,b){
console.log(event);
console.log(a,b);
}
}
})
</script>
2.3 阻止默认事件,阻止事件传播
- 阻止
<!-- 定义挂载点 -->
<div id="app">
<a @click="default1" href="https://www.520xgg.com/?01081720apc-105821611jq&sdclkid=ALf_15fGbSDlA6DN"><img src="https://img2.baidu.com/it/u=1258968720,105769531&fm=253&fmt=auto&app=120&f=JPEG?w=736&h=500" alt=""></a>
<div class="outer" @click="outer">
<div class="inner" @click="inner"></div>
</div>
</div>
<script>
//实例化vue
new Vue({
//挂载点
el:"#app",
//data:model(数据模型)--页面所需的数据
data:{},
//methods:方法 需要使用的函数
methods:{
default1(event){ //隐式传递,默认第一个参数就是事件对象
//阻止默认行为: event.preventDefault() / event.returnValue=false -- 原生js
console.log("阻止默认行为");
event.preventDefault();
},
outer(){
console.log("大盒子被点击了");
},
inner(event){
//阻止事件冒泡:event.stopPropagation() / event.cancelBubble=true -- 原生js
console.log("小盒子被点击了");
event.stopPropagation();
}
}
})
</script>
2.4 事件修饰符
- 事件后面 @事件名 . 修饰符
- 修饰符
.prevent 阻止事件默认行为
.stop 阻止事件冒泡
.self 只触发自己,任何其他的如冒泡都不能触发,只能自己触发自己
.once 只触发一次
.capture 事件捕获
- 案例
<!-- 定义挂载点 -->
<div id="app">
<!-- .prevent 阻止事件默认新闻 -->
<a href="http://www.baidu.com" @click.prevent="default1">百度</a>
<!-- .stop 阻止事件冒泡 -->
<div class="outer" @click="outer">
<div class="inner" @click.stop="inner"></div>
</div>
<!-- .self 只触发自己的事件 -->
<div class="box">
<button @click = 'isShow = true'>显示弹框</button>
<div class="content" v-show="isShow" @click.self="isShow=false">
<input type="text">
<button>确定</button>
<button>取消</button>
</div>
</div>
<!-- .once : 一次性事件 -->
<button @click.once="home">抽奖</button>
<!-- .capture:事件捕获(一般不用) -->
<div class="outer" @click.capture="outer">
<div class="inner" @click.capture="inner"></div>
</div>
</div>
<script>
//实例化vue
new Vue({
//挂载点
el:"#app",
//data:model(数据模型)--页面所需的数据
data:{
isShow:false
},
//methods:方法 需要使用的函数
methods:{
default1(){
console.log("点击了a,但是不想让他跳转");
},
outer(){
console.log("大盒子被点击了");
},
inner(){
console.log("小盒子被点击了");
},
home(){
console.log("10个");
}
}
})
</script>
2.5 键盘修饰符
- 键盘修饰符:@键盘事件名.修饰符=“函数”
除了按键名key之外,你可以利用keyCode码作为修饰符,但是不推荐keyCode码,因为不同的键盘keyCode可能不同 (vue3中移除了keyCode码)
.enter 回车
.left 左箭头
.right 右箭头
.up 上箭头
.down 下箭头
.space 空格
.delete 删除 (捕获删除和退格键)
.esc 退出
.tab 换行(必须配合keydown使用)
.shift
.alt
.ctrl
65
<input type="text" @keydown.65="enterFun" @keydown.space="spaceFun">
-->
3、$set的用法
(1) 一个json属性,如果是在data中声明了这个属性,vue会自动给它加上set和get方法,如果属性改变会引起页面的重新渲染
(2) 刚开始没有在data中定义height属性,height属性没有set和get,数据改变页面不会发生变化
- 说明
this.obj.age=19;
如上这种添加属性的方法无法实现响应式的数据变化,所以要添加响应式的数据不能这样写。
vue是响应式的数据变化,数据改变视图就会改变。
底层原理:因为每一个对象的属性本身都有get(取值)和set(赋值),
这样底层的数据劫持就会根据set方法的执行,发现变化就更新视图
我们在向对象添加属性的时候,如果用以上直接添加,这个属性是不会被vue响应式管理的,
因为没有使用对象的get(取值)和set(赋值)。必须用$set来添加,这样这个属性在底层会用到get set,
这样这个属性就会是响应式的。
以下两个方法其实是同一个方法
this.$set(对象,key,value)
Vue.set(对象,key,value)
总结:未来在给对象添加属性的时候,如果遇到新增属性或者数组元素,无论是对象或者数组都要
利用这个方法去添加(主要是对象)
vue对数组的一些方法进行了重新封装,因此这些数组的方法可以进行响应式变化:
push(),pop(),shift(),unshift(),sort(),reverse(),splice()
- 使用
<!-- 定义挂载点 -->
<div id="app">
<p>{{user}}</p>
<button @click="addAge">添加age</button>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<ul>
<li v-for="item in students" :key="item.id">
<p>今天吃什么:{{item.name}}</p>
<p>价格:{{item.price}}</p>
</li>
</ul>
<button @click="addPrice">添加价格</button>
</div>
<script>
new Vue({
el: "#app",
data: {
user: {
name: "迪丽热巴",
},
students: [
{ id: 1,name:"红烧牛肉面" },
{ id: 2,name:"烧烤" },
{ id: 3,name:"螺蛳粉" },
{ id: 4,name:"螺蛳粉" }]
},
methods: {
//1.修改名字
changeName() {
this.user.name = "古力娜扎"
},
//2.添加属性
addAge() {
/*如果在data声明了这个属性,vue会自动给他添加上set和get方法,通过set能监听到数据的改变,如果数据变了,会引起页面的重新渲染 -- vue3已经解决*/
// this.user.age = 18; 不会重新渲染,因为没有get和set
//解决办法
//1.Vue.set(target,key,value)
//Vue.set(this.user,"age",18);
//2.vue.$set(target,key,value) -- 推荐使用
// this.$set(this.user,"age",18);
//3.整体给user重新赋值
this.user = {
...this.user,
age: 20
}
console.log(this.user);
},
changeAge() {
this.user.age = 19;
},
addPrice(){
//问题:先没有在data中定义,没有set和get
this.students.forEach((value,index)=>{
this.$set(value,"price","7")
});
console.log(this.students);
}
}
})
</script>
4、生命周期
4.1生命周期钩子函数
- 八大生命周期
创建之前 beforeCreate(){}
创建完成 created(){}
挂载之前 beforeMount(){}
挂载完成 mounted(){}
更新之前 beforeUpdate(){}
更新完成 updated(){}
销毁之前 beforeDestroy(){}
销毁完成 destroyed(){}
- 如何理解生命周期流程图(重点)
vue实例化开始:
1、进入到创建之前,这个时候没有el元素,也没有data数据,但是含有一些内置事件和生命周期函数。
2、生命周期走到创建完成,这个时候依然没有el元素,但是出现了数据data,(可以发起ajax请求)
(只要有data就可以发起ajax请求)
3、生命周期走到挂载之前,这个时候出现了大量的逻辑,判断是否有el元素和模板
(1)首先要判断是否含有el元素
如果有,生命周期继续执行;
如果没有,判断是否调用了原型上的$mount(),如果有,生命周期继续执行;如果都没有,生命周期结束。
(这里要注意:$mount('html选择器')是手动挂载,是vue原型上的方法)
(2)然后,我们要判断是否含有template(模板)配置项(对应的是html片段)
如果有,就将它编译到render函数中进行渲染
如果没有,就渲染外部HTML。
这里,我们也可以自己写render函数,render函数的参数也是一个函数,该函数接收两个参数
第一个参数为标签,第二个参数为内容,即将内容放入到这个标签中并调用,返回调用的结果,这个结果会渲染到视图上,代替模板
例:
render(createElement){
// createElement调用,参数2放入到参数1中,代替el元素渲染到页面
return createElement('h1', 'render函数渲染内容');
},
渲染的优先级是:render(){}>template>外部的HTML
这个时候视图并没有渲染,用的仍然是未渲染的html内容,数据data依然存在
4、生命周期走到挂载完成,视图进行了重新渲染(用编译后的html替换了挂载点的内容),数据依然存在,这个时候就可以使用DOM节点了
5、当数据发生变化的时候,会触发更新之前和更新完成;(更新完成之后,可以获取最新的DOM节点)
6、手动调用$destroy()这个方法,会执行销毁之前和销毁完成
($destroy()是vue原型上的方法)销毁之前要卸载监听,否则会容易导致内存泄漏
<div id="app">
<p>姓名:{{name}}</p>
<p>{{user}}</p>
<button id="guzai">手动挂载</button>
<button id="xiezai">手动卸载</button>
<button @click="update">更新</button>
<button @click="add">添加身高</button>
</div>
<script>
/* 自己触发的函数:钩子函数
1.创建vue实例:创建之前(beforeCreate),创建完成(created)
2.挂载期:挂载之前(beforeMount),挂载完成(mounted)
3.更新期:更新之前(beforeUpdate),更新完成(updated)
4.卸载期:卸载之前(beforeDestroy),卸载完成(destroyed)
一般在什么地方发ajax请求
可以在created,beforeMount,mounted都可以发起ajax,我一般在mounted
*/
let vue = new Vue({
el:"#app",
//template:模板,如果有template,会优先加载template,替换el的挂载点
// template:"<div class='box'><h1>我是template111</h1></div>",
// render(h){
// return h("div",'我是template222')
// },
data: {
name: "妲己",
user:{
weight:180
}
},
methods: {
update(){
// this.name = "姜子牙";
this.user.weight = 170;
},
add(){
this.user.height = 180
}
},
//1.创建之前(beforeCreate),所有的都是undefined
beforeCreate() {
console.group("创建之前");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
//2.创建完成(created),vue实例中的data数据已经初始化完成,但是el还是undefined,最早能发ajax的地方
created() {
console.group("创建完成");
console.log("el", this.$el); //undefined
console.log("data", this.$data); //{}
console.log("name", this.name); //妲己
console.groupEnd();
},
//有el属性 或者 执行 vue.$mount() 才会进入挂载期
//3.挂载之前(beforeMount),找到了挂载点,但是{{name}}
beforeMount() {
console.group("挂载之前");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
//4.挂载完成(mounted):数据解析完成,页面渲染好
//ajax,DOM操作,window|document添加事件,开启定时器
mounted() {
console.group("挂载完成");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
//5.更新之前(beforeUpdate),页面更新之前,数据就已经是最新了
beforeUpdate(){
console.group("更新之前");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
//6.更新完成(updated)
updated(){
console.group("更新完成");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
//7.卸载之前(beforeDestroy)
//善后工作:取消window|document事件,关闭定时器
beforeDestroy(){
console.group("卸载之前");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
//8.卸载完成(destroyed)
//DOM处于卸载前最后一个状态,vue不再控制这个节点了
destroyed(){
console.group("卸载完成");
console.log("el", this.$el);
console.log("data", this.$data);
console.log("name", this.name);
console.groupEnd();
},
})
//手动挂载
document.querySelector("#guzai").onclick = function () {
//vue.$mount("挂载点")
vue.$mount("#app");
}
//手动卸载
document.querySelector("#xiezai").onclick = function () {
vue.$destroy();
}
</script>