组合API-computed函数
定义计算属性:
- computed函数,是用来定义计算属性的,计算属性不能修改。
基础用法:
<template>
<div class="container">
<div>今年:{{age}}岁</div>
<div>后年:{{newAge}}岁</div>
</div>
</template>
<script>
import { computed, ref } from 'vue'
export default {
name: 'App',
setup () {
// 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
const age = ref(16)
// 得到后年的年龄
const newAge = computed(()=>{
// 该函数的返回值就是计算属性的值
return age.value + 2
})
return {age, newAge}
}
}
</script>
高级用法:
<template>
<div>
<div>今年年龄:{{ age }}</div>
<div>后年年龄:{{ newAge }}</div>
</div>
</template>
<script>
import { computed, ref } from "vue";
export default {
setup() {
const age = ref(22);
const newAge = computed({
get() {
return age.value + 2;
},
set (value) {
age.value = value - 2
}
})
return { age, newAge };
},
}
</script>
目的:让计算属性支持双向数据绑定。
- 总结:计算属性两种用法
- 给computed传入函数,返回值就是计算属性的值
- 给computed传入对象,get获取计算属性的值,set监听计算属性改变。
组合API-watch函数
- watch函数,是用来定义侦听器的
- 1.监听ref定义的响应式数据
<template>
<div>
<div>{{ count }}</div>
<button @click="add">自加一</button>
<hr />
</div>
</template>
<script>
import { ref, watch } from "vue";
export default {
setup() {
const count = ref(16);
const add = () => {
count.value++;
}
// 当你需要监听数据的变化就可以使用watch
// 1. 监听一个ref数据
// 1.1 第一个参数 需要监听的目标
// 1.2 第二个参数 改变后触发的函数
watch(count, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
return { count, add }
},
}
</script>
- 2.监听reactive定义的响应式数据
<template>
<div>
<p>{{ obj.name }}</p>
<p>{{ obj.age }}</p>
<p>{{ obj.brand.name }}</p>
<button @click="updateName">改名字</button>
</div>
</template>
<script>
import { watch, reactive } from "vue";
export default {
setup() {
const obj = reactive({
name: "ls",
age: 10,
brand: {
id: 1,
name: "宝马",
},
})
const updateName = () => {
obj.name = 'zs'
}
watch(obj, ()=>{
console.log('数据改变了')
})
return { obj, updateName };
},
}
</script>
- 3.监听多个响应式数据数据
<template>
<div>
<p>count的值:{{count}}</p>
<button @click="add">改数据</button>
</div>
<div>
<p>{{ obj.name }}</p>
<p>{{ obj.age }}</p>
<p>{{ obj.brand.name }}</p>
<button @click="updateName">改名字</button>
</div>
</template>
<script>
import { watch, reactive, ref } from "vue";
export default {
setup() {
const count = ref(0)
const add = () => {
count.value++
}
const obj = reactive({
name: "ls",
age: 10,
brand: {
id: 1,
name: "宝马",
},
})
const updateName = () => {
obj.name = 'zs'
}
// 3. 监听多个数据的变化
watch([count, obj], ()=>{
console.log('监听多个数据改变了')
})
return { count, add, obj, updateName };
},
}
</script>
- 4.监听reactive定义的响应式数据,某一个属性
需要写成函数返回该属性的方式才能监听到
<template>
<div class="container">
<p>{{obj.name}}</p>
<p>{{obj.age}}</p>
<p>{{obj.brand.name}}</p>
<button @click="updateName">改名字</button>
</div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup () {
const obj = reactive({
name: 'ls',
age: 10,
brand: {
id: 1,
name: '宝马'
}
})
const updateName = () => {
obj.name = 'zs'
}
// 4. 此时监听对象中某一个属性的变化 例如:obj.name
// 需要写成函数返回该属性的方式才能监听到
watch(()=>obj.name,()=>{
console.log('监听obj.name改变了')
})
return { obj, updateName }
}
}
</script>
- 5.默认触发或者需要深度监听的方法
<template>
<div class="container">
<div>
<p>count的值:{{count}}</p>
<button @click="add">改数据</button>
</div>
<hr>
<div>
<p>{{obj.name}}</p>
<p>{{obj.age}}</p>
<p>{{obj.brand.name}}</p>
<button @click="updateName">改名字</button>
<button @click="updateBrandName">改品牌名字</button>
</div>
</div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup () {
const count = ref(0)
const add = () => {
count.value++
}
const obj = reactive({
name: 'ls',
age: 10,
brand: {
id: 1,
name: '宝马'
}
})
const updateName = () => {
obj.name = 'zs'
}
const updateBrandName = () => {
obj.brand.name = '奔驰'
}
// 2. 监听一个reactive数据
watch(obj, ()=>{
console.log('数据改变了')
})
watch(()=>obj.brand, ()=>{
console.log('brand数据改变了')
},{
// 5. 需要深度监听
deep: true,
// 6. 想默认触发
immediate: true
})
return {count, add, obj, updateName, updateBrandName}
}
}
</script>
组合API-ref属性
获取DOM或者组件实例可以使用ref属性,写法和vue2.0需要区分开
- 1.获取单个DOM或者组件
<template>
<div>
<div ref="dom">我是box</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue'
export default {
setup() {
// 1. 获取单个元素
// 1.1 先定义一个空的响应式数据ref定义的
// 1.2 setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定该数据即可。
const dom = ref(null);
onMounted(() => {
console.log(dom.value)
})
},
}
</script>
- 2.获取v-for遍历的DOM或者组件
<template>
<ul>
<li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li>
</ul>
</template>
<script>
import { onMounted } from 'vue'
export default {
setup() {
// 1. 获取v-for遍历的元素
// 1.1 定义一个空数组,接收所有的LI
// 1.2 定义一个函数,往空数组push DOM
const domList = []
const setDom = (el) => {
domList.push(el)
}
onMounted(()=>{
console.log(domList)
})
return { setDom }
},
}
</script>
组合API-父子通讯
- 1.父传子
- 父组件(方法和vue2基本一致都是自定义属性)
<template>
<div class="container">
<h1>父组件</h1>
<p>{{money}}</p>
<hr>
<Son :money="money" />
</div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {
name: 'App',
components: {
Son
},
// 父组件的数据传递给子组件
setup () {
const money = ref(100)
return { money }
}
}
</script>
- 子组件(子组件接收父组件数据使用props即可)
<template>
<div class="container">
<h1>子组件</h1>
<p>{{money}}</p>
</div>
</template>
<script>
import { onMounted } from 'vue'
export default {
name: 'Son',
// 子组件接收父组件数据使用props即可
props: {
money: {
type: Number,
default: 0
}
},
setup (props) {
// 获取父组件数据money
console.log(props)
}
}
</script>
子传父
- 子组件:
<template>
<div class="container">
<h1>子组件</h1>
<p>{{money}}</p>
<button @click="changeMoney">花50元</button>
</div>
</template>
<script>
import { onMounted } from 'vue'
export default {
name: 'Son',
// 子组件接收父组件数据使用props即可
props: {
money: {
type: Number,
default: 0
}
},
setup (props,{ emit }) {
// 获取父组件数据money
console.log(props.money)
const changeMoney = () => {
emit('sonSendFather',props.money/2)
}
return { changeMoney }
}
}
</script>
- 父组件:
<template>
<div class="container">
<h1>父组件</h1>
<p>{{ money }}</p>
<hr />
<Son :money="money" @sonSendFather="updataFather" />
</div>
</template>
<script>
import { ref } from "vue";
import Son from "./Son.vue";
export default {
name: "App",
components: {
Son,
},
// 父组件的数据传递给子组件
setup() {
const money = ref(100);
const updataFather = (e) => {
money.value = e;
}
return { money, updataFather };
},
}
</script>
在vue2.x的时候 .sync 除去v-model实现双向数据绑定的另一种方式
- 父传子:在setup种使用props数据 setup(props){ // props就是父组件数据 }
- 子传父:触发自定义事件的时候emit来自 setup(props,{emit}){ // emit 就是触发事件函数 }
- 在vue3.0中 v-model 和 .sync 已经合并成 v-model 指令
<Son v-model:money="money" />
组合API-依赖注入
- 使用场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据。
provide函数提供数据和函数给后代组件使用
inject函数给当前组件注入provide提供的数据和函数
父组件:
<template>
<div class="container">
<h1>父组件 {{money}} <button @click="money=1000">发钱</button></h1>
<hr>
<Son />
</div>
</template>
<script>
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {
name: 'App',
components: {
Son
},
setup () {
const money = ref(100)
console.log(money,'这是组件本身的数据' )
const changeMoney = (saleMoney) => {
console.log('changeMoney',saleMoney)
money.value = money.value - saleMoney
}
// 将数据提供给后代组件 provide
provide('money', money)
// 将函数提供给后代组件 provide
provide('changeMoney', changeMoney)
return { money }
}
}
</script>
子组件:
<template>
<div class="container">
<h2>子组件 {{money}}</h2>
<hr>
<GrandSon />
</div>
</template>
<script>
import { inject } from 'vue'
import GrandSon from './GrandSon.vue'
export default {
name: 'Son',
components: {
GrandSon
},
setup () {
// 接收祖先组件提供的数据
const money = inject('money')
console.log( money, '这是父组件传过来的数据')
return { money }
}
}
</script>
<style scoped lang="less"></style>
孙子组件:
<template>
<div class="container">
<h2>子组件 {{money}}</h2>
<hr>
<GrandSon />
</div>
</template>
<script>
import { inject } from 'vue'
import GrandSon from './GrandSon.vue'
export default {
name: 'Son',
components: {
GrandSon
},
setup () {
// 接收祖先组件提供的数据
const money = inject('money')
console.log( money, '这是父组件传过来的数据')
return { money }
}
}
</script>
<style scoped lang="less"></style>
v-model语法糖
- 在vue2.0中v-mode语法糖简写的代码
<Son :value="msg" @input="msg=$event" />
- 在vue3.0中v-model语法糖有所调整:
<Son :modelValue="msg" @update:modelValue="msg=$event" />
演示代码:
父:
<template>
<div class="container">
<!-- 如果你想获取自定义事件 -->
<!-- 如果绑定事函数 fn fn(data){ // data 触发自定义事件的传参 } -->
<!-- 如果绑定的是js表达式 此时 $event代表触发自定义事件的传参 -->
<!-- <Son :modelValue="count" @update:modelValue="count=$event" /> -->
<Son v-model="count" />
</div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {
name: 'App',
components: {
Son
},
setup () {
const count = ref(10)
return { count }
}
}
</script>
子:
<template>
<div class="container">
<h2>子组件 {{modelValue}} <button @click="fn">改变数据</button></h2>
</div>
</template>
<script>
export default {
name: 'Son',
props: {
modelValue: {
type: Number,
default: 0
}
},
setup (props, {emit}) {
const fn = () => {
// 改变数据
emit('update:modelValue', 100)
}
return { fn }
}
}
</script>
总结: vue3.0封装组件支持v-model
的时候,父传子:modelValue
子传父 @update:modelValue
补充: vue2.0的 xxx.sync
语法糖解析 父传子 :xxx
子传父 @update:xxx
在vue3.0 使用 v-model:xxx
代替。
网友评论