Vue.js 前端开发实战之 03-Vue 开发基础(2)
Vue 事件修饰符
事件修饰符概述
事件修饰符是一种特殊的语法,用于指示 Vue 对 DOM 事件监听器行为进行特定的修改。
事件修饰符的基本用法:
<p v-on:事件类型.事件修饰符="xxx"></p>
<p v-on:事件类型.事件修饰符1.事件修饰符2="xxx"></p>Vue 的基本事件修饰符:
| 名称 | 描述 |
|---|---|
| .stop | 阻止事件冒泡 |
| .prevent | 阻止默认事件行为 |
| .capture | 事件捕获,和事件冒泡相反 |
| .self | 将事件绑定到自身,只有自身才能触发事件 |
| .once | 事件只触发一次 |
.stop
在 Vue 中,.stop 修饰符用于阻止事件冒泡。
当一个元素触发了某个事件,如果该元素的父元素也注册了相同的事件,默认情况下,事件会从子元素向上冒泡到父元素,从而触发父元素的相同事件处理函数,而使用 .stop 修饰符可以阻止这种冒泡行为。
示例:.stop 修饰符
入口页面(index.html):
<div id="app">
<!--
button作为div的子元素
当点击button时,按钮点击事件会冒泡(上浮)到div
故先触发button的点击事件,再触发div的点击事件(即事件冒泡)
.stop加给谁,谁的事件就不会冒泡
-->
<div @click="doParent" style="width: 200px; height: 200px; background-color: green">
<button @click="doThis">事件冒泡</button>
<button @click.stop="doThis">阻止事件冒泡</button>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
methods : {
doParent() {
console.log("父元素被点击")
},
doThis() {
console.log("子元素被点击")
}
}
})
</script>示例效果:
.prevent
在 Vue 中,.prevent 修饰符用于阻止默认事件。
默认事件是指浏览器为某些元素或操作预设的行为,如当点击一个链接时,浏览器会默认跳转到链接指向的页面,使用 .prevent 修饰符可以阻止这些默认行为的发生。
示例:.prevent 修饰符
入口页面(index.html):
<div id="app">
<!--
a标签的默认行为时跳转
阻止a标签的默认行为,页面不会进行跳转
-->
<a href="https://www.duozai.cn/">不阻止默认行为</a>
<a href="https://www.duozai.cn/" @click.prevent>阻止默认行为</a>
</div>
<script>
let vm = new Vue({
el: '#app'
})
</script>示例效果:
.capture
在 Vue 中,.capture 修饰符用于事件捕获阶段触发处理函数。
在 DOM 事件流中,事件的传播分为三个阶段:捕获阶段、目标阶段和冒泡阶段,默认情况下事件处理程序在冒泡阶段被触发, 使用 .capture 修饰符可以让事件在捕获阶段被处理。
示例:.capture 修饰符
入口页面(index.html):
<div id="app">
<!--
事件捕获的执行顺序由外向内,与事件冒泡相反
点击button按钮,div的点击事件被捕获
先触发div的点击事件,再触发button的点击事件
-->
<div @click.capture="doParent" style="width: 200px; height: 200px; background-color: green">
<button @click="doThis">事件捕获1</button>
<button @click="doThis">事件捕获2</button>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
methods : {
doParent() {
console.log("父元素被点击")
},
doThis() {
console.log("子元素被点击")
}
}
})
</script>示例效果:
.self
在 Vue 中,.self 修饰符用于事件监听,只有当事件是在自身元素而非子元素上触发时,才会执行相应的处理函数。
示例:.self 修饰符
入口页面(index.html):
<div id="app">
<!--
button存在事件冒泡
-->
<div @click="doParent" style="width: 200px; height: 200px; background-color: green">
<button @click.self="doThis">01</button>
</div>
<!--
div的点击事件只有自身被点击才会被触发
button虽然存在事件冒泡,但是不会影响到div的点击事件
-->
<div @click.self="doParent" style="width: 200px; height: 200px; background-color: red">
<button @click="doThis">02</button>
</div>
</div>
<script>
let vm = new Vue({
el: '#app',
methods : {
doParent() {
console.log("父元素被点击")
},
doThis() {
console.log("子元素被点击")
}
}
})
</script>示例效果:
.once
在 Vue 中,.once 修饰符用于事件监听,它会使绑定的事件只触发一次,之后再触发相应事件时将不会有响应。
示例:.once 修饰符
入口页面(index.html):
<div id="app">
<!-- 按钮的点击事件只会被触发一次 -->
<p v-text="count"></p>
<button @click.once="count+=Math.random()">点击</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
count: 0
}
})
</script>示例效果:
Vue 组件
组件概述
Vue 可以进行组件化开发,组件是 Vue 的基本结构单元。使用组件开发,能实现复杂的页面结构,提高代码的可复用性。
Vue 组件的基本用法:
<div id="app">
<!-- 调用组件 -->
<my-component></my-component>
<my-component></my-component>
</div>
<script>
// Vue.component():全局定义组件
// 参数1:组件名称,使用短横杠命名法
// 参数2:组件的配置对象
Vue.component('组件名称', {
// data:组件使用的数据
// data必须是一个函数,防止data被复用
data() {
return {
// ...
}
},
// methods:组件内的方法
methods: {
// ...
},
// template:组件模板,即组件显示的内容
template: ''
})
</script>示例:全局注册组件
入口页面(index.html):
<div id="app">
<button-component></button-component>
<button-component></button-component>
<button-component></button-component>
</div>
<script>
Vue.component('button-component', {
data() {
return {
count: 0
}
},
template: '<button @click="count++">被单击了{{count}}次</button>'
})
let vm = new Vue({
el: '#app',
})
</script>示例效果:
局部注册组件
组件还可以进行局部注册,局部注册的组件,只对当前的 Vue 实例有效。
局部注册组件的基本用法:
<script>
let vm = new Vue({
el: '#app',
// components:局部注册组件
components: {
// 组件名称,只能使用驼峰命名法
组件名称: {
// ...
}
}
})
</script>示例:局部注册组件
入口页面(index.html):
<div id="app">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<script>
let vm = new Vue({
el: '#app',
components: {
myComponent: {
data() {
return {
count: 0
}
},
template: '<button @click="count++">被单击了{{count}}次</button>'
}
}
})
</script>示例效果:
template 模板
Vue 提供了 template 组件标签来定义结构的模板,可以在标签中书写复杂的 HTML 代码,然后将模板绑定给组件。
template 组件的基本用法:
<template id="myTemplate">
<!-- <template>标签内必须有且只能有一个根标签 -->
<div>
<!-- ... -->
</div>
</template>
<script>
let vm = new Vue({
el: '#app',
components: {
myComponent: {
// 使用id选择器为组件绑定模板
template: '#myTemplate'
}
}
})
</script>示例:template 模板
入口页面(index.html):
<div id="app">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div>
<template id="myTemplate">
<div>
点击以下按钮:
<button @click="count++">被单机了{{count}}次</button>
</div>
</template>
<script>
let vm = new Vue({
el: '#app',
components: {
myComponent: {
data() {
return {
count: 0
}
},
template: '#myTemplate'
}
}
})
</script>示例效果:
组件插槽
Vue 中的组件中使用 template 模板定义 HTML 结构,为了方便使用 template 公共模板结构,Vue 提出了插槽(Slots)的概念,插槽就是定义在组件内部的 template 模板。
组件插槽的基本用法:
<my-component>
<!-- 组件内部的模板 -->
<div>xxx</div>
</my-component>
<template id="myComponent">
<div>
<!-- <slot>:用于接收自定义组件的内容 -->
<slot></slot>
</div>
</template>示例:组件插槽
入口页面(index.html):
<div id="app">
<my-component>
<div>Hello,Vue</div>
<div>Hello,Component</div>
<div>Hello,Slots</div>
</my-component>
</div>
<template id="myTemplate">
<div>
Hello,MyTemplate:
<slot></slot>
</div>
</template>
<script>
Vue.component('my-component', {
template: '#myTemplate'
})
let vm = new Vue({
el: '#app'
})
</script>示例效果:
具名插槽
当有多个插槽时,可以为插槽命名。
具名插槽的基本用法:
<my-component>
<template v-slot:插槽名称>
<div>xxx</div>
</template>
<template v-slot:插槽名称>
<div>xxx</div>
</template>
</my-component>
<template id="myComponent">
<div>
<slot name="插槽名称"></slot>
<slot name="插槽名称"></slot>
</div>
</template>示例:具名插槽
入口页面(index.html):
<div id="app">
<my-component>
<template v-slot:slot01>
<div>Hello,Vue</div>
</template>
<template v-slot:slot02>
<div>Hello,Component</div>
</template>
<template v-slot:slot03>
<div>Hello,Slots</div>
</template>
</my-component>
</div>
<template id="myTemplate">
<div>
Hello,MyTemplate:
<slot name="slot01"></slot>
<hr>
<slot name="slot02"></slot>
<hr>
<slot name="slot03"></slot>
</div>
</template>
<script>
Vue.component('my-component', {
template: '#myTemplate'
})
let vm = new Vue({
el: '#app'
})
</script>示例效果:
组件数据传递
组件实例内部具有自己的独立作用域,不能直接被外部访问。
组件之间的数据传递需要借助一些工具来实现,且组件之间的数据传递是单向的。
父组件向子组件传递数据,使用 props 传值。
示例:父组件向子组件传递数据
入口页面(index.html):
<div id="app">
<!-- 调用子组件,设置子组件的"属性",进行父向子传值 -->
<my-component title="A"></my-component>
<my-component title="AB"></my-component>
<my-component title="ABC"></my-component>
</div>
<script>
let vm = new Vue({
el: '#app',
components: {
myComponent: {
// props:接收父组件给子组件传递的数据(参数列表)
props: ['title'],
// data:组件使用的数据
data() {
return {
count: 0
}
},
template: '<button @click="count++">按钮{{title}}被单击了{{count}}次</button>'
}
}
})
</script>示例效果:
子组件向父组件传递数据,使用 $emit 传值。
示例:子组件向父组件传递数据
入口页面(index.html):
<div id="app">
<!-- 调用父组件 -->
<parent></parent>
</div>
<template id="parent">
<div style="border: green solid 2px; padding: 20px">
<!--
父组件调用子组件
@child-fn:给调用的子组件绑定了一个child-fn事件
注意事件的名称要使用短横杠命名法,驼峰命名法可能无法使用
@child-fn:子组件向父组件发送消息时,触发父组件的transContent方法
-->
<child @child-fn="transContent"></child>
子组件传来的消息:{{message}}
</div>
</template>
<template id="child">
<div style="border: blue solid 2px; padding: 20px;">
<input type="text" v-model="message">
<button @click="send">发送</button>
</div>
</template>
<script>
// 注册父组件
Vue.component('parent', {
template: '#parent',
data() {
return {
message: ''
}
},
methods: {
// playload:子组件传递给父组件的数据
transContent(playload) {
this.message = playload
}
}
})
Vue.component('child', {
template: '#child',
data() {
return {
message: '我是子组件'
}
},
methods : {
send() {
// this.$emit:向父组件传递子组件的message
// child-fn:调用子组件时绑定的事件名称
// this.message:要传递的数据
this.$emit('child-fn', this.message)
}
}
})
let vm = new Vue({
el: '#app',
})
</script>示例效果:
组件切换
实现组件切换的方式:
- 使用 v-if 控制组件的显示和隐藏。
- 使用 component 标签的 is 属性绑定组件名称。
示例:组件切换
入口页面(index.html):
<div id="app">
<a href="#" @click.prevent="flag ? flag : flag=!flag">登录</a>
<a href="#" @click.prevent="flag ? flag=!flag : flag">注册</a>
<login v-if="flag"></login>
<register v-else></register>
<br>
<a href="#" @click.prevent="componentName='login'">登录</a>
<a href="#" @click.prevent="componentName='register'">注册</a>
<component v-bind:is="componentName"></component>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
flag: true,
componentName: 'login'
},
components : {
login: {
template: '<div>登录页面</div>'
},
register: {
template: '<div>注册页面</div>'
}
}
})
</script>示例效果:
Vue 生命周期
生命周期概述
每个 Vue 实例在被创建时都要经过一系列的初始化过程,如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。
Vue 的生命周期:
在 Vue 的生命周期的过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
Vue 生命周期对应的钩子函数:
| 名称 | 描述 |
|---|---|
| beforeCreate | 实例创建之前执行 |
| created | 实例创建之后执行 |
| beforeMount | 页面挂载成功之前执行 |
| mounted | 页面挂载成功之后执行 |
| beforeUpdate | 组件更新之前执行 |
| updated | 组件更新之后执行 |
| beforeDestory | 实例销毁之前执行 |
| destoryed | 实例销毁之后执行 |
beforeCreate/created
beforeCreate:在实例创建之前被调用,此时数据观测和事件配置尚未完成。
created:此时实例已经创建完成,数据观测和事件配置完成,但 DOM 尚未挂载,可进行一些数据请求和初始化操作。
示例:实例创建生命周期
入口页面(index.html):
<div id="app">
<h3>{{name}}</h3>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
name: 'Vue实例创建成功!'
},
beforeCreate() {
// 实例创建前:无法访问Vue实例的数据
console.log('实例创建之前:' + this.name)
},
created() {
// 实例创建后:可以访问Vue实例的数据
console.log('实例创建之后:' + this.name)
}
})
</script>示例效果:
beforeMount/mounted
beforeMount:在挂载之前被调用,此时模板已经编译完成,但尚未渲染到 DOM 中。
mounted:挂载完成,即模板已经渲染到 DOM 中,可以进行 DOM 操作和获取 DOM 元素。
示例:页面挂载生命周期
入口页面(index.html):
<div id="app">
<h3>{{name}}</h3>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
name: 'Vue实例创建成功!'
},
beforeMount() {
// this.$el.innerHTML:获取#app的HTML内容
// 页面挂载前:数据未被渲染
console.log('页面挂载之前:' + this.$el.innerHTML)
},
mounted() {
// 页面挂载后:数据已经被渲染
console.log('页面挂载之后:' + this.$el.innerHTML)
}
})
</script>示例效果:
beforeUpdate/updated
beforeUpdate:数据更新之前调用,可在此时获取更新前的状态。
updated:数据更新完成后调用,可在此进行基于更新后 DOM 的操作。
示例:数据更新生命周期
入口页面(index.html):
<div id="app">
<h3>{{name}}</h3>
<button @click="showInfo">点我</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
name: 'Vue实例创建成功!'
},
methods: {
showInfo() {
this.name = '点击啦!'
}
},
beforeUpdate() {
// 数据更新前:数据未被渲染
// 数据是新的,但是还没渲染到视图页面上
console.log('数据更新之前:' + this.name)
console.log('数据更新之前:' + this.$el.innerHTML)
},
updated() {
// 数据更新后:数据已经被渲染
// 数据和视图页面都是新的
console.log('数据更新之后:' + this.name)
console.log('数据更新之后:' + this.$el.innerHTML)
}
})
</script>示例效果:
beforeDestroy/destroyed
beforeDestroy:实例销毁之前调用,可进行一些清理操作。
destroyed:实例销毁后调用,解绑相关的事件监听器和定时器等。
示例:实例销毁生命周期
入口页面(index.html):
<div id="app">
<h3>{{name}}</h3>
<button @click="showInfo">点我</button>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
name: 'Vue实例创建成功!'
},
methods: {
showInfo() {
this.name = '点击啦!'
}
},
beforeDestroy() {
// 实例销毁前:绑定、事件还未失效
console.log('实例销毁之前')
},
destroyed() {
// 实例销毁后:绑定、事件失效
console.log('实例销毁之后')
}
})
// 销毁实例
vm.$destroy()
</script>示例效果: