vue3 学习

248 阅读5分钟

指令

v-text 用来显示文本

<template>
  <div v-text="message"></div>
</template>
<script setup lang="ts">
const message = "我是张三";
</script>

v-html 用来展示富文本

<template>
  <div v-html="html"></div>
</template>
<script setup lang="ts">
const html = "<h1>我是标题</h1>";
</script>
<style></style>

v-if 用来控制元素的显示隐藏(切换真假DOM)

<template>
  <div v-if="shou === 1">我是{{ shou }}</div>
  <div v-else-if="shou === 2">我是{{ shou }}</div>
  <div v-else>我什么都不是{{ shou }}</div>
</template>
<script setup lang="ts">
const shou = 2;
</script>

v-show 用来控制元素的显示隐藏(display none block Css切换)

<template>
  <div v-show="shou">显示内容</div>
</template>
<script setup lang="ts">
const shou = true;
</script>
<style></style>

v-on 简写@ 用来给元素添加事件

<template>
  <button @click="onclick">按钮</button>
</template>
<script setup lang="ts">
const onclick = (): void => {
  console.log("点击按钮");
};
</script>
<style></style>

v-bind 简写: 用来绑定元素的属性

<template>
  <input type="text" v-bind:value="name" />
</template>
<script setup lang="ts">
const name = "我是名称";
</script>
<style></style>
// 绑定class
<template>
  <input type="text" v-bind:class="name" />
</template>
<script setup lang="ts">
const name = "我是名称";
</script>
<style></style>

v-model 双向绑定

<template>
  <input v-model="name" type="text" />
  {{ name }}
</template>
<script setup lang="ts">
import { ref, Ref } from "vue";
​
const name: Ref<string> = ref("我是名称");
</script>
<style></style>

v-for 用来遍历元素

<template>
  <div v-for="(item, idnex) in list" :key="idnex">{{ item }}</div>
</template>
<script setup lang="ts">
const list: string[] = ["1", "2", "3"];
</script>
<style></style>

v-on修饰符

//冒泡案例
<template>
  <div @click="parent">
    <div @click.stop="child">child</div>
  </div>
</template>
 
 
<script setup lang="ts">
const child = () => {
  console.log('child');
 
}
const parent = () => {
  console.log('parent');
}
 
</script>
​
//阻止表单提交案例
<template>
  <form action="/">
    <button @click.prevent="submit" type="submit">submit</button>
  </form>
</template>
<script setup lang="ts">
const submit = () => {
  console.log('child');
}
</script>
<style>
</style>

生命周期

​
​
选项式 APIHook inside setup描述
beforeCreate抛弃
created抛弃
beforeMountonBeforeMount在组件DOM实际渲染安装之前调用。在这一步中,根元素还不存在
mountedonMounted在组件的第一次渲染后调用,该元素现在可用,允许直接DOM访问
beforeUpdateonBeforeUpdate数据更新时调用,发生在虚拟 DOM 打补丁之前
updatedonUpdatedDOM更新后,updated的方法即会调用。
beforeUnmountonBeforeUnmount在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
unmountedonUnmounted卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。
errorCapturedonErrorCaptured每当事件处理程序或生命周期钩子抛出错误时,Vue 会调用该钩子。
renderTrackedonRenderTrackedonRenderTracked直译过来就是状态跟踪,它会跟踪页面上所有响应式变量和方法的状态,也就是我们用return返回去的值,它都会跟踪。只要页面有update的情况,它就会跟踪,然后生成一个event对象,我们通过event对象来查找程序的问题所在。
renderTriggeredonRenderTriggeredonRenderTriggered直译过来是状态触发,它不会跟踪每一个值,而是给你变化值的信息,并且新值和旧值都会给你明确的展示出来。
activatedonActivatedkeep-alive组件激活时使用
deactivatedonDeactivatedkeep-alive组件停用时调用

Ref全家桶

ref

ref支持类型响应数据(StringNumberBooleanSymbol)

  • 生成值类型响应式数据

  • 通过.value值修改

  • 生成对象和数组类型的响应式对象 (对象和数组一般会选用reactive方式,比较便捷)

    <template>
      <div>{{ name }}</div>
      <div>{{ name2 }}</div>
      <button @click="onclick">按钮</button>
    </template>
    <script setup lang="ts">
    import { Ref, ref } from "vue";
    ​
    // vue2.0 使用在data函数里面进行双向绑定,但是vue3 是需要借助 ref 函数进行修改
    // ref 第一种 const name = ref<string>("我的名称"); 第二种 const name2: Ref<string> = ref("我的名称");
    const name = ref<string>("我的名称");
    const name2: Ref<string> = ref("我的名称");
    const onclick = (): void => {
      setTimeout(() => {
        name2.value = "222";
      }, 5000);
    };
    </script>
    <style></style>

    isRef

    • 判断是不是一个ref对象
    <template>
      <div>{{ name }}</div>
      <button @click="onclick">按钮</button>
    </template>
    <script setup lang="ts">
    import { isRef, Ref, ref } from "vue";
    ​
    const name = ref<string>("我是ref");
    const noref = "我不是ref";
    const onclick = (): void => {
      console.log(isRef(name), name);
      console.log(isRef(noref), noref);
    };
    </script>
    <style></style>

    shallowRef

    创建一个跟踪自身 .value 变化的 ref

    # 但不会使其值也变成响应式的
    <template>
      <div>
        <button @click="changeMsg">change</button>
        <div>{{ message }}</div>
      </div>
    </template>
    <script setup lang="ts">
    import { Ref, shallowRef } from 'vue'
    type Obj = {
      name: string
    }
    let message: Ref<Obj> = shallowRef({
      name: "小满"
    })
     
    const changeMsg = () => {
      message.value.name = '大满'
    }
    </script>
     
     
    <style>
    </style>
    ​
    这样是可以被监听到的修改value
    <script setup lang="ts">
    import { Ref, shallowRef } from 'vue'
    type Obj = {
      name: string
    }
    let message: Ref<Obj> = shallowRef({
      name: "小满"
    })
     
    const changeMsg = () => {
      message.value = { name: "大满" }
    }
    </script>

    triggerRef

    强制刷新DOM元素

    <template>
      <div>
        <button @click="changeMsg">change</button>
        <div>{{ message.name }}</div>
        <div>{{ message.text }}</div>
      </div>
    </template><script setup lang="ts">
    import { shallowRef, triggerRef } from "vue";
    const message = shallowRef({
      name: "小满",
      text: "2222",
    });
    const changeMsg = () => {
      message.value.name = "2222";
      triggerRef(message);
    };
    </script>
    <style></style>
    

    customRef

    • 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
    • 如果要使用,记得是在自定义的 ref中返回一个 customRef,而 customRef也要返回一个,customRef包含一个get方法和set方法 ---获取值走get方法,修改走set方法,
    • customRef的两个参数分别是用于追踪的 track 与用于触发响应的 trigger
    <template>
      <div>
        {{ message }}
        <button @click="changeMsg">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { customRef } from "vue";
    ​
    const Myref = function <T>(value: T) {
      return customRef((track, trigger) => {
        return {
          get() {
            track();
            return value;
          },
          set(newVal: T) {
            console.log("set");
            value = newVal;
            trigger();
          },
        };
      });
    };
    ​
    let message = Myref("小满");
    const changeMsg = () => {
      message.value = "大满";
    };
    </script><style></style>

Reactive全家桶

reactive

  • 绑定复杂的数据类型,一般是在引用数据类型使用

  • reactive不能直接赋值只可以修改里面的内容

  • reactive 只可以修改里面的值,不可以直接赋值

    <template>
      <div>
        {{ message }}
        <button @click="changeMsg">按钮</button>
        {{ arrlist }}
      </div>
    </template>
    ​
    <script setup lang="ts">
    import { reactive } from "vue";
    interface Aobj {
      value: string;
    }
    const message = reactive<Aobj>({
      value: "name",
    });
    let arrlist = reactive<number[]>([1, 2, 3]);
    const changeMsg = () => {
      message.value = "大满";
      // arrlist = [2]; //不支持
      arrlist[0] = 11;
      arrlist.push(...[1]);
    };
    </script>
    ​
    <style></style>
    ​
    

readonly

  • 拷贝一份proxy对象将其设置为只读

    import { reactive ,readonly} from 'vue'
    const person = reactive({count:1})
    const copy = readonly(person)
    //person.count++
     copy.count++
    

shallowReactive

  • 只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图

    <template>
      <div>
        <div>{{ state }}</div>
        <button @click="change1">test1</button>
        <button @click="change2">test2</button>
      </div>
    </template>
     
     
     
    <script setup lang="ts">
    import { shallowReactive } from 'vue'
     
     
    const obj = {
      a: 1,
      first: {
        b: 2,
        second: {
          c: 3
        }
      }
    }
     
    const state = shallowReactive(obj)
     
    function change1() {
      state.a = 7
    }
    function change2() {
      state.first.b = 8
      state.first.second.c = 9
      console.log(state);
    }
     
    </script> 
     
    <style>
    </style>

to全家桶

toRef

  • 如果原始对象是非响应式的就不会更新视图 数据是会变的

    <template>
      <div>
        {{ message.name }}
        {{ setmessage }}
    ​
        <button @click="onclick">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { toRef } from "vue";
    ​
    let message = {
      name: "名称",
    };
    const setmessage = toRef(message, "name");
    ​
    const onclick = (): void => {
      setmessage.value = "name";
      console.log(setmessage.value)
    };
    </script><style></style>
    ​
    ​
    
  • 如果原始对象是响应式的是会更新视图并且改变数据的

    <template>
      <div>
        {{ message.name }}
        -------
        {{ setmessage }}
    ​
        <button @click="onclick">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { ref, toRef } from "vue";
    ​
    let message = ref({
      name: "名称",
    });
    const setmessage = toRef(message, "value");
    ​
    const onclick = (): void => {
      setmessage.value = {
        name: "name",
      };
      console.log(setmessage.value);
    };
    </script><style></style>

toRefs

  • 可以帮我们批量创建ref对象主要是方便我们解构使用

    <template>
      <div>
        {{ message.name }}
        {{ message.age }}
    ​
        <button @click="onclick">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { reactive, toRefs } from "vue";
    ​
    let message = reactive({
      name: "名称",
      age: 18,
    });
    ​
    const onclick = (): void => {
      const { name } = toRefs(message);
      name.value = "name";
    };
    </script><style></style>
    ​
    ​
    

toRaw

  • 将响应式对象转化为普通对象

    <template>
      <div>
        {{ message.name }}
        {{ message.age }}
    ​
        <button @click="onclick">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { reactive, toRaw } from "vue";
    ​
    let message = reactive({
      name: "名称",
      age: 18,
    });
    ​
    const onclick = (): void => {
      const name = toRaw(message);
      console.log(message);//Proxy {name: '名称', age: 18}
      console.log(name);//{name: '名称', age: 18}
    };
    </script><style></style>

Computed计算属性--watch侦听器

computed计算属性

  • 计算属性就是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值。

    <template>
      <div>
        {{ message }}
        {{ com }}
        {{ setage }}
    ​
        <button @click="onclick">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { computed, ref, Ref } from "vue";
    ​
    const message: Ref<string> = ref("name");
    const age: Ref<number> = ref(1);
    // 函数格式
    const com = computed<string>(() => {
      return `${message.value}测试`;
    });
    //对象格式
    const setage = computed({
      get: () => {
        return age.value;
      },
      set: (value) => {
        age.value = value + 1;
      },
    });
    const onclick = (): void => {
      message.value = "22222";
      age.value++;
    };
    </script><style></style>

watch侦听器

  • watch 需要侦听特定的数据源,并在单独的回调函数中执行副作用

  • watch第一个参数监听源 使用数组可以传参监听多个

  • watch第二个参数回调函数cb(newVal,oldVal)使用reactive 回调函数 两个参数都是修改后的值, 如果使用ref的话newVal修改后的值,oldVal未修改的值

  • watch第三个参数一个options配置项是一个对象{immediate:true //是否立即调用一次deep:true //是否开启深度监听} 使用reactive的时候deep开不开启都是一样的,但是ref就会不一样

    <template>
      <div>
        {{ message }}
    ​
        <button @click="onclick">按钮</button>
      </div>
    </template><script setup lang="ts">
    import { reactive, watch, ref } from "vue";
    ​
    const message = reactive({
      name: "名称",
      age: 11,
      bool: {
        sex: "接口",
      },
    });
    const nane = ref({
      name: {
        set: "男",
      },
    });
    // ref 监听
    watch(
      nane,
      (newVal, oldVal) => {
        console.log(newVal, "nane修改后");
        console.log(oldVal, "nane修改前");
      },
      {
        immediate: false,
        deep: false,
      }
    );
    // reactive 监听
    watch(
      message,
      (newVal, oldVal) => {
        console.log(newVal, "message修改后");
        console.log(oldVal, "message修改前");
      },
      {
        immediate: false,
        deep: false,
      }
    );
    // reactive 里面单一监听
    watch(
      () => message.name,
      (newVal, oldVal) => {
        console.log(newVal, "message单一修改后");
        console.log(oldVal, "message单一修改前");
      },
      {
        immediate: false,
        deep: true,
      }
    );
    const onclick = (): void => {
      message.name = "name";
      // nane.value.name.set = "2222"; // deep:true 可以监听到
      nane.value = { name: { set: "222" } }; //都可以监听到
    };
    </script><style></style>

watchEffect高级侦听器

立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

如果用到message 就只会监听message 就是用到几个监听几个 而且是非惰性 会默认调用一次

<template>
  <div>
    {{ message }}
​
    <button @click="onclick">按钮</button>
  </div>
</template><script setup lang="ts">
import { reactive, watchEffect, ref } from "vue";
​
const message = ref("222");
watchEffect(() => {
  console.log(message);
});
const onclick = (): void => {
  message.value = "name";
};
</script><style></style>

清除副作用就是在触发监听之前会调用一个函数可以处理你的逻辑例如防抖

<template>
  <div>
    {{ message }}
​
    <button @click="onclick">按钮</button>
  </div>
</template><script setup lang="ts">
import { reactive, watchEffect, ref } from "vue";
​
const message = ref("222");
watchEffect((oninvalidate) => {
  oninvalidate(() => {
    console.log("22222");
    //这里可以写防抖
  });
  console.log(message, message.value);
});
const onclick = (): void => {
  message.value = "name";
};
</script><style></style>

停止跟踪 watchEffect 返回一个函数 调用之后将停止更新

<template>
  <div>
    {{ message }}
​
    <button @click="onclick">按钮</button>
    <button @click="stop">停止</button>
  </div>
</template><script setup lang="ts">
import { reactive, watchEffect, ref } from "vue";
​
const message = ref(1);
const stop = watchEffect((oninvalidate) => {
  oninvalidate(() => {
    console.log("22222");
    //这里可以写防抖
  });
  console.log(message, message.value);
});
const onclick = (): void => {
  message.value++;
};
</script><style></style>

父子组件传参

defineProps

  • 获取组件传值

    <template>
      <h1>{{ msg }}</h1>
      <div @click="clickThis">1111</div>
    </template><script setup lang="ts">
      defineProps<{ // 采用ts专有声明,无默认值
        msg: string,
        num?: number
      }>()
         // 采用ts专有声明,有默认值
        interface Props {
            msg?: string
            labels?: string[]
        }
        const props = withDefaults(defineProps<Props>(), {
            msg: 'hello',
            labels: () => ['one', 'two']
        })
        
      defineProps({ // 非ts专有声明
        msg: String,
        num: {
          type:Number,
          default: ''
        }
      })
    </script><style scoped lang="less">
    </style>
    

defineEmits

  • 子组件向父组件事件传递

    <template>
      <div @click="clickThis">点我</div>
    </template><script setup lang="ts">
        /*ts专有*/
      const emit= defineEmits<{
        (e: 'click', num: number): void
      }>()
        /*非ts专有*/
      const emit= defineEmits(['click'])
      
      const clickThis = () => {
        emit('click',2)
      }
    </script><style scoped lang="less">
    </style>
    

defineExpose

  • 子组件暴露自己的属性

    <template>
      <div>子组件helloword.vue</div>
    </template><script setup lang="ts">
    import { ref } from 'vue'
    const count = ref(123456)
    defineExpose({
      count
    })
    </script><style scoped lang="less">
    </style>
    
  • 父组件获取属性

    <template>
      <div @click="helloClick">父组件</div>
      <helloword ref="hello"></helloword>
    </template><script setup lang="ts">
    import { ref } from 'vue'
    import helloword from './components/HelloWorld.vue'
    const hello = ref(null)
    const helloClick = () => {
      console.log(hello.value.count) // 123456
    }
    </script>
    ​
    ​
    <style lang="less" scoped>
    </style>
    
    <template>
      <div>
        我是父组件
        <br />
        <button @click="onckick">按钮</button>
        <Onw ref="I" name="我是名称" :data="data" @on-click="getList"></Onw>
      </div>
    </template><script setup lang="ts">
    import { reactive, ref } from "vue";
    import Onw from "./onw.vue";
    const I = ref(null);
    const data = reactive<number[]>([1, 2, 3, 4]);
    ​
    const onckick = () => {
      data.push(1);
    };
    console.log(I.value);
    const getList = (list: number[]): void => {
      console.log(list);
    };
    </script><style></style>
    <template>
      我是子组件
      {{ name }}
      {{ data }}
      <button @click="clickTap">派发给父组件</button>
    </template><script setup lang="ts">
    import { reactive } from "vue";
    ​
    // 接收父组件值
    defineProps<{
      name: string;
      data: number[];
    }>();
    ​
    const list = reactive<number[]>([4, 5, 6]);
    // 子组件暴露改父组件
    defineExpose({
      list,
    });
    const emit = defineEmits(["on-click"]);
    const clickTap = (): void => {
      emit("on-click", [1, 2, 3, 4]);
    };
    </script><style></style>

组件(全局组件,局部组件,递归组件,动态组件)

全局组件

局部组件

递归组件

动态组件

插槽slot

Teleport传送组件

keep-alive缓存组件

自定义指令directive

自定义Hooks--Vue3 hook 库

Vue3定义全局函数和变量

Evnet Loop 和 nextTick

\