VUE3 学习

import { computed, provide, ref, watch, watchEffect } from 'vue'

/* 1. ref 创建简单类型 和 复杂类型 返回一个响应式的对象
推荐:以后声明数据,统一用 ref => 统一了编码规范
注意点:

  1. 脚本中访问数据,需要通过 .value
  2. 在template中,.value不需要加 (帮我们扒了一层)
    */
    const count = ref(0)
    const setCount = () => {
    count.value++
    }

/*

  1. 计算属性
    */
    const list = ref([1, 2, 3, 4, 5, 6])
    // 定义计算属性
    const computedList = computed(() => {
    return list.value.filter(item => item > 2)

})

/*

  1. watch 监听单个数据变化
    */
    const x = ref(0)
    const y = ref(0)
    const obj = ref({ id: 0 })
    // 1. 监听单个数据变化
    watch(x, (newValue, oldValue) => {
    console.log(newValue, oldValue)
    })
    // 2. 监听对象属性值
    // 注意: 不能直接侦听响应式对象的属性值, 需要用一个返回该属性的 getter 函数
    watch(() => obj.value.id, (count) => {
    console.log(count)
    })
    // 3. 监听多个数据变化
    watch([x, () => y.value, () => obj.value.id], ([newArray, oldArray]) => {
    console.log(newArray, oldArray)
    })

// 4. 深层监听器
watch(
() => obj.value.count,
(newValue, oldValue) => {
// 注意:newValue 此处和 oldValue 是相等的
// 除非 state.someObject 被整个替换了
console.log(newValue, oldValue)
},
{ deep: true, immediate: true, once: true }
)

/*

  1. watchEffect
    特点:
  2. 自动追踪回调函数内所有响应式依赖(无需显式指定依赖)
  3. 会立即执行一次.
  4. 只能获取当前值(无旧值)
  5. watchEffect也是自动深度监听
    注意: 内同步修改依赖可能引发无限循环(例:count.value++)
    */
    watchEffect(() => {
    // 自动跟踪回调的响应式依赖, 也可监听多个依赖.
    console.log(obj.value.id)
    })

/* watch 和 watchEffect 的区别

watch 需显式声明监听目标属性, 强调精确控制. 适用于需要对比新旧值, 限制触发范围或延迟执行的场景.
// 显式指定监听源
watch(() => obj.value.id, (newVal, oldVal) => { ... })


watchEffect  通过自动依赖追踪简化代码,专注副作用执行。适合依赖关系复杂或需立即执行的逻辑
// 自动收集所有依赖

watchEffect(() => {
fetchData(obj.value.id, config.value.lang) // 自动追踪 obj.value.id 和 config.value.lang
})
*/

/* 6. 生命周期函数

数据请求放在 setUp 中, Dom 操作放在 onMounted 中.

setup : 就是用来替代 vue2.0 中的 beforeCreate 和 created
注意: 无法操作 Dom

onMounted 主要用于:

  1. 需要操作的 DOM 元素的场景
  2. 获取元素尺寸,位置等信息的场景
  3. 第三方库的初始化(需要 DOM 已经存在)

不依赖 DOM 的请求 → 优先 setup 同步执行
依赖 DOM/第三方库 → 必须 onMounted
*/

/*

  1. 父传子
  • 在父页面中,给子组件添加属性的方式传值
  • 在子组件, 通过 props 接收数据
    */
    import SonCom from '@/components/son-com.vue'
    const money = ref(100)
    // 页面应用
    < SonCom car = "宝马车" : money = "money" ></>

/** SonCom 子组件页面

  • 对于props传递过来的数据,模板(template)中可以直接使用
  • 在 setUp 中需要借助于 “编译器宏” 函数接收子组件传递的数据, 例如 props.car
    */
    const props = defineProps({
    car: {
    type: String,
    default() {
    return ''
    }
    },
    money: {
    type: Number,
    default() {
    return 0
    }
    }
    })

/**

  • 9.子传父
    • 在父页面, 通过 @XX 事件监听
    • 在子组件内部, emit触发事件(编译器获取)

*/
import SonCom from '@/components/son-com.vue'

// 给子组件,添加属性的方式传值
<SonCom @changeMoney="changeFn" ></SonCom >
// 触发事件接收数据
const changeFn = (newMoney) => {
money.value = newMoney
}

/** SonCom 子组件页面 */
const emit = defineEmits(['changeMoney'])
// 需要 emit 触发事件
const setAction = () => {
emit('changeMoney', 5)
}

/**

  • 模版引用 ref
    */
    // 3.5+ 之前, 定义ref: const txtRef = ref(null)
    // 3.5+ 之后, 定义 ref: const txt = useTemplateRef('txtRef')
    // 上面两者的作用都是一样的,只不过是写法不一样.
    // 开发过程中主要用其两个作用:
    // 1.通过 ref 来实现调用父页面的标签属性
    // 2.通过 ref 来实现调用子组件的方法或属性, 由于使用了 <script setup> 的组件是默认私有的,需要在子组件中通过 defineExpose 宏显式暴露:

//示例1:
// 1. 调用 ref 函数得到 ref 对象
const inp = ref(null)
// 2. 通过 ref 标识绑定 ref 对象
< input ref = "inp" type = "text" >
onMounted(() => {
// console.log(inp.value)
// inp.value.focus()
})

// 示例 2
import { useTemplateRef, onMounted } from 'vue'
import { Model } from 'echarts'

// 第一个参数必须与模板中的 ref 值匹配
const input = useTemplateRef('my-input')

onMounted(() => {
input.value.focus()
})

< input ref = "my-input" />

/**

  • defineExpose 宏显示暴漏
  • 使用了 <script setup> 的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 的子组件中的任何东西,除非子组件在其中通过 defineExpose 宏显式暴露:
    */

const a = 1
const b = ref(2)

// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
a,
b
})

/**
为什么在定义全局变量时,有的使用 ref 或 reactive, 有的可以直接定义 let chart = null
原因:

  1. 需要响应式 → ref 或 reactive 例如: const array = ref([])
  2. 不需要响应式 → let 或 const 例如: let chart = null

总结: 为什么 Vue 3 代码中大量使用 const 的原因,

例如:
const 防止意外重新赋值 array 变量, const定义的变量完全满足日常的操作需求;

const array = ref([]);

// ✅ 允许:修改 ref 内部的值
array.value.push(1);
array.value = [1, 2, 3];

// ❌ 不允许:重新赋值 ref 变量
array = ref([1, 2, 3]); // 报错

使用 const 和 let 定义变量的区别:
使用 const - 不能重新赋值
例如:
// 使用 let - 可以重新赋值
let chartInstance = null;
chartInstance = echarts.init(dom); // ✅ 允许
chartInstance = null; // ✅ 允许清空

// 使用 const - 不能重新赋值
const chartData = ref([]);
chartData.value = [1, 2, 3];          // ✅ 允许:修改值
chartData = ref([4, 5, 6]);           // ❌ 报错:不能重新赋值

*/

/**

  • provide 和 inject
  • 顶层组件向任意的底层组件传递数据和方法,实现 [跨层] 组件通信
    */

// 顶层
provide('key', '顶层组件中的数据')
// 底层
const message = inject('key')
console.log(message) // '顶部组件中的数据'

/**

  • Vue3.3 新特性-defineOptions
  • 在 Vue 3.3 中新引入了 defineOptions 宏。顾名思义,主要是用来定义 Options API 的选项。可以用 defineOptions 定义任意的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)
  • 用于在 <script setup> 中声明组件选项(如 name、inheritAttrs)属于静态配置,不参与运行时逻辑.
    */

defineOptions({
name: '名字',
inheritAttrs: false
})

/**

  • Vue3.3新特性-defineModel
  • 在Vue3中,自定义组件上使用v-model, 相当于传递一个modelValue属性, 同时触发 update:modelValue 事件
  • 生效需要配置 vite.config.js

*/

/**
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue({
script: {
defineModel: true
}
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
*/
<Child v-model= "isVisible">
// 相当于
<Child :modeValue="isVisible" @update:modelValue= 'isVisible=$event'>

</script>

<style lang="scss" scoped></style>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容