VUE3笔记

本文详细介绍了Vue3的新特性和关键功能,包括CompositionAPI的使用、响应式系统(ref、reactive、computed和watch)、组件生命周期、全局组件注册、过滤器更新、父子组件通信方法以及VUE3.3的defineOptions和defineModel。
摘要由CSDN通过智能技术生成

Vue3

创建项目

// vite创建
npm init vue@latest
// 或
npm create vue@latest

// vue-cli创建
vue create demo

语法格式

Composition API (组合式)
<script setup>
// 导入函数
import { ref } from 'vue'
// 数据对象
const obj = ref({
  sum: 5,
  price: 10
})
// 事件函数
const btn = () => {
  obj.value.sum = 10
}
</script>

新特性

Fragment :template 允许存在多个根标签

组合式API

setup

setup函数(狗都不用)

执行时机比beforeCreate钩子函数还要早

setup函数中获取不到this

数据和函数需要在 setup最后return才能在模板中使用

<script>
export default {
    setup(){
        const message = '你好'
        const messageLog = () => {
            console.log(message)
		}
        return {
           message,
           messageLog
        }
    }
}
</script>

<template>
	<h1 @click='messageLog'>{{ message }}</h1>
</template>

setup语法糖(常用)

简化代码,不用return

<script setup>
const message = '你好'
const messageLog = () => {
  console.log(message)
}
</script>
<template>
	<h1 @click='messageLog'>{{ message }}</h1>
</template>

reactive函数

接受对象类型数据的参数传入,返回一个响应式对象

reactive只接受对象类型

<script setup>
import { reactive } from 'vue'
const state = reactive({
    count:100
})
const setCount = () => {
    state.count++
}
</script>
<template>
	<h1 @click='setCount'>{{ state.count }}</h1>
</template>

ref函数

ref 可以构建《简单数据类型》《复杂数据类型》的响应性

如果要修改ref的响应性数据,必须通过.value进行访问

为什么要.value 因为proxy只能构建复杂数据类型,所以简单数据类型不能通过proxy处理代理对象

实际开发中常使用 ref 目的《让整个数据代码具备统一性》

当传入的数据是《简单数据类型》时,它的setter行为和getter行为本质上是函数的调用

当传入的数据是《复杂数据类型》时,它的响应性依赖于 reactive 响应性

<script setup>
// 导入函数
import { ref } from 'vue'
// 数据对象
const obj = ref({
  sum: 5,
  price: 10
})
// 数据对象
const count = ref(0)

// 访问数据需要.value
console.log(obj.value.sum)
console.log(count.value)

// 事件函数
const btn = () => {
  obj.value.sum = 10
}
</script>

// 在页面不需要.value
<template>
	<h1>{{ count }}</h1>
	<h1>{{ obj.sum }}</h1>
</template>

computed 计算属性

// 基础写法
<script setup>
// 导入
import { ref, computed } from 'vue'
// 声明数据
const list = ref([1, 2, 3, 4, 5, 6])
// 计算属性
const computedList = computed(() => {
  return list.value.filter(item => item > 2)
})
// 打印测试
console.log(computedList.value);
</script>
计算属性-可写

适用于全选反选

<script setup>
// 导入函数
import { ref, computed } from 'vue'
// 数据对象
const obj = ref({
  sum: 5,
  price: 10
})
// 事件函数
const btn = () => {
  // 更改计算属性
  num.value = 100
}

const num = computed({
  // 依赖项发生改变会触发这个方法
  get () {
    return obj.value.sum * obj.value.price
  },
  // 计算属性的值被更改会触发这个方法
  set (newValue) {
    console.log(newValue) // 更改后的值
  }
})
</script>

watch侦听器

watch(ref对象 , 事件函数 , 配置项)

<script setup>
// 导入函数
import { ref, watch } from 'vue'
// 数据对象
const obj = ref({
  sum: 5,
  price: 10
})
// 侦听数据
watch(obj, (newValue, oldValue) => {
  console.log(newValue)
}, {
  deep: true, // 深度侦听
  immediate: true  // 立即执行
})
</script>

仅侦听对象中的某个属性

watch(()=>对象.value.属性 , 事件函数 , 配置项)

<script setup>
// 导入函数
import { ref, watch } from 'vue'
// 数据对象
const obj = ref({
  sum: 5,
  price: 10
})
// 侦听数据
watch(()=>obj.value.sum, (newValue, oldValue) => {
  console.log(newValue)
}, {
  deep: true, // 深度侦听
  immediate: true  // 立即执行
})
</script>

侦听多个对象 [ref对象,ref对象]

watch([obj,obj], (newValue, oldValue) => {
  console.log(newValue) // [obj,obj]
}, {
  deep: true, // 深度侦听
  immediate: true  // 立即执行
})

生命周期

移除了两个生命周期函数,beforeCreate,Created

新增了一个,setup 可以把这个看做是created

修改了销毁的两个生命周期函数,改为 beforeUnmount , unmounted

setup

onBeforeMount onMounted

onBeforeUpdate onUpdated

onBeforeUnmount onUnmounted

// 使用
import { onMounted } from 'vue'

onMounted(() => {
  console.log(`the component is now mounted.`)
})

ref获取dom

<div ref="but">{{ num }}</div>

1.声明一个数据 名字就叫要获取的ref名
const but = ref(null)
2.生命周期中获取
onMounted(() => {
  console.log(but.value)
})

访问子组件里的属性及方法 (defineExpose )

获取子组件里的属性及方法需要子组件使用defineExpose 进行暴露,配合ref获取dom

// 子组件
<script setup>
import { ref,onMounted } from 'vue'
    
const num = ref(1)

const btn = () => {
  console.log(num.value)
}
// 使用defineExpose 进行暴露
defineExpose({
  num,
  btn
})
</script>
// 父组件
<script setup>
import { ref,onMounted } from 'vue'
// 获取子组件dom
const but = ref(null)
onMounted(() => {
  console.log(but.value)  // 这里就有子组件里的属性和方法
})
</script>

<template>
  <子组件 ref="but"></子组件>
</template>

父子组件通信

.sync 移除 v-model: 代替

子组件接收数据(defineProps)和返回数据(defineEmits)
// 导入 props 和 emit
import { defineProps, defineEmits } from 'vue'
// 接收数据
const props = defineProps({
  数据名: {
    type: 数据类型,
    required: true // 是否必传
  }
  // 也可以这样接收
  数据名:数据类型
})
// 打印测试 
console.log(props.数据名)

// 返回数据  拿到父组件的 @自定义事件
const emits = defineEmits(['自定义事件名'])

// 触发方法 
const onClick = () => {
  emits('自定义事件名', 'a')
}
用 v-model 父子通信
// 父
<组件名 v-model:title="title" />

// 子

// 导入 props 和 emit
import { defineProps, defineEmits } from 'vue'
// 接收数据
const props = defineProps({
  title: {
    type: 数据类型,
    required: true // 是否必传
  }
})

// 返回数据  拿到父组件的自定义事件
const emits = defineEmits(['update:title'])
// 触发方法 
const onClick = () => {
  emits('update:title', 'a')
}

注册全局组件

src/libs/index.js

import Banner from './banner'

const libs = {
  install (app) {
    // app为vue的实例
    // app.component('组件名',组件对象)
    app.component('Banner', Banner)
  }
}
export default libs

main.js
import libs from './libs/index'
createApp(App).use(libs)

全局过滤器

局部过滤器移除,全局过滤器用全局属性代替

// main.js文件内
// 全局属性 过滤器
const app = createApp(App)
// $filter 自定义的属性名  currencyUSD自定义的方法名
app.config.globalProperties.$filter = {
  currencyUSD (value) {
    return value
  }
}
// main.js的这里要改成app
app.use(store).use(router).mount('#app')
使用
<div>{{ $filter.currencyUSD(num) }}</div>

跨层组件通信

父组件里有子组件,子组件里还有孙组件,孙组件里有重孙组件

父组件向下传值 , 单向传值

provide 传值

provide(‘自定义属性名’ , ‘传的值’)

inject 接收

inject(‘自定义属性名’)

// 父组件
<script setup>
// 导入
import { ref,provide } from 'vue'
// 定义数据
const age = ref(123)
// 传值
provide('age',age)
    
// 也可以传方法用来让孙组件来改传过去的值
provide('changeAge',(newValue)=>{ age.value = newValue})
</script>
// 某个孙组件
<script setup>
// 导入
import { inject } from 'vue'
// 接收
const age = inject('age')  // 123 并且是响应式的

// 也可以接收方法用来改传过来的值
const changeAge = inject('changeAge')

// 某个方法里调用这个父传过来的方法
const btn = () => {
  changeAge(100)
}
</script>

VUE 3.3 新特性

defineOptions

用来命名组件,解决某个组件起名为 index.vue 页面里第一行红色波浪线情况

类似于以下

<script>
export default {
  name: 'LoginIndex'
}
</script>

使用方法

<script setup>
defineOptions({
  name:'LoginIndex'
})
</script>

defineModel

用来简化v-model 相当于接收父传来的值使用并可以修改并同步到父

省略了props 和 emits

目前是试验阶段 需要配置才可生效

// vite.config.js

export default defineConfig({
  plugins: [
    // 这里需配置 true
    vue({
      defineModel:true
    }),
  ],
})

使用

// 父组件
<script setup>
import { ref }from 'vue'
const txt = ref('100')
</script>

<template>
  <子组件 v-model="txt"></子组件>
</template>
// 子组件
<script setup>
import { defineModel } from 'vue'
// 接收传下来的值
const txt = defineModel()
</script>
<template>
  // 可以通过点击事件直接修改收到的值,并且父组件会同步,这里用input标签举例
  <input type="text" :value="txt" @input= e => txt = e.target.value ></input>
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值