vue3的基本使用

模板语法

// 1、插值表达式
<div>{{ message }}</div>
<p>{{ count + 1 }}</p>

// 2、指令系统
<!-- 条件渲染 -->
<!-- 如果条件为false则不渲染该dom-->
<div v-if="isActive">显示A内容</div> 
<div v-else>显示B内容</div> 

<!-- 如果条件为false则该dom的display为false 高频则推荐该方式-->
<div v-show="isActive">显示内容</div> 

<!-- html结构渲染 -->
<div v-html="htmlStr"></div>

<!-- 数组列表渲染 -->
  <li v-for="(item, index) in items" :key="item.id">{{ item.name }}</li>

<!-- 对象渲染 -->
  <li v-for="(value, key, index) in obj" :key="value.id">{{ value.name }}</li>

<!-- 动态属性绑定 -->
<img :src="imageUrl" :alt="imageDescription">

// 4、模板里面访问所需全局对象可配置在main.js
const app = createApp(App)
app.config.globalProperties.TestConfig = {}
app.mount('#app')

vue3 模板语法具有沙盒特性,保证安全性,只能访问部分全局对象。
禁止的操作类型
‌1、全局对象访问‌ - 无法访问window、document等
2‌、危险操作‌ - 如delete操作符、with语句
3‌、函数定义‌ - 无法在模板中定义新函数
4‌、赋值操作‌ - 无法在模板中修改变量值
5、不要在标签上同时使用v-if和v-for,因为优先级不明显

类与样式绑定

// 1、动态类属性绑定 isActive是布尔值
<!-- 对象语法 -->
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
<!-- 数组语法 -->
<div :class="['active','text-danger']"></div>

// 动态样式绑定
<!-- 对象语法 -->
<p :style="{ color: 'red', fontSize: '10px' }"></p>
<!-- 数组语法 -->
<p :style="[{ color: 'red' }, { fontSize: '10px' }]"></p>

事件

<!-- 事件 -->
<!-- $event、e都是事件对象 -->
  <button v-on:click="add">添加</button>
  <button @click="add">添加</button>
  <button @click="add($event)">添加</button>
  <button @click="(e) => add(e)">添加</button>

  <!-- 修饰符 -->
  <!-- 阻止冒泡 -->
  <button @click.stop="reduce"></button>
  <!-- 阻止默认事件 -->
  <button @click.prevent="reduce"></button>
  <!-- 只有事件在该元素本身才能触发该函数,非子元素 -->
  <button @click.self="reduce"></button>
  <!-- 改变事件触发的阶段,捕获阶段触发,而非冒泡阶段 -->
  <button @click.capture="reduce"></button>
  <!-- 只触发一次 -->
  <button @click.once="reduce"></button>
  <!-- 提高页面滚动性能 -->
  <button @click.passive="reduce"></button>

  <!-- 按键修饰符 -->
  <button @keydown.left="reduce"></button>
  <button @keyup.enter="reduce"></button>
  <!-- ... -->

  <!-- 组合修饰符 -->
  <button @click.ctrl="reduce"></button>
  <!-- ... -->

v-model、defineModel(vue3.4)

v-model 既可以实现数据到表单元素之间的双向绑定,也可以用于父子组件之间的数据双向绑定

		<!-- 使用场景一:基本表单组件(将组件实例上的searchText绑定给input的value属性) -->
    <input v-model="searchText" />
		
		<!-- 使用场景二:父子组件双向绑定 -->
		<!-- 当父组件中pageNum发生变化时,子组件会自动更新currentPage的值,同样当子组件的currentPage发生变化时,父组件也会自动更新pageNum的值 -->
    <!-- 父组件 -->
    <pagination v-model:page="pageNum" />
    <!-- 子组件 -->
    const props = defineProps({
    page: {
        type: Number,
        default: 1
    }
    });
    const emit = defineEmits(['update:page']);
    const currentPage = computed<number | undefined>({
    get: () => props.page,
    set: value => {
        emit('update:page', value);
    }
    });

defineModel仅用于父子组件之间的数据双向绑定,它只是一个语法糖,内部还是用的props取值以及自定义事件来完成父组件数据的更新,并没有打破单向数据流

	<!-- 父组件 -->
   <Home v-model:count1="state.count" v-model:count2="_count1" name="张三"></Home>
   
	 <!-- 子组件 -->
	 const count1 = defineModel('count1')
	 const count2 = defineModel('count2')
	 function update(){
	 		count1.value++;
	 		count2.value++;
	 }

ref

ref 是用来创建响应式引用的主要方法。它通常用于基本数据类型(如字符串、数字、布尔值、对象、数组等)的响应式包装。在模板中可以直接使用,但在 JavaScript 中需要通过 .value 属性来访问或修改它的值
1、ref具有深层次响应式特点,主要针对对象;
2、通过shallowRef创建的响应式,不会深层递归,不具备深层响应式特点;

    import { ref } from 'vue';

    const count = ref(0);
    const userName = '洛可可白';

    // 在 JavaScript 中访问
    console.log(count.value); // 0
    count.value++; // 增加计数

    // 在模板中访问
    // <div>{{ count }}</div>



    // ref也可以用于获取dom元素
    <div><div ref="myDiv"></div>
    const myDiv = ref(null);
    myDiv.value.innerHTML = userName;

reactive

reactive 是用来创建响应式对象的方法,适用于处理对象和数组。reactive对象的属性可以在模板和 JavaScript 中直接访问和修改,不需要 .value
1、reactive具有深层次响应式特点;
2、通过shallowReactive创建的响应式,不会深层递归,不具备深层响应式特点;
3、使用reactive创建对象时不要去直接替换reactive关联的对象,会丢失响应式;
4、对reactive的数据进行对象解构时,解构的数据也会丢失响应式;
5、如果将ref作为reactive创建对象的属性,获取该属性值时,不需要解包(无需.value);但是如果将ref作为shallowReactive创建对象的属性时,不会自动解包。

   import { reactive } from 'vue';

    const state = reactive({
    count: 0,
    userName: '洛可可白'
    });

    // 在 JavaScript 中访问和修改
    console.log(state.count); // 0
    state.count++; // 增加计数

    // 在模板中直接访问
    // <div>{{ state.count }}</div>
    // <div>{{ state.userName }}</div>

ref和reactive

vue中的响应式是通过Proxy来实现的,Proxy只能拦截对象,无法拦截原始值;那如果需要把原始值转成响应式如何处理?
1、用户自己把原始值包装成对象,再使用reactiveApi;
2、框架层面帮你处理成对象(使用refApi),ref有两种处理方式:
A、如果是原始值,使用Object.defineProperty来实现;
B、如果是对象,使用reactiveApi来实现;
C、reactive响应式内部是由Proxy来实现;

响应式其它API

toRef、toRefs、unRef、readonly、isRef、isReactive、isProxy、isReadonly

import {
  isReactive,
  reactive,
  toRef,
  isRef,
  unref,
  toRefs,
  shallowReactive,
  shallowReadonly,
  readonly,
  isProxy,
} from 'vue'
const state = reactive({
  count: 1,
  obj: {
    value: 1,
  },
})
// 将响应式对象属性转化为ref
const countRef = toRef(state, 'count') // => const countRef = ref(state.count)

// 将整个reactive对象的所有属性都转化为ref对象
const refs = toRefs(state) // 取值 => const count = refs.count.value

// 判断一个对象是否是ref
isRef(countRef) // true

// 解包ref对象,如果不是ref直接返回值
unref(countRef) // 1

// 判断是否是reactive
isReactive(state) // true
isReactive(state.obj) // true reactive是深层次响应式,所以下层对象也是reactive对象

// 创建只读代理 只能获取不能改值
const readObj = readonly(state || countRef)

// isProxy 检查一个对象是否由reactive、readonly、shallowReactive、shallowReadonly创建的代理
// 因为ref内部是用了两种方式,所以它并不是单一的Proxy代理实现
isProxy(state)

computed

computed 用于创建计算属性,这些属性的值是基于其他响应式数据源派生出来的。计算属性是惰性求值的,只有当它们的依赖响应式数据发生改变时才会重新计算,对比模板中直接使用函数来实现,它的性能更好
computed值也可以修改,但是computed的设计思想只用来获取值,所以不建议进行修改操作

import { ref, computed } from 'vue'

const count = ref(0)
const doubleCount = computed(() => count.value * 2)

// computed的修改使用
import { computed, isReactive, reactive, ref } from 'vue'
const state = reactive({
  count: 1,
  obj: {
    value: 1,
  },
})
const count = ref(0)
const newCount = computed({
  get(value) {
    return state.count + 10
  },
  set(value) {
    count.value = value
  },
})
setTimeout(() => {
  newCount.value = newCount.value + 1
}, 2000)

watch

watch 用于观察响应式数据的变化,并在数据变化时执行特定的函数。
1、watch的执行顺序优于computed
2、watch可以监听ref、reactive、computed,以及Getter函数(监听函数返回值),以及数组形式的ref或者reactive
3、watch监听的对象是reactive数据时,监听层级是深层次的
4、如果想要监听reactive对象属性值时,应该使用回调函数形式来监听【watch(()=> getValue, () => {})】

import { ref, watch } from 'vue';

const count = ref(0);
watch(count, (newValue, oldValue) => {
	console.log(`Count changed from ${oldValue} to ${newValue}`);
});
		
function getValue() {
  return state.count / 2
}
watch(getValue, (newV, oldV) => {})

watch([_count1, _count2, state, state2], (newV, oldV) => {},
{
    immediate: true, // 默认false 组件渲染时会执行一次
    deep: true,  // 默认true 深度监听,但是如果监听对象是computed值或者Getter函数时默认就是false
    once:true // 默认false 监听器回调函数只执行一次
    flush:'post' // dom更新之后执行
  },
)

watchEffect

watchEffect 是一个基于响应式数据源的观察者,当响应式数据源变化时重新执行。
1、会立即执行一次
2、多依赖项监听可以使用watchEffect,而不是watch
3、如果只需要监听reactive对象的某个属性,那么watchEffect函数中只需要用到该属性即可,性能对比watch更优

    import { ref, watchEffect } from 'vue';

    const count = ref(0);

   const unwatch = watchEffect(() => {
    console.log(`Count is now: ${count.value}`);
    });
	unwatch() // 停止侦听器

生命周期

onBeforeMount(() => {})

onMounted(() => {})

onBeforeUpdate(() => {})

onUpdated(() => {})

onBeforeUnmount(() => {})

onUnmounted(() => {})

provide 和 inject

provide 和 inject 是用于组件间通信的 API,允许父组件提供数据,子组件注入并使用这些数据,用于跨层级父子组件通信

    import { provide, inject } from 'vue';

    // 父组件
    provide('injectedValue', 'This is provided by parent');

    // 子组件
    const injectedValue = inject('injectedValue');

nextTick

nextTick 是一个全局方法,用于在下次 DOM 更新循环结束之后执行延迟回调。在修改了响应式数据之后,通常用于等待 DOM 更新

    import { nextTick } from 'vue';

    nextTick(() => {
    console.log('DOM has been updated!');
    });

宏(defineProps、defineEmits)

defineProps用于父组件给子组件传递数据

	<!-- 父组件 -->
  <Home name="张三"></Home>
  <Home user-name="李四"></Home>
  	<!-- 非字符串类型,必须使用动态方式传递参数 -->
  <Home user-name="王五" :age="18"></Home>
	
	<!-- 子组件 -->
	<!-- 模块中可以不需要props前缀 -->
	const props = defineProps({
	  name: String,
	  userName: String,
	  age: Number,
	})
	
<template>
  <div>{{ name }}</div>
  <div>{{ userName }}</div>
  <div>{{ age }}</div>
</template>

defineEmits自定义事件由父组件给子组件传递事件,用于子组件主动触发该事件或者给父组件传递数据

	<!-- 父组件 -->
  <Home @reduce="reduce" name="张三"></Home>
	
	<!-- 子组件 -->
	const emit = defineEmits({
  		reduce: Function,
	})
	
<template>
	<!-- 写法1 -->
   <button @click="emit('reduce', 2)">-</button>
   <!-- 写法2 -->
   <button @click="$emit('reduce', 2)">-</button>
</template>

插槽

插槽是一种让父组件能够向子组件传递内容的机制。插槽可以分为默认插槽、具名插槽和作用域插槽

默认插槽

子组件在模板中预留一个插槽位,父组件可以传入内容填充这个位置

    // 子组件
    <template>
    <div>
        <slot />
    </div>
    </template>

    // 父组件
    <template>
    <ChildComponent>
        <p>这是父组件传递的内容。</p>
    </ChildComponent>
</template>

具名插槽

子组件可以定义多个插槽位,父组件可以指定内容填充到哪个插槽位。

    // 子组件
    <template>
    <div>
        <slot name="header"></slot>
        <slot name="main"></slot>
        <slot name="footer"></slot>
    </div>
    </template>

    // 父组件
    <template>
    <ChildComponent>
        <template v-slot:header>
        <h1>这是头部内容</h1>
        </template>
        <template v-slot:main>
        <p>这是主体内容</p>
        </template>
        <template v-slot:footer>
        <footer>这是底部内容</footer>
        </template>
    </ChildComponent>
    </template>

作用域插槽

除了传递内容,插槽还可以传递数据

    // 子组件
    <template>
    <div>
        <slot :user="user">{{ user.name }}</slot>
    </div>
    </template>

    <script>
    export default {
        data() {
            return {
                user: { name: '张三', age: 30 }
            };
        }
    };
    </script>

    // 父组件
    <template>
    <ChildComponent>
        <template v-slot:default="slotProps">
        <p>{{ slotProps.user.name }} 今年 {{ slotProps.user.age }} 岁。</p>
        </template>
    </ChildComponent>
    </template>

自定义 hooks

根目录 src 下创建 hooks 文件夹,然后创建一个 xxx.js 文件。写法同 react 自定义 hooks 差不多,返回一个对象,对象中的属性和方法可以提供给父组件使用

export default () => {
  const state = reactive<IState>({
    lightWall: undefined,
  })

  /**
   * 创建光墙
   * @param position 中心点
   */
  const createLightWall = () => {
    const id = v4()
    const lightWall = new LightWall({
      id,
      ziCesium,
    })
    state.lightWall = lightWall
  };

  onUnmounted(() => {})


  return {
    createLightWall,
  };
};

Pinia 介绍

Pinia 是一个专门为 Vue.js 设计的状态管理库,它提供了一种简单和直观的方式来管理应用程序的状态。在使用 Pinia 时,可以轻松地创建定义状态的存储,然后将其与 Vue 组件绑定,使它们能够使用该状态。和 Vuex 相比,Pinia 更加简单易用,体积更小,同时具有更好的 TypeScript 支持和插件系统

// 步骤一:main.ts中需要挂载pinia
    import { createApp } from 'vue';
    import { createPinia } from 'pinia';
    import App from './App.vue';
    const app = createApp(App);
    const pinia = createPinia();
    app.use(pinia);
    app.mount('#app');

// 步骤二:在src目录下创建store文件夹,store文件下创建一个modules文件夹,然后modules文件夹下面创建一个user.ts文件,内容如下
    import { defineStore } from 'pinia';
    const useUserStore = defineStore({
    id: 'user',
    state: (): UserState => ({
        userInfo:null
    }),
    actions: {
        async RESET_STATE() {
        this.$reset();
        },
        setUserInfo(userInfo) {
        this.userInfo = userInfo
        },
    },
    });

    export default useUserStore;


// 步骤三:在store文件夹下创建一个index.ts文件,内容如下
    import useUserStore from './modules/user';
    const useStore = () => ({
    user: useUserStore(),
    });

    export default useStore;

// 步骤四:使用
    import useStore from '@/store';
    import { onMounted } from 'vue';
    const { user } = useStore();
    onMounted(()=>{
        console.log(user.userInfo)
    })
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值