vue3的学习【超详细】

news2024/11/20 15:14:31

目录

  • 一、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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux + ros 使用 catkin 从源码编译安装并运行 rocon_rtsp_camera_relay 订阅 rtsp 视频流

1. rocon_rtsp_camera_relay 介绍 最主要的功能在于把相机的 rtsp 视频流 转换为 ros topic 发布出来&#xff0c;使其他节点可以通过订阅的形式获取视频流数据。 2. 编译安装 注&#xff1a;官网的安装命令 sudo apt-get install ros-<distro>-rocon-rtsp-camera-rel…

leetcode 1557. Minimum Number of Vertices to Reach All Nodes(到达所有顶点的最少顶点集)

给出一个有向无环图&#xff08;DAG&#xff09;&#xff0c;顶点有n个&#xff1a;0&#xff5e;n - 1, 边[from, to]为从顶点from到to的边。 找出最小的顶点集合&#xff0c;从这些顶点出发能到达图中的所有顶点&#xff08;集合里不一定每个点都能到达所有顶点&#xff0c;而…

kettle——处理缺失值

目录 一、删除缺失值 1、文本文件输入 2、字段选择 3、过滤记录 4、输出excel文件 5、运行 二、填充缺失值 1、添加文件 2、过滤记录 3、替换NULL值 4、合并记录 5、替换NULL值2 6、字段选择 7、Excel输出 8、运行并查看执行结果 一、删除缺失值 1、文本文件输入…

MMOE - 经典多任务模型(谷歌)

文章目录 1、动机&#xff1a;2、模型结构&#xff1a; Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Expertsmmoe: Multi-gate Mixture-of-Expertsmmoe由谷歌发表在KDD-2018【和阿里的ESMM同年发表&#xff0c;SIGIR-2018】&#xff1b;模…

华为手环8添加门禁卡操作指导

不得不说&#xff0c;华为基于手机/手环NFC和蓝牙等技术应用&#xff0c;结合门禁卡灵活、安全、便利的优势&#xff0c;给社区场景提供更优质和更多样的技术支持与服务&#xff0c;为广大用户创造美好的数字化生活体验。 目前华为手环8支持模拟市面上未经加密过的、频率为13.5…

服务发现原理与grpc源码解析

一 服务发现基础概念 为什么需要服务发现 在微服务架构中&#xff0c;在生产环境中服务提供方都是以集群的方式对外提供服务&#xff0c;集群中服务的IP随时都可能发生变化&#xff0c;如服务重启&#xff0c;发布&#xff0c;扩缩容等&#xff0c;因此我们需要及时获取到对应…

ThreadLocal使用和原理

ThreadLocal是线程本地变量&#xff0c;用来解决并发下数据隔离性的问题&#xff0c;不能解决共享。 他可以将一个变量拷贝的线程内&#xff0c;线程调用时再线程内进行使用&#xff0c;相当于给每个线程复制一个副本供各个线程使用。 ThreadLocal简单使用 他的目的很简单&a…

Unity用AI制作天空盒,并使用,详细图文教程

Unity用AI制作天空盒&#xff0c;并使用&#xff0c;详细图文教程 效果AI制作使用总结版权声明 效果 先上我自己做的效果 AI制作 首先登录AI制作的网站&#xff0c;打开就可以用&#xff0c;不需要登录 这是网址&#xff1a;https://skybox.blockadelabs.com/ 1.创建新的 2…

idea操作——如何format代码

1.选中需要format的类&#xff0c;然后右击&#xff0c;选择reformat code 2.出现的复选框根据自己的需求进行选择。然后点击OK即可。 Optimize imports 优化导入 选中此复选框可从所选范围内的代码中删除未使用的导入语句。 删除代码中没使用到的import 。使导入最优化 Rearr…

【C++】-模板初阶(函数和类模板)

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 文章目录 前言一、为什么要模板&…

【面试题】谈谈你对vite的了解

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 1.什么是vite vite是新一代前端构建工具&#xff0c;能够显著提升前端开发体验。他是使用…

东邻到家小程序|东邻到家小程序源码|东邻到家小程序开发功能

上门服务这几年已经越来越火爆&#xff0c;不论是家政、按摩、美甲等等都在不断的发展上门服务&#xff0c;这几年东邻到家小程序系统在不断的摸索阶段&#xff0c;对于系统各方面的需求也在不断提升&#xff0c;东郊到家小程序通过线上匹配用户和技师的需求&#xff0c;让人们…

低代码开发打破CRM开发瓶颈,是否靠谱呢?

低代码开发平台是一种快速开发应用程序的新兴技术&#xff0c;它通过提供可视化开发工具和预配置组件&#xff0c;使开发者更加高效地创建应用程序。低代码开发平台的出现为企业开发带来了一次全新的机遇&#xff0c;尤其是在CRM领域。但是&#xff0c;低代码开发在CRM领域中是…

得物前端巡检平台的建设和应用(建设篇)

1.背景 我们所在的效能团队&#xff0c;对这个需求最原始的来源是在一次“小项目”的评审中&#xff0c;增长的业务同学提出来的&#xff0c;目的在于保障前端页面稳定性的同时减少大量测试人力的回归成本。 页面稳定性提升&#xff0c;之前迭代遇见过一些C端的线上问题&…

自学软件测试,我还是劝你算了吧。。。

本人8年测试经验&#xff0c;在学测试之前对电脑的认知也就只限于上个网&#xff0c;玩个办公软件。这里不能跑题&#xff0c;我为啥说&#xff1a;自学软件测试&#xff0c;一般人我还是劝你算了吧&#xff1f;因为我就是那个一般人&#xff01; 软件测试基础真的很简单&…

乒乓测评:电视盒子哪个牌子最好?2023电视盒子品牌排行榜

这里是乒乓测评&#xff0c;致力于带来更客观、真实的数码产品体验。本期我们测评的主题是电视盒子哪个牌子最好&#xff0c;为此我们购入了二十多款热门电视盒子&#xff0c;从硬件配置、视频流畅度、系统界面、操作、广告程度等方面进行多维度的测评&#xff0c;根据结果整理…

C++每日一练:详解-买铅笔影分身三而竭

文章目录 前言一、买铅笔二、影分身三、三而竭总结 前言 这回又换成C了&#xff0c;Python要用C也要用&#xff0c;没有哪个正经程序员只会一门语言的&#xff0c;咱可是CSDN认证带V的全栈攻城狮。今天的题目除了买铅笔都还是有点难度的&#xff0c;虽然影分身主要是考验阅读理…

【matlab报错】:函数或变量 ‘randint‘ 无法识别。

问题产生 首先定位问题&#xff0c;这个问题是由matlab版本造成的&#xff0c;随着matlab版本的更新&#xff0c;matlab删除了 randint 这个函数。 怎么替代呢&#xff1f;鼠标悬浮在报错代码上面&#xff0c;如下&#xff1a; matlab提示我们对代码进行相应更改后改用randi了…

基于SSM+JSP校园二手交易系统

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

5年测试经验华为社招:半月3次面试,成功拿到Offer

背景经历 当时我工作近5年&#xff0c;明显感觉到了瓶颈期。具体来说&#xff0c;感觉自己用过很多测试框架和测试工具、做过一些测试开发、也有过高并发的性能测试&#xff0c;但是从技术深度上感觉不足&#xff0c;到后期时做事也没有明显挑战&#xff0c;完全适应了公司节奏…