1.1 模版语法
Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。
1.1.1 插值表达式和文本渲染
插值表达式:最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 ,即双大括号
{{}}
- 插值表达式是将数据渲染到元素的指定位置的手段之一
- 插值表达式不绝对依赖标签,其位置相对自由
- 插值表达式中支持JavaScript的运算表达式
- 插值表达式中也支持函数的调用
- 插值表达式只能用于数据的显示,不能用于属性赋值
<script setup>
/* 插值表达式 语法: {{}} */
let msg = "hello Vue3"
function getMsg() {
return "我是Vue.js"
}
let a = 100
let b = 100
let user = {
id: 100,
name :"tomcat"
}
</script>
<template>
<div>
<!-- 1.基本数据的引入 -->
<h1>{{msg}}</h1>
<!-- 2.插入表达式调用函数 -->
<h2>{{getMsg()}}</h2>
<!-- 3.进行js计算 -->
<h2>{{ a + b}}</h2>
<!-- 4.进行对象的引用 -->
<h2>{{ user.id + ":" + user.name }}</h2>
</div>
</template>
<style scoped>
</style>
为了渲染双标中的文本,我们也可以选择使用
v-text
和v-html
命令
- v-*** 这种写法的方式使用的是vue的命令
- v-***的命令必须依赖元素,并且要写在元素的开始标签中
- v-***指令支持ES6中的字符串模板
- 插值表达式中支持JavaScript的运算表达式
- 插值表达式中也支持函数的调用
- v-text可以将数据渲染成双标签中间的文本,但是不识别html元素结构的文本
- v-html可以将数据渲染成双标签中间的文本,识别html元素结构的文本
<script setup>
/* 文本绑定标签 */
let msg = "hello Vue"
function getMsg() {
return "我是一个业务操作"
}
let myHtml = "<h1>我是一个标题标签</h1>"
</script>
<template>
<div>
<!-- 插入表达式引入数据 -->
<h1>{{ msg }}</h1>
<!-- 1.v-text语法: 为标签添加显示内容 -->
<h1 v-text="msg"></h1>
<!-- 2.v-text语法: 调用函数 -->
<h1 v-text="getMsg()"></h1>
<!-- 3.v-html语法: 为标签添加html语法 -->
<div v-html="myHtml"></div>
</div>
</template>
<style scoped>
</style>
1.1.2 Attribute属性渲染
想要渲染一个元素的 attribute,应该使用
v-bind
指令
- 由于插值表达式不能直接放在标签的属性中,所有要渲染元素的属性就应该使用v-bind
- v-bind可以用于渲染任何元素的属性,语法为
v-bind:属性名='数据名'
, 可以简写为:属性名='数据名'
<script setup>
/* v-bind指令 属性绑定 */
let url = "http://www.baidu.com"
let imageUrl = "http://www.xxxx.com/images/index_new/logo.png"
let colorClass = "greenClass"
let username = "admin"
</script>
<template>
<div>
<!-- 1.动态绑定属性 -->
<a v-bind:href="url">百度</a> <br>
<a :href="url">百度-简化</a><br>
<!-- 2.绑定图片地址 -->
<img :src="imageUrl">
<!-- 3.绑定样式class -->
<div :class="colorClass"></div>
<!-- 4.绑定input默认值 -->
<input type="text" name="username" :value="username">
</div>
</template>
<style scoped>
.greenClass {
width: 100px;
height: 100px;
background-color:green;
}
</style>
1.1.3 事件的绑定
我们可以使用
v-on
来监听 DOM 事件,并在事件触发时执行对应的 Vue的JavaScript代码。
- 用法:
v-on:click="handler"
或简写为@click="handler"
- vue中的事件名=原生事件名去掉
on
前缀 如:onClick --> click
- handler的值可以是方法事件处理器,也可以是内联事件处理器
- 绑定事件时,可以通过一些绑定的修饰符,常见的事件修饰符如下
.once:只触发一次事件。[重点]
.prevent:阻止默认事件。[重点]
- .stop:阻止事件冒泡。
- .capture:使用事件捕获模式而不是冒泡模式。
- .self:只在事件发送者自身触发时才触发事件。
<script setup>
//引入响应式
import { ref } from 'vue';
/* 事件绑定案例 */
function myClick(){
alert("我是点击触发事件")
}
function myChange(){
alert("change事件触发")
}
function myBlur(){
alert("blur事件触发")
}
//定义自增变量 定义响应式
let count = ref(0)
function addNum(){
count.value ++
}
function myHref(event){
console.log(event)
console.log(event.target) //获取当前元素
window.location.href = "http://www.jd.com"
//阻止默认行为
event.preventDefault()
}
</script>
<template>
<div>
<!-- 1.点击事件绑定 -->
<button v-on:click="myClick">点击触发事件</button>
<!-- 2.简化写法 -->
<button @click="myClick">点击事件绑定2</button>
<br>
<!-- 3.点击change事件-->
<input type="text" @change="myChange" placeholder="change事件"><br>
<!-- 4.blur事件操作 -->
<input type="text" @blur="myBlur" placeholder="blur事件"><br>
<!-- 5.响应式自增操作 -->
<h3 v-text="count"></h3>
<button @click="addNum">自增</button>
<hr>
<!-- 6. .once事件 只触发一次 -->
<button @click.once="addNum">只触发一次自增</button>
<br>
<!-- 7.阻止默认行为 -->
<a href="http://www.baidu.com" @click.prevent="myHref">阻止百度跳转1</a>
<!-- $event表示获取当前事件 -->
<a href="http://www.baidu.com" @click="myHref($event)">阻止百度跳转2</a>
</div>
</template>
<style scoped>
</style>
1.2 响应式基础
此处的响应式是指 : 数据模型发生变化时,自动更新DOM树内容,页面上显示的内容会进行同步变化,vue3的数据模型不是自动响应式的,需要我们做一些特殊的处理
1.2.1 响应式需求案例
需求:实现 + - 按钮,实现数字加一减一
<script type="module" setup>
let counter = 0;
function show(){
alert(counter);
}
</script>
<template>
<div>
<button @click="counter--">-</button>
{{ counter }}
<button @click="counter++">+</button>
<hr>
<!-- 此案例,我们发现counter值,会改变,但是页面不改变! 默认Vue3的数据是非响应式的!-->
<button @click="show()">显示counter值</button>
</div>
</template>
<style scoped>
</style>
1.2.2 响应式实现关键字ref
ref
可以将一个基本类型的数据(如字符串,数字等)转换为一个响应式对象。ref
只能包裹单一元素
<script type="module" setup>
/* 从vue中引入ref方法 */
import {ref} from 'vue'
let counter = ref(0);
function show(){
alert(counter.value);
}
/* 函数中要操作ref处理过的数据,需要通过.value形式 */
let decr = () =>{
counter.value--;
}
let incr = () =>{
counter.value++;
}
</script>
<template>
<div>
<button @click="counter--">-</button>
<button @click="decr()">-</button>
{{ counter }}
<button @click="counter++">+</button>
<button @click="incr()">+</button>
<hr>
<button @click="show()">显示counter值</button>
</div>
</template>
<style scoped>
</style>
- 在上面的例子中,我们使用
ref
包裹了一个数字,在代码中给这个数字加 1 后,视图也会跟着动态更新。需要注意的是,由于使用了ref
,因此需要在访问该对象时使用.value
来获取其实际值。
1.2.3 响应式实现关键字reactive
我们可以使用 reactive() 函数创建一个响应式对象或数组:
<script setup>
//引入响应式
import { ref,reactive } from 'vue';
/* 响应式的2种写法 */
let conunt = ref(0)
function addNum(){
conunt.value ++
}
let person = reactive({
id: 100,
name: "tomcat"
})
//通过reactive标识响应式对象
function updateData(){
person.id = 200
person.name = "mysql"
}
</script>
<template>
<div>
<h3>{{ conunt }}</h3>
<button @click="addNum">ref-响应式</button>
<hr>
<div>
<p>{{ person.id }} ~~~~ {{ person.name }}</p>
</div>
<button @click="updateData">reactive响应式</button>
</div>
</template>
<style scoped>
</style>
对比ref和reactive:
-
使用
ref
适用于以下开发场景:- 包装基本类型数据:
ref
主要用于包装基本类型数据(如字符串、数字等),即只有一个值的数据,如果你想监听这个值的变化,用ref
最为方便。在组件中使用时也很常见。 - 访问方式简单:
ref
对象在访问时与普通的基本类型值没有太大区别,只需要通过.value
访问其实际值即可。
- 包装基本类型数据:
-
使用
reactive
适用于以下开发场景:- 包装复杂对象:
reactive
可以将一个普通对象转化为响应式对象,这样在数据变化时会自动更新界面,特别适用于处理复杂对象或者数据结构。 - 需要递归监听的属性:使用
reactive
可以递归追踪所有响应式对象内部的变化,从而保证界面的自动更新。
- 包装复杂对象:
-
综上所述,
ref
适用与简单情形下的数据双向绑定,对于只有一个字符等基本类型数据或自定义组件等情况,建议可以使用ref
;而对于对象、函数等较为复杂的数据结构,以及需要递归监听的属性变化,建议使用reactive
。当然,在实际项目中根据需求灵活选择也是十分必要的。
1.2.4 扩展响应式关键字toRefs 和 toRef
toRef基于reactive响应式对象上的一个属性,创建一个对应的 ref响应式数据。这样创建的 ref 与其源属性保持同步:改变源属性的值将更新 ref 的值,反之亦然。toRefs将一个响应式对象多个属性转换为一个多个ref数据,这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 toRef() 创建的。
案例:响应显示reactive对象属性
<script setup>
//引入响应式
import { ref,reactive,toRef,toRefs} from 'vue';
/* toRef 和Refs用法 */
let user = reactive({
id: 200,
username: "张三"
})
//写代码时注意引号
let nameRef = toRef(user,"username")
let {id:myId,username:myUsername} = toRefs(user)
function changeData(){
nameRef.value = "修改后的值!!!!!"
}
</script>
<template>
<div>
<div>
{{ user.id }} ~~~~ {{ user.username }}
<br>
{{ nameRef }} ~~~{{ myId }} ~~~{{ myUsername }}
</div>
<button @click="changeData">修改数据1</button>
<button @click="nameRef = '第二种方式'">修改数据2</button>
</div>
</template>
<style scoped>
</style>
1.3 条件和列表渲染
1.3.1 条件渲染
v-if
条件渲染
-
v-if='表达式'
只会在指令的表达式返回真值时才被渲染 -
也可以使用
v-else
为v-if
添加一个“else 区块”。 -
一个
v-else
元素必须跟在一个v-if
元素后面,否则它将不会被识别。
<script type="module" setup>
import {ref} from 'vue'
let awesome = ref(true)
</script>
<template>
<div>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
<button @click="awesome = !awesome">Toggle</button>
</div>
</template>
<style scoped>
</style>
v-show
条件渲染扩展:
-
另一个可以用来按条件显示一个元素的指令是
v-show
。其用法基本一样: -
不同之处在于
v-show
会在 DOM 渲染中保留该元素;v-show
仅切换了该元素上名为display
的 CSS 属性。 -
v-show
不支持在<template>
元素上使用,也不能和v-else
搭配使用。
<script type="module" setup>
import {ref} from 'vue'
let awesome = ref(true)
</script>
<template>
<div>
<h1 id="ha" v-show="awesome">Vue is awesome!</h1>
<h1 id="hb" v-if="awesome">Vue is awesome!</h1>
<h1 id="hc" v-else>Oh no 😢</h1>
<button @click="awesome = !awesome">Toggle</button>
</div>
</template>
<style scoped>
</style>
v-if
vsv-show
-
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。 -
v-if
也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。 -
相比之下,
v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有 CSSdisplay
属性会被切换。 -
总的来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要频繁切换,则使用v-show
较好;如果在运行时绑定条件很少改变,则v-if
会更合适。
1.3.2 列表渲染
我们可以使用
v-for
指令基于一个数组来渲染一个列表。
-
v-for
指令的值需要使用item in items
形式的特殊语法,其中items
是源数据的数组,而item
是迭代项的别名: -
在
v-for
块中可以完整地访问父作用域内的属性和变量。v-for
也支持使用可选的第二个参数表示当前项的位置索引。
<script setup>
//引入响应式
import {ref} from "vue"
//定义数组
let array = ["王昭君","安琪拉","不知火舞"]
//遍历集合数据
let userList = [{id: 1001,name:"张三"},{id:1002,name:"李四"}]
</script>
<template>
<div>
<!-- 知识点: v-for = "每个元素,下标值 in 数组" -->
<p v-for="item in array" v-text="item" :key="item"></p>
<p v-for="item,index in array" :key="item">
{{ index }} ~~~ {{ item }}
</p>
<!-- 遍历对象 -->
<div v-for="user in userList" :key="user.id">
<p v-text="user.id"></p>
<p v-text="user.name"></p>
</div>
</div>
</template>
<style scoped>
</style>
1.4 双向绑定
单项绑定和双向绑定
- 单向绑定: 响应式数据的变化会更新dom树,但是dom树上用户的操作造成的数据改变不会同步更新到响应式数据
- 双向绑定: 响应式数据的变化会更新dom树,但是dom树上用户的操作造成的数据改变会同步更新到响应式数据
- 用户通过表单标签才能够输入数据,所以双向绑定都是应用到表单标签上的,其他标签不行
- v-model专门用于双向绑定表单标签的value属性,语法为
v-model:value=''
,可以简写为v-model=''
- v-model还可以用于各种不同类型的输入,
<textarea>
、<select>
元素。
<script setup>
import {ref,reactive} from "vue"
//通过响应式定义数据
let user = reactive({id:100, name: "tom"})
let person = reactive({
username: "admin",
password: "admin123",
gender: "男",
city: "北京"
})
function addPerson(){
alert(person.username + ":" +person.password)
}
</script>
<template>
<div>
ID号: <input type="text" v-model="user.id">
姓名: <input type="text" v-model="user.name">
<hr>
数据绑定测试: <br>
ID号: {{ user.id }}<br>
姓名: {{ user.name }}<br>
<hr>
<form>
用户名: <input type="text" name="username" v-model="person.username"><br>
密码: <input type="password" name="password" v-model="person.password"><br>
性别: <input type="radio" name="gender" value="男" v-model="person.gender">男
<input type="radio" name="gender" value="女" v-model="person.gender">女<br>
所在城市:
<select name="city" v-model="person.city">
<option value="上海"> 上海</option>
<option value="北京"> 北京</option>
<option value="海南"> 海南</option>
<option value="西安"> 西安</option>
</select>
<button @click="addPerson()">双向数据绑定测试</button>
</form>
</div>
</template>
<style scoped>
</style>
1.5 属性计算
模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象:
<script setup>
import { computed } from 'vue';
let books = ["java编程","mysql","vue"]
//let books = []
function getBookLength(){
console.log("方法被调用!!")
return books.length > 0 ? "有图书" : "没有图书"
}
</script>
<template>
<div>
<!-- 1.计算获取图书的数量 -->
{{ books.length > 0 ? "有图书" : "没有图书" }}<br>
<!-- 2.通过方法获取图书 -->
{{ getBookLength() }} <br>
{{ getBookLength() }} <br>
</div>
</template>
<style scoped>
</style>
- 这里的模板看起来有些复杂。我们必须认真看好一会儿才能明白它的计算依赖于
books
。更重要的是,如果在模板中需要不止一次这样的计算,我们可不想将这样的代码在模板里重复好多遍。
因此我们推荐使用计算属性来描述依赖响应式状态的复杂逻辑。这是重构后的示例:
<script setup>
import { computed } from 'vue';
let books = ["java编程","mysql","vue"]
//let books = []
let computedBooks = computed( () => {
console.log("计算属性被调用")
return books.length > 0 ? "有图书" : "没有图书"
})
</script>
<template>
<div>
<!-- 3.调用计算属性 -->
{{ computedBooks }} <br>
{{ computedBooks }} <br>
{{ computedBooks }} <br>
</div>
</template>
<style scoped>
</style>
- 我们在这里定义了一个计算属性
computedBooks
。computed()
方法期望接收一个 getter 函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,你可以通过.value
访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加.value
。
计算属性缓存 vs 方法
- 若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
1.6 数据监听器
计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数:
- watch主要用于以下场景:
- 当数据发生变化时需要执行相应的操作
- 监听数据变化,当满足一定条件时触发相应操作
- 在异步操作前或操作后需要执行相应的操作
监控响应式数据(watch):
- ref响应式-监听器用法
<script type="module" setup>
//引入模块
import { ref,reactive,computed,watch} from 'vue'
/* 监听器用法---ref用法 */
let msg = ref("")
/* 使用方法没有办法实现数据的实时监控 */
function getMsg(){
console.log(msg.value)
}
/*通过监听器实现业务 */
watch(msg,function(newMsg,oldMsg){
//监控属性 msg
console.log("新数据:"+newMsg)
console.log("旧数据:"+oldMsg)
let rege = /行动/
if(rege.test(newMsg)){
alert("小子 盯你好久了!!!")
}else{
console.log("放长线,钓大鱼!!!")
}
})
</script>
<template>
<div>
<!-- 1.准备一个属性定义监听器 -->
特务: <input type="text" name="msg" v-model="msg"/>
<!-- <button @click="getMsg">获取用户信息</button> -->
</div>
</template>
<style scoped>
</style>
- reactive 用法
<script type="module" setup>
//引入模块
import { ref,reactive,computed,watch} from 'vue'
/* 监听器用法--- reactive 用法*/
let msgRea = reactive({msg: ''})
//获取响应式数据
function getMsg() {
alert(msgRea.msg)
}
//配置监听器
//语法: watch(function(){return 监控的数据},function(newMsg,oldMsg){...})
/* watch(function(){return msgRea.msg},function(newMsg,oldMsg){
//console.log("新数据:"+newMsg)
//console.log("旧数据:"+oldMsg)
let rege = /行动/
if(rege.test(newMsg)){
alert("小子盯你好久了")
}else{
console.log("放长线钓大鱼!!!")
}
}) */
/* 配置监听器-监控所有属性 只要msgRea中的属性发生变化则会监控
语法:
{
deep:true, 深度监控
immediate: true 立即执行
}
*/
watch(() => msgRea,(newMsg,oldMsg) => {
//使用该语法 新旧数据相同
console.log(newMsg)
console.log(oldMsg)
},{deep:true,immediate: true})
</script>
<template>
<div>
<!-- 1.准备一个属性定义监听器 -->
特务: <input type="text" name="msg" v-model="msgRea.msg"/>
<button @click="getMsg">获取数据</button>
</div>
</template>
<style scoped>
</style>
监控响应式数据(watchEffect):
- watchEffect默认监听所有的响应式数据
<script type="module" setup>
//引入模块
import { ref,reactive,computed,watch,watchEffect} from 'vue'
//监控所有响应式数据
let msgRea = reactive({msg: ''})
//语法: watchEffect(function(){ 需要监控的数据 })
watchEffect(function(){
let rege = /行动/
if(rege.test(msgRea.msg)){
alert("行动")
}else{
console.log("放长线,钓大鱼!!!")
}
})
</script>
<template>
<div>
<!-- 1.准备一个属性定义监听器 -->
特务: <input type="text" name="msg" v-model="msgRea.msg"/>
</div>
</template>
<style scoped>
</style>
watch
vswatchEffect
watch
和watchEffect
都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:watch
只追踪明确侦听的数据源。它不会追踪任何在回调中访问到的东西。另外,仅在数据源确实改变时才会触发回调。watch
会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。watchEffect
,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。这更方便,而且代码往往更简洁,但有时其响应性依赖关系会不那么明确。
1.7 Vue生命周期
1.7.1 生命周期简介
每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为
生命周期钩子的函数
,让开发者有机会在特定阶段运行自己的代码!
- 周期图解:
- 常见钩子函数
- onMounted() 注册一个回调函数,在组件挂载完成后执行。
- onUpdated() 注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。
- onUnmounted() 注册一个回调函数,在组件实例被卸载之后调用。
- onBeforeMount() 注册一个钩子,在组件被挂载之前被调用。
- onBeforeUpdate() 注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。
- onBeforeUnmount() 注册一个钩子,在组件实例被卸载之前调用。
1.7.2 生命周期案例
<script setup>
import {ref,onUpdated,onMounted,onBeforeUpdate} from 'vue'
let message =ref('hello')
// 挂载完毕生命周期
onMounted(()=>{
console.log('-----------onMounted---------')
let span1 =document.getElementById("span1")
console.log(span1.innerText)
})
// 更新前生命周期
onBeforeUpdate(()=>{
console.log('-----------onBeforeUpdate---------')
console.log(message.value)
let span1 =document.getElementById("span1")
console.log(span1.innerText)
})
// 更新完成生命周期
onUpdated(()=>{
console.log('-----------onUpdated---------')
let span1 =document.getElementById("span1")
console.log(span1.innerText)
})
</script>
<template>
<div>
<span id="span1" v-text="message"></span> <br>
<input type="text" v-model="message">
</div>
</template>
<style scoped>
</style>
1.8 Vue组件
1.8.1 组件之间传递数据
1.8.1.1 父传子
Vue3 中父组件向子组件传值可以通过 props 进行,具体操作如下:
-
首先,在父组件中定义需要传递给子组件的值,接着,在父组件的模板中引入子组件,同时在引入子组件的标签中添加 props 属性并为其设置需要传递的值。
-
在 Vue3 中,父组件通过 props 传递给子组件的值是响应式的。也就是说,如果在父组件中的传递的值发生了改变,子组件中的值也会相应地更新。
- 父组件代码:App.vue
<script setup>
import Son from './components/Son.vue'
import {ref,toRefs} from 'vue'
let message = ref('parent data!')
let title = ref(42)
function changeMessage(){
message.value = '修改数据!'
title.value++
}
</script>
<template>
<div>
<h2>{{ message }}</h2>
<hr>
<!-- 使用子组件,并且传递数据! -->
<Son :message="message" :title="title"></Son>
<hr>
<button @click="changeMessage">点击更新</button>
</div>
</template>
<style scoped>
</style>
- 子组件代码:Son.vue
<script setup type="module">
import {ref,isRef} from 'vue'
//声明父组件传递属性值
defineProps({
message:String ,
title:Number
})
</script>
<template>
<div>
<div>{{ message }}</div>
<div>{{ title }}</div>
</div>
</template>
<style>
</style>
1.8.1.2 子传父
- 父组件: App.vue
<script setup>
import Son from './components/Son.vue'
import {ref} from 'vue'
let pdata = ref('')
const padd = (data) => {
console.log('2222');
pdata.value =data;
}
//自定义接收,子组件传递数据方法! 参数为数据!
const psub = (data) => {
console.log('11111');
pdata.value = data;
}
</script>
<template>
<div>
<!-- 声明@事件名应该等于子模块对应事件名!调用方法可以是当前自定义!-->
<Son @add="padd" @sub="psub"></Son>
<hr>
{{ pdata }}
</div>
</template>
<style>
</style>
- 子组件:Son.vue
<script setup>
import {ref,defineEmits} from 'vue'
//1.定义要发送给父组件的方法,可以1或者多个
let emites = defineEmits(['add','sub']);
let data = ref(1);
function sendMsgToParent(){
console.log('-------son--------');
//2.出发父组件对应的方法,调用defineEmites对应的属性
emites('add','add data!'+data.value)
emites('sub','sub data!'+data.value)
data.value ++;
}
</script>
<template>
<div>
<button @click="sendMsgToParent">发送消息给父组件</button>
</div>
</template>
1.8.1.3 兄弟传参
- Navigator.vue: 发送数据到App.vue
<script setup type="module">
const emits = defineEmits(['sendMenu']);
//触发事件,向父容器发送数据
function send(data){
emits('sendMenu',data);
}
</script>
<template>
<!-- 推荐写一个根标签-->
<div>
<ul>
<li @click="send('学员管理')">学员管理</li>
<li @click="send('图书管理')">图书管理</li>
<li @click="send('请假管理')">请假管理</li>
<li @click="send('考试管理')">考试管理</li>
<li @click="send('讲师管理')">讲师管理</li>
</ul>
</div>
</template>
<style>
</style>
- App.vue: 发送数据到Content.vue
<script setup>
import Header from './components/Header.vue'
import Navigator from './components/Navigator.vue'
import Content from './components/Content.vue'
import {ref} from "vue"
//定义接受navigator传递参数
var navigator_menu = ref('ceshi');
const receiver = (data) =>{
navigator_menu.value = data;
}
</script>
<template>
<div>
<hr>
{{ navigator_menu }}
<hr>
<Header class="header"></Header>
<Navigator @sendMenu="receiver" class="navigator"></Navigator>
<!-- 向子组件传递数据-->
<Content class="content" :message="navigator_menu"></Content>
</div>
</template>
<style scoped>
.header{
height: 80px;
border: 1px solid red;
}
.navigator{
width: 15%;
height: 800px;
display: inline-block;
border: 1px blue solid;
float: left;
}
.content{
width: 83%;
height: 800px;
display: inline-block;
border: 1px goldenrod solid;
float: right;
}
</style>
- Content.vue
<script setup type="module">
defineProps({
message:String
})
</script>
<template>
<div>
展示的主要内容!
<hr>
{{ message }}
</div>
</template>
<style>
</style>