Vue3.0——常用的Composition API(监听属性、生命周期、Teleport、属性、自定义事件、状态驱动的动态 CSS、注册组件、uspense、 isRef等)

目录

一、常用的Composition API(组合API)

 7.监听属性

8.Vue3生命周期

1) 什么是生命周期

2)  Vue2.x中的生命周期

3) Vue3.x的生命周期

4) vue3 新增的生命周期钩子

9.Teleport

10.属性

1. 组件内部 还是可以用2.0

2.vue3组件内部组合式API setup中取属性值

3.setup语法糖中获取属性值

11.自定义事件

1)事件名

2)定义自定义事件

3)`v-model` 参数

4)多个 `v-model` 绑定

12.状态驱动的动态 CSS

13.注册组件

1)  组件内部

2)vue3组件内部组合式API setup语法糖中注册组件  

3)注册全局组件

4)定义同步组件:

5.1)定义局部异步组件:

5.2)定义全局异步组件:

13.Suspense

14. isRef   toRef   toRefs  readonly

1)isRef:

2) toRef

3) toRefs

4)readonly

15. 组合式API compostionAPI 的属性和上下文对象


一、常用的Composition API(组合API)

1.setup      2.ref函数    3.reactive函数     4.Vue3.0中的响应式原理 (面试题)

5.Vue3.0中组件的使用    6.计算属性    7.监听属性    8.Vue3.0生命周期

9.Teleport     10.自定义事件    11.状态驱动的动态css    12.Suspense

 7.监听属性

- 与vue2.x中的watch配置功能一致


- 注意
  - 监视reactive定义的响应式数据时,oldvalue无法正确获取,强制开始了深度监视(deep的配置失效)
  - 监视reactive定义的响应式数据的某一个值时:deep配置有效

注意:

1、如果将原来的引用数据,改为和原来一摸一样的引用数据,去watch,也算是改变了,所以watch也会触发

2、使用的是reactive,如果数据是一个嵌套的多层的引用数据,改变里面层的数据,是可以监听到的。但是得不到旧值。

<template>
  <div class="home">
    <h1>{
   
   {num}}</h1>
    <h1>{
   
   {msg}}</h1>
    <button @click="num++">点击num++</button>
    <button @click="addmsg()">点击msg+!</button>
  </div>
</template>
<script>
// 注意:vue2.x和vue3.x不要混用
// 1.引入
import { watch, ref,reactive } from "vue"
export default {
  data() {
    return {
    }
  },
  computed: {
  },
  setup() {
    let num = ref(0);
    let msg = ref("hello");
    let person = reactive({
        name:"李国栋",
        age:18,
        more:{
            job:"前端开发工程师",
            salary:"12k"
        }
    })
    // 1.监听ref定义的响应式数据
    watch(num, (newvalue, oldvalue) => {
      console.log("num变量", newvalue, oldvalue);
    })

    // 2.监听多个ref定义的响应式数据
    watch([num, msg], (newvalue, oldvalue) => {
      console.log("msg数据变化了", newvalue, oldvalue);
    })
    let addmsg = () => {
      msg.value += "!"
    }
    
    //3.监听reactive所定义的一个响应式数据的全部属性
    //注意:此处无法正确的获取oldvalue
    //注意:并且强制开启了深度监视(deep配置无效)
    
    watch(person, (newvalue, oldvalue) => {  //person不能写person.name,因为它是监听一个变量。那么就只有返回函数了,就是下面的4
      console.log("person数据变化了", newvalue, oldvalue);
    },{deep:false})   //即使设置了false,但是也会强制开启,所以为true
      
    //4.监听reactive所定义的一个响应式数据的某一个属性
    //这种方法一般不用
    watch(()=>person.name, (newvalue, oldvalue) => {
      console.log("person数据变化了", newvalue, oldvalue);
    },{deep:false})

    return { num, msg, addmsg }

  }
}
</script>

8.Vue3生命周期

created可以访问this了

created做网络请求的时候,页面还没出来

mounted做网络请求的时候,页面出来了

1) 什么是生命周期

  Vue中每个组件都是独立的,每个组件都有一个属于它的生命周期,从一个组件创建、数据初始化、挂载、更新、销毁、这就是一个组件所谓的生命中周期

2)  Vue2.x中的生命周期

beforeCreate   created
beforeMount    mounted
beforeUpdate  updated
beforeDestroy  destroyed
activated     deactivated   
errorCaptured 

3) Vue3.x的生命周期

在Vue3.x中,新增了一个setup生命周期函数,setup执行的时机是在beforeCreate生命函数之前执行,因为在这个函数中不能通过this来获取实例的;

同时为了命名的统一,

将beforeDestory改名为beforeUnmount,

destoryed改名为unmounted

beforeCreate(建议使用setup代替)created(建议使用setup代替)

选项式API
setup
beforeMount     mounted   
beforeUpdate    updated
beforeUnmount   unmounted

4) vue3 新增的生命周期钩子

我们可以通过在**生命周期函数**前加**on**来访问组件的生命周期

**Composition API 形式的生命周期钩子**

组合式API

onBeforeMount  onMounted   (unmounted==>app组件挂载了以后执行)
onBeforeUpdate  onUpdated
onBeforeUnmount  onUnmounted
onErrorCaptured
onRenderTracked
onRenderTriggered

effect

<script>
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  ref
} from 'vue'
 
export default {
  setup () {
    // 其他的生命周期
    onBeforeMount (() => {
	console.log("App ===> 相当于 vue2.x 中 beforeMount")
    })
    onMounted (() => {
	    console.log("App ===> 相当于 vue2.x 中 mounted")
    })
    
    // 注意,onBeforeUpdate 和 onUpdated 里面不要修改值
    onBeforeUpdate (() => {
	    console.log("App ===> 相当于 vue2.x 中 beforeUpdate")
    })
    
    onUpdated (() => {
    	console.log("App ===> 相当于 vue2.x 中 updated")
    })
    
    onBeforeUnmount (() => {
	console.log("App ===> 相当于 vue2.x 中 beforeDestroy")
    })
    
    onUnmounted (() => {
	    console.log("App ===> 相当于 vue2.x 中 destroyed")
    })
   
    return {
    }
    
  }
}
</script>

9.Teleport

Vue 鼓励我们通过将 UI 和相关行为封装到组件中来构建 UI。我们可以将它们嵌套在另一个内部,以构建一个组成应用程序 UI 的树。

然而,有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置

就是让它不要渲染到vue里面

模态弹框

to属性:放到指定位置

<template>
  <div class="reson">
    <button @click="showModel">点击弹出模态框</button>

    <teleport to="body">
      <div class="mask" v-show="isShow">
        <div class="box">
          <h1>我是模态框</h1>
          <button @click="closeModel">点击关闭模态框</button>
        </div>
      </div>
    </teleport>

  </div>
</template>

<script>
import { ref } from "vue"
export default {
  name: 'Reson',

  setup() {
    let isShow = ref(false)
    //显示
    let showModel = function () {
      isShow.value = true
    }
	//隐藏
    let closeModel = function () {
      isShow.value = false
    }
    return { isShow, showModel, closeModel }
  }

};
</script>

<style lang="scss" scoped>
.reson {
  background-color: pink;
}
.mask {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.5);
}
.box {
  width: 300px;
  height: 300px;
  background-color: aqua;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>

10.属性

1. 组件内部 还是可以用2.0

<script>
export default {
   pops:["msg"],    // pops:{msg:String}, 
   methods:{fn(){console.log(this.msg)}},
   setup(props,ctx){console.log(props.title)}    
}
< /script>
<template>
  <div>
      {
   
   {msg}}
  </div>
</template>
    

    父组件:
    <Box v-model:msg="n"></Box>

2.vue3组件内部组合式API setup中取属性值

<script>
export default {
   pops:["msg","count"],// pops:{msg:String}, 
   setup(props){
       let fn=()=>{console.log(props.msg,props.count)}//必须在组件中注册属性不然setup函数收不到数据
       return {fn}
   }    
}
< /script>
<template>
  <div>
     <p> {
   
   {msg}}</p>
      <button @click="fn">look</button>
  </div>
</template>
    

    父组件:
    <Box :msg="n" :count="200"></Box>

3.setup语法糖中获取属性值

defineProps定义属性

<script setup>
    import 	{defineProps} from "./Box1.vue"    //注意3.2之后不用引入可以直接使用
    let obj=defineProps(["msg","count"])   //它是props对象
    let fn=()=>{console.log(obj.msg,obj.count)}         
}
< /script>
<template>
  <div>
     <p> {
   
   {obj.msg}}</p>
      <button @click="fn">look</button>
  </div>
</template>
    

    父组件:
    <Box :msg="n" :count="200"></Box>

11.自定义事件

1)事件名

defineEmit 3.2之前

useContext  废弃了,useContext函数的返回值又{emit,attr}

defineEmits  3.2之后

与组件和 prop 一样,事件名提供了自动的大小写转换。如果在子组件中触发一个以 camelCase (驼峰式命名) 命名的事件,你将可以在父组件中添加一个 kebab-case (短横线分隔命名) 的监听器。

//父组件HomeView
<template>
  <div>
    <MyBox1 @myclick="fn" @my-event="fm"></MyBox1>
  </div>

</template>

<script setup>
import MyBox1 from "../components/MyBox1.vue"

let fn = (arg) => {
  console.log(6666, arg)
}

let fm = (arg) => {
  console.log(77777, arg);
}

</script>

//子组件MyBox1
<template>

  <div @mousemove="change1">
    <button @click="change">点击触发myevent事件</button>
  </div>

</template>

<script >

export default {

  methods: {
    change() {
      this.$emit('myclick', "helo666");
    },
    change1() {
      this.$emit('myEvent', "121212");

    }
  },

}
</script>

2)定义自定义事件

​        可以通过 `emits` 选项在组件上定义发出的事件

//父组件
<HomeView @my-event="fn" @my-submit="fn1"></HomeView>

//子组件
<template>
	<div @mouseenter="fm">
		<button @click="fn">点我触发mybtn组件内部的myclick事件</button>		
	</div>
</template>

<script>
	export default {
		emits:["myEvent","myclick"],
		methods:{
			fn(){
				this.$emit("myClick",200)
			},
			fm(){
				this.$emit("click",300)
			}
		}
		
	}
</script>

3)`v-model` 参数

//父组件
<HomeView v-model:title="bookTitle"></HomeView>

//子组件
//1.接收参数
props:["title"]
//2.定义事件
emits: ['update:title']
//3.触发事件
this.$emit("update:title","子组件传递给父组件的值")

4)多个 `v-model` 绑定

//2.0这样写会有矛盾
<MyVmodel v-model="msg" v-model="msg2" v-model="msg3"></MyVmodel> 
		
//2.0应该这样写:
<MyVmodel 
	v-model="msg" 
	:msg2="msg2" @changemsg2="changemsg2" 
	:msg3="msg3" @changemsg3="changemsg3">
</MyVmodel>
js: 
changemsg2(arg){this.msg2=arg}
changemsg3(arg){this.msg3=arg}
		
		
//3.0
<MyVmodel v-model="msg" v-model:msg2="msg2" v-model:msg3="msg3"></MyVmodel> 

//父组件
<user-name
  v-model:msg1="msg1"
  v-model:msg2="msg2"
></user-name>

//子组件
//1.接收参数
props:["msg1","msg2"]
//2.定义事件
emits: ['update:msg1','update:msg2']
//3.触发事件
this.$emit('update:msg1',"子组件传递给父组件的值1")
this.$emit('update:msg2',"子组件传递给父组件的值2")

APP.vue

<script setup>
import {ref} from "vue"
import Box from "./Box.vue"
let msg1=ref("111")
let msg2=ref("222")
let msg3=ref("333")
</script>
<template>
    <div>
        <p>{
   
   {msg1}}--{
   
   {msg2}}--{
   
   {msg3}}</p>
        <Box v-model:value="msg1" v-model:value2="msg2" v-model:value3="msg3"></Box>
        
    </div>
</template>

Box.vue

<script setup>
let obj = defineProps(["value", "value2", "value3"]);
let emit = defineEmits();
let fn = () => {
  emit("update:value", 100);
  emit("update:value2", 200);
  emit("update:value3", 300);
};
</script> 
<template>
  <div>
    <p>{
   
   { obj.value }}-{
   
   { obj.value2 }}--{
   
   { obj.value3 }}</p>
    <button @click="fn">box2-change1</button>
  </div>
</template>

12.状态驱动的动态 CSS

单文件组件的 <style> 标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上

<template>
  <div class="box1">hello</div>
  <button @click="changcolor">修改box1的样式</button>
  <div class="box2">hello66666</div>
  <button @click="changother">修改box2的样式</button>
</template>

<script setup>

import { ref, reactive } from "vue"


let color = ref("red")
let changcolor = () => {
  color.value = "blue"
}

let other = reactive({
  width: "200px",
  height: "100px"
})

let changother = () => {
  other.width = "400px"
}

</script>

<style lang="scss" scoped>
.box1 {
  color: v-bind('color');
}

.box2 {
  background-color: yellow;
  width: v-bind('other.width');
  height: v-bind('other.height');
}
</style>

学习——面试题/笔试题:css语法中的变量

13.注册组件

7种方式,最常用的是第二种

1)  组件内部

<script>
    import Box1 from "./Box1.vue"
    export defult{
        components:{
            Box1
        },
        setup(){}
    }
</script>
<template>
    <Box1></Box1>	
< /template>

2)vue3组件内部组合式API setup语法糖中注册组件  

<script setup>
    import Box1 from "./Box1.vue"  
    //只需要导入 不用写注册代码  会在打包的时候自动帮我们注册 
</script>
<template>
    <Box1></Box1>	
< /template>

3)注册全局组件

//main.js文件:
import { createApp} from 'vue'
import 3.注册全局组件App from './App.vue'
const app=createApp(App)

import Box1 from "./Box5.vue"
app.component(Box1.name,Box1)

app.mount('#app')//注意 一定要在app.mount之前注册全局组件 否则使用不了

//App.vue文件:
<template>
    <Box1></Box1>	
< /template>

4)定义同步组件:

//Box1.vue文件:
<script>
  import {defineComponent} from "vue"
  export default defineComponent({
		data(){
			return {}
		},
		methods:{},		
		setup(){
		}		
	});
</script>

5.1)定义局部异步组件:

组件内部    

<script>
	import {defineAsyncComponent} from "vue"
	let Box1 = defineAsyncComponent(() => import("./Box1.vue")) //注意3.2之后不用引入defineAsyncComponent
	export default {
		components: {
			Box1
		},
		setup() {}
	}
</script>

setup语法糖:

<script setup>
		import 	Box1 from "./Box1.vue"
		import 	Box2 from "./Box2.vue"
		import {defineAsyncComponent} from "vue"
		let Box3=defineAsyncComponent(()=>import("./Box3.vue"))//注意3.2之后不用引入defineAsyncComponent,而且这个变量名直接就是注册的组件名(打包时自动注册的)
</script>

5.2)定义全局异步组件:

//main.js文件:
import { createApp,defineAsyncComponent} from 'vue'
import App from './App.vue'
const app=createApp(App)
let Box1=defineAsyncComponent(()=>import("./Box4.vue"))
app.component("Box1",Box1)
app.mount('#app')//注意 一定要在app.mount之前注册全局组件 否则使用不了

13.Suspense

- 等待异步组件时渲染一些额外的内容,让应用有更好的用户体验

  `<suspense>` 组件有两个插槽。它们都只接收一个直接子节点。`default` 插槽里的节点会尽可能展示出来。如果不能,则展示 `fallback` 插槽里的节点。

<template>
  <div class="fa">
    <h1>父组件HomeView</h1>

    <!-- <Helloworld></Helloworld> -->
    <suspense>
      <template #default>   
<!--#是v-slot:default的语法糖-->
        <MyChild></MyChild>
      </template>
      <template #fallback>
        <div>
          <h1> 正在加载中Loading...</h1>
        </div>
      </template>
    </suspense>
  </div>
</template>

<script setup>
import { defineAsyncComponent } from "vue"
// import Helloworld from "../components/HelloWorld.vue"  //静态引用

let MyChild = defineAsyncComponent(() => import("../components/HelloWorld.vue")) //异步引入

</script>

<style lang="scss" scoped>
.fa {
  height: 300px;
  background-color: #ccc;
}
</style>

14. isRef   toRef   toRefs  readonly

1)isRef:

isRef(msg)==> 判断msg是否为响应式的,返回值是布尔值

<script setup>
//案例一
import { ref, isRef } from "vue";
let msg = ref(0);
let msg2 = 1;
function fn() {
  console.log(isRef(msg));  //true
  msg.value++;
}
function fm() {
  console.log(isRef(msg2));  //false
  msg2++;
}
</script>
<template>
  <div>
    <p>{
   
   { msg }}</p>
    <button @click="fn">msg</button>
    <p>{
   
   { msg2 }}</p>
    <button @click="fm">msg2</button>
  </div>
</template>

2) toRef

let x=toRef(obj,"x")  //隐式: let x=ref(obj.x),并且响应到obj对象去

<script setup>
//案例一
import { ref, isRef ,toRef,reactive} from "vue";
//toRef
let obj=reactive({x:20,y:30})
let x=toRef(obj,"x")
let change=function() {
  x.value=200
  console.log(11,x,111,obj.x)
}
</script>
<template>
  <div>
    <!-- toRef -->
    <p>{
   
   {obj.x}}----{
   
   {x}}</p>
    <button @click="change">点击改变x</button>
  </div>
</template>

3) toRefs

普通对象结构,响应式数据解构

let {x,y}=toRefs(obj)

<script setup>
//案例一
import { ref, isRef ,toRef,reactive,toRefs} from "vue";
//toRefs
let obj2=reactive({a:1,b:2})
let {a,b}=toRefs(obj2)
function change2(){
  a.value++
  b.value++
  console.log(a.value,1111,b.value)
}
</script>
<template>
  <div>
    <!-- toRefs -->
    <p>{
   
   { a }}---{
   
   { obj2.a }}--{
   
   { b }}---{
   
   { obj2.b }}</p>
    <button @click="change2">点击改变a,b</button>
  </div>
</template>

4)readonly

响应式只读技术,只能读,不能改

obj3是响应式的,obj4是响应式的,而且关联  obj3是可读可写,obj4只可读

<script setup>
//案例一
import { ref, isRef ,toRef,reactive,toRefs, readonly} from "vue";
//readonly
let obj3=reactive({x:1,y:2})
let obj4=readonly(obj3)
console.log(obj3.x,obj4.x)
function change4(){  //这里就会报警告说,obj4是只读,不能修改
  obj3.x=2
  obj4.x=4
}

</script>
<template>
  <div>
    <!-- readonly -->
    <p>{
   
   {obj3.x}}---{
   
   {obj4.x}}</p>
    <button @click="change4">点击修改</button>
  </div>
</template>

15. 组合式API compostionAPI 的属性和上下文对象

//Vue2.0组件内部接收外部数据时:
<script>
export default {
  props: ["msg"], //props:{msg:String},
  inject:["count"]  //父组件提供provide:{count:200}
};

//Vue3.0
//第一种
export default {
  props: ["msg"], //props:{msg:String},
  inject:["count"]  //父组件提供provide:{count:200}
};
//第二种 在compositionAPI
export default {
	setup(props,ctx) {
		//props:父祖家给子组件的属性传值
		//ctx:代表Vue提供的功能:emit、inject等等
		//this用不了
        function btnckicked(){
            ctx.emit("myevent",10)  //触发父组件的事件
        }

	}
};
</script>

//第三种:在compositionAPI 语法糖
<script setup>
//版本3.0到3.2
import {defineprops} from "vue"
let obj=defineprops(["title"])
console.log(obj.title)

//3.2

//3.2以后
let obj=defineprops(["title"])
console.log(obj.title)
</script>

猜你喜欢

转载自blog.csdn.net/qq_52301431/article/details/126897306
今日推荐