vue3的学习【超详细】

目录

  • 一、vue3的优点
    • 1、vue3的优点
  • 二、常用的API
    • 1、setup(Composition API)
    • 2、生命周期(Composition API)
    • 3、ref函数和reactive函数用法和区别(Composition API)
      • 1、ref
      • 2、reactive
      • 3、ref和reactive的区别
    • 4、计算属性(computed)和侦听属性(watch)(Composition API)
      • 1、computed
      • 2、watch
    • 5、nextTick(全局API)
    • 6、props(选项式API)
      • 1、非ts语法
      • 2、ts语法
    • 7、toRefs(Composition API)
    • 8、vue3中的响应式原理
      • 1、vue2中的响应式原理
      • 2、vue3中的响应式原理
    • 总结
    • 9、自定义指令
      • 1、什么是指令
      • 2、怎么实现
      • 3、应用场景
    • 10、自定义修饰符
    • 11、vue的vueuse库(工具库)
  • 三、新组件和新属性
    • 1、v-bind(内置内容)
    • 2、teleport 传送门
    • 3、Suspense

一、vue3的优点

1、vue3的优点

1、源码体积得到优化:
(1) API减少,移除一些冷门API,如filter、inline-template等;
(2)引入tree-shaking 减少打包体积;

2、源码的升级:
(1)Vue3使用Proxy进行数据劫持,可以很好的规避vue2使用Object.defineProperty进行数据劫持带来的缺陷;

3、拥抱TypeScript:
(1) 更好的支持Ts(typescript)

4、高级给与:
(1)暴露了更底层的API和提供更先进的内置组件;

5、 组合API(Composition API):
(1) 能够更好的组织逻辑,封装逻辑,复用逻辑;

二、常用的API

1、setup(Composition API)

1、setup是vue3中的一个全新的配置项,值为一个函数;

2、setup是所有CompositionAPI(组合API)的基础,组件中所用到的数据、方法等都需要在setup中进行配置;
(1):若返回一个对象,则对象中的属性、方法,均可以在模板中直接使用;

(2):若返回一个渲染函数:则可以自定义渲染内容;

setup的两个注意点:

1、setup执行时机,在beforeCreate之前执行一次,this是undefined;

2、setup的参数:

(1):props:指为对象,包含组件外部传递过来,且组件内部声明接收了的属性。

(2):context:上下文对象

attrs:值为对象,包含组件外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs;

slots:收到的插槽内容,相当于this.$slots;

emit:分发自定义事件的函数,相当于this.$emit。

2、生命周期(Composition API)

vue3中的生命周期和vue2的区别:
beforeCreate=>setup()(创建实例前)

created=>setup() (创建实例后)

beforeMount=>onBeforeMount ( 挂载DOM前)

mounted=>onMounted ( 挂载DOM后)

beforeUpdate=>onBeforeUpdate (更新组件前)

updated=>onUpdated (更新组件后)

beforeUnmount=>onBeforeUnmount (卸载销毁前)

unmounted=>onUnmounted (卸载销毁后)

3、ref函数和reactive函数用法和区别(Composition API)

1、ref

特点

(1)ref的参数一般是基本数据类型,也可以是对象类型

(2)如果参数是对象类型,其实底层的本质还是reactive,系统会自动将ref转换为reactive,例如
==ref(1) => reactive({value:1})=
(3)在模板中访问ref中的数据,系统会自动帮我们添加.value,在JS中访问ref中的数据,需要手动添加.value

(4)ref的底层原理同reactive一样,都是Proxy


<script setup>
import { ref } from 'vue'
 
const count = ref(0)
 
function increment() {
  count.value++
}
</script>
 
<template>
  <button @click="increment">
    {{ count }} <!-- 无需 .value -->
  </button>
</template>

2、reactive

特点
(1)reactive的参数一般是对象或者数组,他能够将复杂数据类型变为响应式数据。

(2)reactive的响应式是深层次的,底层本质是将传入的数据转换为Proxy对象


<template>
  <h2>名称:{{name.title}}</h2>
  <h2>主要爱好:{{job.hobby[0].type}}</h2>
  <button @click="changeName">修改姓名和爱好</button>
</template>
<script>
import { ref,reactive } from 'vue' // 按需引入ref函数
export default {
  name: 'App',
  setup () {
    let name = ref({ // ref定义对象类型响应式变量
      title:'赵丽颖'
    }) 
    let job = reactive({ // reactive定义对象类型响应式变量
      type:'演员',
      hobby:[
        {
          type:'演戏',
          degree:'✨✨✨✨✨'
        },
        {
          type:'看书',
          degree:'✨✨✨'
        }
      ],
    })
    function changeName () {
      console.log('name',name)
      name.value.title = '刘亦菲' // 对ref定义的响应式数据进行操作,需要使用.value
      console.log('job',job.hobby[0])
      job.hobby[0].type = '运动' // 对reactive定义的响应式数据进行操作,无需使用.value,且是深层次响应 
      console.log('job',job.hobby[0])
    }
    // 将变量和函数返回,以便在模版中使用
    return {
      name,
      job,
      changeName
    }
  }
}
</script>

3、ref和reactive的区别

1、从定义数据角度对比:

ref用来定义:基本数据类型;

reactive用来定义:对象(或数组)类型数据;

备注:ref也可以用来定义对象或数组类型数据,它内部会自动通过reactive转为代理对象;

2、从原理角度对比:

ref通过Object.defineProperty()的get和set来实现响应式;

reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据。

3、从使用角度对比:

ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value;

reactive定义的数据:操作数据与读取数据均不需要.value;

4、计算属性(computed)和侦听属性(watch)(Composition API)

computed和watch都是vue框架中的用于监听数据变化的属性,都能在数据改变时,针对改变的相关数据做成相应的变化

1、computed

(1)计算属性的优点:
计算属性是基于缓存来实现的,无论你后端调用十次还是几百次,只要计算属性依赖的相关值没有发生变化,那计算属性就可以通过缓存读取。例子如下:

<script setup lang="ts">
import { reactive, computed } from "vue"


const allName = reactive({
  userName1:'小',  //姓
  userName2:'明',   //名
  age:20,
})
const userName = computed(()=>{
  console.log("我是计算属性调用的");
  return allName.userName1 +
    allName.userName2+"年龄"+allName.age
})
 
const userAllName = function(){
 console.log("我是方法调用的");
 return allName.userName1 + allName.userName2+"年龄"+allName.age
}

</script>

<template>
 
<!--下面是通过方法得出的名字-->
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
  <div>{{userAllName()}}</div>
 
<!--下面是通过计算属性得出的名字-->
  <div>{{userName}}</div>
  <div>{{userName}}</div>
  <div>{{userName}}</div>
  <div>{{userName}}</div>
  <div>{{userName}}</div>
  <div>{{userName}}</div>
  <div>{{userName}}</div>
</template>

从上面对应的浏览器中打印的我们可以看出,方法和计算属性调用了八次,但是与方法不一样的是,计算属性就打印了一次,就好像就第一次调用了这个函数一样,后面就没调用了。这就是计算属性的缓存,只要其依赖的值不发生相关的变化,那么无论你计算属性调用了好多次,但最终就只是执行一次。
在这里插入图片描述
(2)可写的计算属性
当计算属性是只读的,你试着修改他的话,会收到一个警告,例如:

<script setup lang="ts">
import { ref, computed } from "vue"

const count = ref(1)
const plusOne = computed(() => count.value + 1)

plusOne.value++

</script>

<template>
  <div>
    <p>{{ count }}</p>
    <p>{{ plusOne }}</p>
  </div>
</template>

值既没有发生变化还会得到警告,如图:

在这里插入图片描述

正确的可写计算属性代码如下:

<script setup lang="ts">
import { ref, computed } from "vue"

const count = ref(1)
/*利用get和set函数*/
const plusOne = computed({
  get: () => count.value + 1, 
   set: (val) => {
    count.value = val - 1
  }
})

plusOne.value++
</script>

<template>
  <div>
    <p>{{ count }}</p>
    <p>{{ plusOne }}</p>
  </div>
</template>

结果如图:
在这里插入图片描述

2、watch

默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。

第一个参数是侦听器的源。这个来源可以是以下几种:

一个函数,返回一个值
一个 ref
一个响应式对象
…或是由以上类型的值组成的数组

第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。
第三个可选的参数是一个对象,支持以下这些选项:

immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined。
deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。
flush:使侦听器在侦听器回调中能访问被 Vue 更新之后的DOM。

<script setup lang="ts">
import { ref, watch } from "vue"

const count = ref(0)

/**
 * 挑战 1: Watch 一次
 * 确保副作用函数只执行一次
 * 使用stopWatch停止侦听器
*/
const stopWatch=watch(count, () => {
  console.log("Only triggered once")
  stopWatch()
})
count.value = 1
setTimeout(() =>{ count.value = 2})

/**
 * 挑战 2: Watch 对象
 * 确保副作用函数被正确触发
 * 使用deep深层次监听
*/
const state = ref({
  count: 0,
})

watch(state, () => {
  console.log("The state.count updated")
},{
      deep:true,
      })

state.value.count = 2

/**
 * 挑战 3: 副作用函数刷新时机
 * 确保正确访问到更新后的`eleRef`值
 * 一般侦听器是在Vue组件更新之前被调用,所以要使用flush访问被Vue更新后的DOM
*/

const eleRef= ref()
const age = ref(2)
watch(age, () => {
  console.log(eleRef.value)
},{ flush: 'post'})
age.value = 18

</script>

<template>
  <div>
    <p>
      {{ count }}
    </p>
    <p ref="eleRef">
      {{ age }}
    </p>
  </div>
</template>

watch和watchEffect
相同点
1、两者都可以监听data属性变化
2、watch 与 watchEffect 在手动停止侦听、清除副作用 (将 onInvalidate 作为第三个参数传递给回调)、刷新时机和调试方面有相同的行为。

区别
1、watch不加immediate初始值监听不到,watchEffect一开始就能监听到;
2、watch需要明确监听哪个属性;
3、watchEffect会根据其中的属性,自动监听其变化;
4、watcheffect初始化时,一定会执行一次(收集要监听的数据,不然不知道监听的是什么),watch只有你设置了初始化监听才会监听;
5、watchEffect获取不到更改前的值,而watch可以同时获取更改前和更改后的值;

<script setup lang="ts">
import {ref,reactive,watch,watchEffect} from 'vue'
			//数据
			let sum = ref(0)
			let person = reactive({
				name:'张三',
				age:18,
				job:{
					j1:{
						salary:20
					}
				}
			})

			//监视
			
            /*watch(sum,(newValue,oldValue)=>{
				console.log('sum的值变化了',newValue,oldValue)
			},{immediate:true})*/ 

			watchEffect(()=>{
				const x1 = sum.value
				const x2 = person.job.j1.salary
				console.log('watchEffect所指定的回调执行了')
			})
      function add(){
       sum.value=sum.value+1
      }
		
</script>
<template>
  <div>
    <p>
      {{sum}}
    </p>
    <button @click="add">
      点我加一
    </button>
  </div>
</template>

在这里插入图片描述

5、nextTick(全局API)

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM,例子

<script setup>
import { ref,nextTick } from "vue"

const count = ref(0)
const counter = ref(null)

async function increment(){
  count.value++
  console.log(counter.value.textContent )
  await nextTick()
  console.log(+counter.value.textContent ===1,counter.value.textContent )
}
</script>

<template>
  <button ref="counter" @click="increment">
    {{ count }}
  </button>
</template>

在这里插入图片描述

6、props(选项式API)

主要用在组件的父组件向子组件的传值,主要有两大类ts语法和非ts语法
default:默认值;
type:类型;
required:是否必传;
validator:props验证;

1、非ts语法

const props = defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true
  },
  // Number 类型的默认值
  propD: {
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propE: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  },
  // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})

2、ts语法

interface Props {
    // id
    id:string
    // 宽度
    width: number,
    // 高度?:
    height?: number,
    // 是否初始化
    init?: boolean,
    // 子项
    list?: Array<ganttChartItem>,
    // 是否显示描述
    desc?:string
    // 描述颜色
    descColor?:string
}
const props = withDefaults(defineProps<Props>(), {
    // 高度默认20
    height: 20,
    // 默认初始化
    init: true,
    // 子项默认为空
    list: () => [],
    // 是否显示描述
    desc: '',
    // 描述颜色
    descColor: ''
});

通过定义interface接口来规范props的属性的格式
?:表示可选属性
定义默认属性值时需要使用withDefaults

7、toRefs(Composition API)

toref函数和toref函数与ref函数的区别:

toRef 函数会与源数据交互,修改响应式数据会造成源数据的修改,但是他的修改不会造成视图层数据的更新;

ref 函数可以将对象里面的属性值变成响应式的数据,修改响应式数据,是不会影响到源数据,但是视图层上的数据会被更新

为啥要使用toRefs函数,原因:

Vue.js中,我们同样解构/扩展“响应式”对象,但它会失去响应性。toRefs函数才能保证解构/扩展不丢失响应性

一般都会使用toRefs函数而不是toRef函数,原因:

(1)toRefs 函数用于批量设置多个数据为相应是数据。

(2)toRefs 函数还可以与其他响应式数据相交互,更加方便处理视图层数据。

toRef函数的使用

//toRef 函数有两个参数
toRef(操作对象, 对象属性)

toRefs函数的使用

<script setup lang="ts">
import { reactive ,toRefs } from "vue"

function useCount() {
  const state = reactive({
    count: 0,
  })

  function update(value: number) {
    state.count = value
  }

  return {
     ...toRefs(state),
    update,
  }
}

// Ensure the destructured properties don't lose their reactivity  ...toRefs(state)
const {  count , update } =useCount()

</script>

<template>
  <div>
    <p>
      <span @click="update(count-1)">-</span>
      {{ count }}
      <span @click="update(count+1)">+</span>
    </p>
  </div>
</template>

8、vue3中的响应式原理

1、vue2中的响应式原理

基本原理

vue2利用的是原生js下边的Object.defineProperty()进行数据劫持,在通过里面的getter和
setter方法,进行查看和数据的修改,通过发布、订阅者模式进行数据与视图的响应式。

let person = {
            name:'路飞',
            age:18
        }

let p = {}
Object.defineProperty(p, "name", {
    get(){      //有人读取name时调用
        return person.name;
    },
    set(value){      //有人修改name时调用
        console.log("有人修改了name属性")
        person.name = value
    }
});

Object.defineProperty(p, "age", {
    get(){      //有人读取age时调用
        return person.age;
    },
    set(value){      //有人修改age时调用
        console.log("有人修改了age属性")
        person.age = value
    }
});

在这里插入图片描述
vue2给对象增加和修改新属性用 $set;
vue2想删除已有的属性可以用 $delete;

2、vue3中的响应式原理

基本原理

1、对于基本数据类型来说,响应式依然是靠Object.defineProperty()的get和set来完成的

2、对于对象类型的数据:

通过Proxy代理:拦截对象中任意属性的变化,包括属性值得读写、添加、删除等操作等…
通过Reflect反射函数进行操作

new Proxy(data,{
  //拦截读取属性值
  get(target, prop){
    return Reflect.get(target, prop)
  },
  //拦截设置属性值或添加新属性
  set(target, prop, value){
    return Reflect.set(target, prop, value)
  },
  //拦截删除属性
  deleteProperty(target, prop){
    return Reflect.deleteProperty(target, prop)
  }
})

总结

在Vue2中,数据响应式主要借助Object.defineProperty()来实现,存在的缺陷是无法操作数据的增加和删除,在Vue3中,数据响应式主要借助proxy和Reffect配合实现,可以做到实现数据的增删改查。

9、自定义指令

1、什么是指令

指令系统是计算机硬件的语言系统,也叫机器语言,它是系统程序员看到的计算机的主要属性。因此指令系统表征了计算机的基本功能决定了机器所要求的能力

在vue中提供了一套为数据驱动视图更为方便的操作,这些操作被称为指令系统

我们看到的v- 开头的行内属性,都是指令,不同的指令可以完成或实现不同的功能

除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令

指令使用的几种方式:

//会实例化一个指令,但这个指令没有参数
v-xxx

// – 将值传到指令中
v-xxx="value"

// – 将字符串传入到指令中,如v-html="'<p>内容</p>'"
v-xxx="'string'"

// – 传参数(arg),如v-bind:class="className"
v-xxx:arg="value"

// – 使用修饰符(modifier
v-xxx:arg.modifier="value"

2、怎么实现

注册一个自定义指令有全局注册与局部注册

全局注册注册主要是用过Vue.directive方法进行注册

Vue.directive第一个参数是指令的名字(不需要写上v-前缀),第二个参数可以是对象数据,也可以是一个指令函数

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()  // 页面加载完成之后自动让输入框获取到焦点的小功能
  }
})

局部注册通过组件options选项中设置directive属性

directives: {
  focus: {
    // 指令的定义
    inserted: function (el) {
      el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
    }
  }
}

使用新自定义指令

  <input v-focus="state" type="text">

指令钩子

const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}

钩子参数
指令的钩子会传递以下几种参数:

el:指令绑定到的元素。这可以用于直接操作 DOM。

binding:一个对象,包含以下属性。

(1)value:传递给指令的值。例如在 v-my-directive=“1 + 1” 中,值是 2。
(2)oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。
(3)arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 “foo”。
(4)modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }。
(5)instance:使用该指令的组件实例。
(6)dir:指令的定义对象。
vnode:代表绑定元素的底层 VNode。

prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。

3、应用场景

例子一:自定义防抖点击指令

<script setup lang='ts'>
/**
 * 实现以下自定义指令
 * 确保在一定时间内当快速点击按钮多次时只触发一次点击事件
 * 你需要支持防抖延迟时间选项, 用法如 `v-debounce-click:ms`
 *
*/
const VDebounceClick = {
beforeMount(el, binding, vnode, prevVnode) {
  let s = binding.arg * 1
    let timer
    el.addEventListener('click', () => {
      if (timer) {
        clearTimeout(timer)
      }
      timer = setTimeout(() => {
        binding.value(s)
      }, s)
    })
},
}

function onClick() {
  console.log("Only triggered once when clicked many times quickly")
}

</script>

<template>
  <button v-debounce-click:1000="onClick">
    Click on it many times quickly
  </button>
</template>

例子二:自定义获取焦点指令

<script setup lang='ts'>
import { ref } from "vue"

const state = ref(false)

/**
 * 实现一个自定义指令,让元素获取焦点
 * 确保当切换`state`时,元素随着状态值获取/失去焦点
 *
*/
const VFocus = {
   updated:(el)=>{
     if(state.value){
       el.focus() 
     }else{
       el.blur()
     }
   }
}

setInterval(() => {
  state.value = !state.value
}, 2000)

</script>

<template>
  <input v-focus="state" type="text">
</template>

例子三:一键copy功能

import { Message } from 'ant-design-vue';
 
const vCopy = { //
  /*
    bind 钩子函数,第一次绑定时调用,可以在这里做初始化设置
    el: 作用的 dom 对象
    value: 传给指令的值,也就是我们要 copy 的值
  */
  bind(el, { value }) {
    el.$value = value; // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到
    el.handler = () => {
      if (!el.$value) {
      // 值为空的时候,给出提示,我这里的提示是用的 ant-design-vue 的提示,你们随意
        Message.warning('无复制内容');
        return;
      }
      // 动态创建 textarea 标签
      const textarea = document.createElement('textarea');
      // 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
      textarea.readOnly = 'readonly';
      textarea.style.position = 'absolute';
      textarea.style.left = '-9999px';
      // 将要 copy 的值赋给 textarea 标签的 value 属性
      textarea.value = el.$value;
      // 将 textarea 插入到 body 中
      document.body.appendChild(textarea);
      // 选中值并复制
      textarea.select();
      // textarea.setSelectionRange(0, textarea.value.length);
      const result = document.execCommand('Copy');
      if (result) {
        Message.success('复制成功');
      }
      document.body.removeChild(textarea);
    };
    // 绑定点击事件,就是所谓的一键 copy 啦
    el.addEventListener('click', el.handler);
  },
  // 当传进来的值更新的时候触发
  componentUpdated(el, { value }) {
    el.$value = value;
  },
  // 指令与元素解绑的时候,移除事件绑定
  unbind(el) {
    el.removeEventListener('click', el.handler);
  },
};
 
export default vCopy;

10、自定义修饰符

主要是用来进行数据表单的双向绑定的
添加到组件 v-model 的修饰符将通过 modelModifiers prop 提供给组件。
下面是自定义修饰符capitalize,自动将 v-model 绑定输入的字符串值首字母转为大写:
父组件:

<template>
    <div>
        <Renderer v-model.capitalize="data"/> {{modelValue}}
    </div>
</template>

<script setup>
import  Renderer from  "./Comp.vue";
import { ref } from "vue";
   const  data = ref('');
</script>

子组件:

<script setup>
  import {ref} from 'vue'
const props = defineProps({
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
});
const emit = defineEmits(['update:modelValue']);
const updateValue = (e) => {
  let value=e.target.value
   // console.log('oooo',props.modelModifiers)
    if (props.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1)
    //  console.log(value,'pplplp')
    }
    emit('update:modelValue',value);
}
</script>

<template>
  <input type="text" :value="modelValue" @input="updateValue" />
</template>

11、vue的vueuse库(工具库)

vueuse工具库链接

1、实现一个计数器

<script setup lang='ts'>
import { ref } from 'vue'
interface UseCounterOptions {
  min?: number
  max?: number
}

/**
 * 实现计数器函数,确保功能正常工作
 * 1. 加 (+)
 * 2. 减 (-)
 * 3. 重置 
 * 4. 最小值 & 最大值 选项支持
*/
function useCounter(initialValue = 0, options: UseCounterOptions = {}) {
 const count = ref(initialValue)
  const {max, min} = options
  const inc = () => count.value = Math.min(max, count.value + 1)
  const dec = () => count.value = Math.max(min, count.value - 1)
  const reset = () => (count.value = initialValue)

  return { count, inc, dec, reset }
}

const { count, inc, dec, reset } = useCounter(0, { min: 0, max: 10 })

</script>

<template>
  <p>Count: {{ count }}</p>
  <button @click="inc">
    inc
  </button>
  <button @click="dec">
    dec
  </button>
  <button @click="reset">
    reset
  </button>
</template>

2、实现一个切换状态的可组合函数

<script setup lang='ts'>
import { ref } from 'vue'
/**
 * 实现一个切换状态的可组合函数
 * 确保该功能正常工作
*/
function useToggle(state: boolean): [boolean, () => void] {
                                     
 const status = ref(state);
  const toggle = () => (status.value = !status.value);
  return [status, toggle];
}

const [state, toggle] = useToggle(false)

</script>

<template>
  <p>State: {{ state ? 'ON' : 'OFF' }}</p>
  <p @click="toggle">
    Toggle state
  </p>
</template>

三、新组件和新属性

1、v-bind(内置内容)

Vue3中的新增的v-bind()的常用使用方式,主要包括在css,less,scss中的使用

<script setup>
import { ref } from "vue"
const theme = ref("red")

const colors = ["blue", "yellow", "red", "green"]
const width=200
const style={
  height:'50px'
}
setInterval(() => {
  theme.value = colors[Math.floor(Math.random() * 4)]
}, 1000)

</script>
<template>
  <p>hello</p>
</template>

<style scoped>
/* 修改以下代码绑定动态颜色 */
p {
  color: v-bind(theme);
  line-height: v-bind('style.height');
  border:solid;
  width: v-bind(width+'px');
}
</style>

2、teleport 传送门

能将插槽内容渲染到 DOM 中的另一个指定位置。

<script setup>

const msg = "Hello World"

</script>

<template>
  <!-- to='移动到指定DOM里'-->
  <teleport  to="body">
  	<span>{{ msg }}</span>
  </teleport>
</template>

3、Suspense

允许应用程序在等待异步组件时渲染一些其它内容,让用户有一个更好体验。
使用步骤:

1、异步引入组件;

import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))

2、使用Suspense包裹组件,并配置好default 与 fallback
(1) 插槽包裹异步组件;
(2) 插槽包裹渲染异步组件渲染之前的内容;

<template>
    <div class="app">
        <h3>我是App组件</h3>
        <Suspense>
            <template v-slot:default>
                <Child/>
            </template>
            <template v-slot:fallback>
                <h3>加载中.....</h3>
            </template>
        </Suspense>
    </div>
</template>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/20879.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JAVA】this关键字和static关键字

目录 1.this关键字 2.static关键字 容易混淆的问题 1.this关键字 一个对象一个this。this是一个变量&#xff0c;是一个关键字&#xff0c;是一个引用。this保存当前对象的内存地址&#xff0c;指向自身。所以&#xff0c;严格意义上来说&#xff0c;this代表的就是“当前对象…

顶象助力如祺出行打造高品质服务

近日&#xff0c;广东省自然资源厅审批通过了如祺出行提交的测绘资质申请&#xff0c;如祺出行获得地理信息系统工程和互联网地图服务两个专业的乙级测绘资质。此次获批意味着&#xff0c;如祺出行能够在许可区域内依法合规开展数据标注和场景仿真等相关业务&#xff0c;构建全…

【Spring框架全系列】第一个Spring程序

&#x1f3d9;哈喽&#xff0c;大家好&#xff0c;我是小浪。那么从今天开始&#xff0c;我就要开始更新spring框架全系列的博客了&#xff1b;本专栏免费阅读&#xff0c;最好能够点个订阅&#xff0c;以便于后续及时收到更新信息哈&#xff01;&#x1f3df; &#x1f4f2;目…

全网最详细,性能测试各种测试场景分析+性能测试基准测(超细总结)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 面对日益复杂的业…

生成一个手绘图为底图的导游图

目录 1 前言 2 新增一个景区 3 生成验证码用于上传手绘图切片 4 免费下载切图客户端并配置、切图 5 增加景点 1 前言 上一篇演示了制作一个简版导游图。简版导游图的优点是制作简单、快速&#xff0c;不需要第三方软件&#xff0c;缺点是略显简陋、不够专业。 本编介绍制…

【Linux】信号概述

目录 1、信号概念2、Linux常用信号表3、信号的5种默认处理动作 橙色 1、信号概念 信号是 Linux进程间通信的最古老的方式之一&#xff0c;是事件发生时对进程的通知机制&#xff0c;有时也称之为软件中断&#xff0c;它是在软件层次上对中断机制的一种模拟&#xff0c;是一种…

两小时搭建属于自己的chatGPT(ChatGLM)免硬件(白嫖)

目录 准备&#xff08;注册&#xff09;: 搭建: API模式: 测试&#xff1a; 总结&#xff1a; 准备&#xff08;注册&#xff09;: 注册modelscope(白嫖)免费使用服务器 https://modelscope.cn/ 按照图片里的选择(选择其他好像不能创建成功) 可以白嫖60多个小时的配置 8…

新星计划 Electron+vue2 桌面应用 1 基础

/(ㄒoㄒ)/~~报名了两个新星计划&#xff0c;工作之余写博客…… 另外一个是uniapp的属于个人兴趣&#xff0c;这个桌面应用正好符合工作需要。 活动地址&#xff1a;https://marketing.csdn.net/p/1738cda78d47b2ebb920916aab7c3584 教程地址&#xff1a; 2023新星导师活动…

基于FPGA+JESD204B 时钟双通道 6.4GSPS 高速数据采集设计(三)连续多段触发存储及传输逻辑设计

本章将完成数据速率为 80MHz 、位宽为 12bits 的 80 路并行采样数据的连续多 段触发存储。首先&#xff0c;给出数据触发存储的整体框架及功能模块划分。然后&#xff0c;简介 MIG 用户接口、设置及读写时序。最后&#xff0c;进行数据跨时钟域模块设计&#xff0c;内存…

【瑞萨RA系列FSP库开发】RASC+Keil的环境搭建

文章目录 一、获取资源包二、安装 Keil 软件、RA 芯片包和 RASC三、RASC 集成到 Keil四、使用 RASC 生成 Keil 工程五、通过 Keil 打开 RASC 的 FSP 配置器界面六、配置和编译 Keil 工程七、使用调试器下载程序 本节将介绍如何在Keil上开发瑞萨RA MCU &#xff08;如需了解 e2 …

百汇BCR:十个外汇交易常见问题解析

外汇交易是一种受到市场欢迎的投资方式&#xff0c;参与交易很容易&#xff0c;但想要盈利却很难。特别是一些细节问题容易被忽略&#xff0c;百汇BCR小编整理了十个外汇交易常见问题供有需要的投资者借鉴学习。 问题一、外汇开户需要哪些资料&#xff1f; 个人相关信息资料、…

20 KVM管理虚拟机-虚拟机生命周期示例

文章目录 20 KVM管理虚拟机-虚拟机生命周期示例20.1 创建虚拟机20.2 启动虚拟机20.3 重启虚拟机20.4 关闭虚拟机20.5 销毁虚拟机 20 KVM管理虚拟机-虚拟机生命周期示例 本节给出虚拟机生命周期管理相关命令的示例。 20.1 创建虚拟机 虚拟机XML配置文件为openEulerVM.xml # …

Windows批处理指令

前言 批处理文件&#xff08;batch file&#xff09;包含一系列 DOS 命令&#xff0c;通常用于自动执行重复性任务。用户只需双击批处理文件便可执行任务&#xff0c;而无需重复输入相同指令。编写批处理文件非常简单&#xff0c;但难点在于确保一切按顺序执行。编写严谨的批处…

使用mkdocs快速部署上线静态站点到Github

背景 mkdocs是一种方便地生成站点的工具&#xff0c;相比hugo、hexo等个人博客而言&#xff0c;mkdocs更加简便、轻量级&#xff0c;可以快速帮助部署上线类似个人技术本&#xff08;notebook&#xff0c;wiki&#xff09;之类的站点。并且支持默认支持站点内搜索&#xff0c;…

基于SSM的网上宠物店

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

网络基础进阶

1、交换机接口类型 Console口&#xff1a;也称为&#xff1a;串口接口&#xff0c;一般用于与PC连接&#xff0c;用于配置和监控交换机。百兆以太网接口&#xff1a;用于连接计算机和交换机之间的通信。Console到的网络接口&#xff1a;俗称交叉串口&#xff0c;是用于连接交换…

微信小程序xr-frame实现多光源效果

1.基础知识&#xff1a; 灯光 灯光组件Light用于给场景提供照明&#xff0c;也是阴影的核心。相机组件一般被代理到灯光元素XRLight中使用&#xff0c;其派生自XRNode&#xff0c;对应在xml中的标签为xr-light。 主光源以及参数 类型uniforms宏说明书写环境光颜色和亮度u_a…

2023年门店管理系统如何选?简单好用的门店管理系统有哪些?

开单收银效率低、商品管理混乱、记账对账耗时耗力还易出错...... 是我们在进行门店管理过程中常见的问题。 为了改善门店管理遇到的这几大问题&#xff0c;提高门店管理效率&#xff0c;越来越多的门店开始使用门店管理系统。 但如何选择简单实用、性价比高的门店管理系统&…

template和component自定义组件之间的区别

在小程序中自定义组件 component 方式和组件模板 template 2种方式实现页面组件化。 一、component自定义组件 1.概念 自定义组件是指可以被多个页面使用的组件&#xff0c;可以在小程序中多次复用。在开发中可以将一个页面中的代码和样式抽象出来&#xff0c;然后创建一个自定…

springboot缓存

1. 认识缓存 一级缓存 - 缓存是一种介于数据永久存储介质与数据应用之间的数据临时存储介质 - 使用缓存可以有效的减少低速数据读取过程的次数&#xff0c;提高系统性能 Service public class BookServiceImplCache implements BookService {Autowiredprivate BookDao book…