Vue3新知识

脚手架构建项目

  • 方式一
    在这里插入图片描述
  • 方式二
    在这里插入图片描述

生命周期在这里插入图片描述

写了多个生命周期时会顺序触发
在这里插入图片描述

获取dom

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

引入字体图标

在这里插入图片描述
index.html里引入
在这里插入图片描述

代码结构

  • Script
    普通的script块允许有多个,但setup的script块不允许有多个
    在这里插入图片描述
    在这里插入图片描述
    下面则是OK的
    在这里插入图片描述
  • Template
    单文件只允许出现一个Template块
    在这里插入图片描述

在这里插入图片描述

Template里允许有多个div
在这里插入图片描述

  • Style
    style块允许出现多个

插件

在这里插入图片描述

模板语法

  • 与表达式向结合

在这里插入图片描述在这里插入图片描述

v-show和v-if区别

v-show操作的是css
v-if是操作元素节点的

点击事件

  • 冒泡
    在这里插入图片描述

在这里插入图片描述
解决
在这里插入图片描述
在这里插入图片描述

  • 默认事件
    在这里插入图片描述

在这里插入图片描述
点击后会刷新页面
解决
在这里插入图片描述

在这里插入图片描述

动态样式

  • 案例1

在这里插入图片描述

在这里插入图片描述

  • 案例二
    在这里插入图片描述
    在这里插入图片描述
  • 案例三
    在这里插入图片描述
    在这里插入图片描述
  • 案例四
    在这里插入图片描述
    在这里插入图片描述
  • 案例五
    在这里插入图片描述

在这里插入图片描述
如果是对象,需要加引号
在这里插入图片描述

  • 案例六
    在这里插入图片描述
    在这里插入图片描述
    $style也可以自定义名称
    在这里插入图片描述
  • 案例7
    当y大于78时,添加show的class
    在这里插入图片描述

ref

  • 复杂类型
    在这里插入图片描述
  • 自定义ref
    在这里插入图片描述
  • customRef实现防抖
    在这里插入图片描述

reactive

  • 数组添加元素
    在这里插入图片描述

to系列

  • toRef对非响应式对象无效
    在这里插入图片描述
    在这里插入图片描述
    点击无效

在这里插入图片描述
在这里插入图片描述
点击变化

应用场景:
例如一个方法需要传参,参数是一个对象里的某个属性,且需要这个参数是响应式的

  • toRefs
    在这里插入图片描述
    在这里插入图片描述
  • toRaw
    在这里插入图片描述
    在这里插入图片描述

computed

在这里插入图片描述

在这里插入图片描述
另一种写法
在这里插入图片描述

计算属性里不应该有副作用(如在计算里修改dom,请求数据等)

watch

  • 基本用法
    在这里插入图片描述
    在这里插入图片描述
  • 监听多个
    在这里插入图片描述
    或者
    在这里插入图片描述

在这里插入图片描述

  • 深度监听
    在这里插入图片描述

在这里插入图片描述

  • 精确的深度监听
    在这里插入图片描述

  • 第一次就触发监听
    在这里插入图片描述

在这里插入图片描述

  • 监听对象的单一属性
    字符类型需使用回调函数
    在这里插入图片描述
    在这里插入图片描述

watchEffect

  • 监听单个
    在这里插入图片描述

在这里插入图片描述

  • 监听多个
    在这里插入图片描述

在这里插入图片描述

  • 监听之前操作
    在这里插入图片描述
    在这里插入图片描述

  • 停止监听

在这里插入图片描述
在这里插入图片描述

组件生命周期

A.vue

<template>
  <div>{{ msg }}</div>
  <button @click="update">更新组件</button>
</template>

<script lang="ts" setup>
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  ref,
} from "vue";

const msg = ref("我是个组件");

const update = () => {
  msg.value = "我被更新了";
};

// 挂载前
onBeforeMount(() => {
  console.log("挂载前");
});

// 挂载完成
onMounted(() => {
  console.log("挂载完成");
});

// 更新前
onBeforeUpdate(() => {
  console.log("更新前");
});

// 更新完成
onUpdated(() => {
  console.log("更新完成");
});

// 卸载前
onBeforeUnmount(() => {
  console.log("卸载前");
});

// 卸载完成
onUnmounted(() => {
  console.log("卸载完成");
});
</script>
<style lang="scss" scoped></style>

APP.vue

<template>
  <A v-if="flag"></A>
  <br />
  <button @click="flag = !flag">组件卸载</button>
</template>

<script setup lang="ts">
import { ref } from "vue";
import A from "@/components/A.vue";

const flag = ref(true);

console.log("setup");
</script>

<style scoped></style>

在这里插入图片描述

父传子

在这里插入图片描述

  • 子组件
<template>
  <div>我是子组件:{{ name }}</div>
</template>

<script lang="ts" setup>
const props = defineProps({
  name: {
    type: String,
    default: "xiaohong",
    requier: false,
  },
});
</script>
<style lang="scss" scoped></style>

  • 父组件
<template>
  <input type="text" v-model="myName" />
  <A :name="myName"></A>
</template>

<script setup lang="ts">
import { ref } from "vue";
import A from "@/components/A.vue";

const myName = ref("");

console.log("setup");
</script>

<style scoped></style>

子传父

在这里插入图片描述

  • 子组件
<template>
  <button @click="send">子组件更新</button>
</template>

<script lang="ts" setup>
const emit = defineEmits(["update"]);

const send = () => {
  emit("update", "我是来自子组件的数据");
};
</script>
<style lang="scss" scoped></style>

  • 父组件
<template>
  <input type="text" v-model="myName" />
  <A @update="updateFromChild"></A>
</template>

<script setup lang="ts">
import { ref } from "vue";
import A from "@/components/A.vue";

const myName = ref("");

const updateFromChild = (newVal: string) => {
  myName.value = newVal;
};
</script>

<style scoped></style>

父调子里的方法和参数

在这里插入图片描述
在这里插入图片描述

子组件

<template>
  <div>我是子组件</div>
</template>

<script lang="ts" setup>
defineExpose({
  name: "xiaohong",
  open: () => {
    console.log("我是子组件里的open方法");
  },
});
</script>
<style lang="scss" scoped></style>

父组件

<template>
  <A ref="myA"></A>
</template>

<script setup lang="ts">
import { onMounted, ref } from "vue";
import A from "@/components/A.vue";

// 变量名字需要与ref的值一致
const myA = ref<InstanceType<typeof A>>();

onMounted(() => {
  console.log(myA.value?.name);
  myA.value?.open();
});
</script>

<style scoped></style>

在这里插入图片描述

跨层组件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

局部组件

上面都是

全局组件

main.ts里注册
在这里插入图片描述

递归组件

在这里插入图片描述
可以自定义当前组件的名称,在script块内
在这里插入图片描述
在这里插入图片描述

需要注意的是递归组件会有点击冒泡
在这里插入图片描述

动态组件

<template>
  <div style="display: flex">
    <div
      class="tabs"
      v-for="(item, index) in data"
      :key="index"
      @click="comId = item.com"
    >
      <div>{{ item.name }}</div>
    </div>
  </div>
  <component :is="comId"></component>
</template>

<script setup lang="ts">
import { reactive, markRaw, shallowRef } from "vue";
import A from "@/components/A.vue";
import B from "@/components/B.vue";
import C from "@/components/C.vue";

const comId = shallowRef(A);

const data = reactive([
  {
    name: "A组件",
    com: markRaw(A),
  },
  {
    name: "B组件",
    com: markRaw(B),
  },
  {
    name: "C组件",
    com: markRaw(C),
  },
]);
</script>

<style scoped>
.tabs {
  border: 1px solid #ccc;
  padding: 5px 10px;
  margin: 5px;
  cursor: pointer;
}
</style>

在这里插入图片描述
注意这里使用了markRaw和shallowRef
不然会报警告

插槽

  • 匿名插槽
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 具名插槽
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 插槽传值
    子组件
<template>
  <div style="color: red">我是上面<slot name="up"></slot></div>
  <div style="color: red" v-for="(item, index) in datas" :key="index">
    <slot name="center" :item="item" :index="index"></slot>
  </div>
  <div style="color: red">我是下面<slot name="foot"></slot></div>
</template>

<script lang="ts" setup>
import { reactive } from "vue";

type names = {
  name: string;
  age: number;
};

const datas = reactive<names[]>([
  {
    name: "name1",
    age: 18,
  },
  {
    name: "name2",
    age: 19,
  },
  {
    name: "name3",
    age: 20,
  },
]);
</script>
<style lang="scss" scoped></style>

父组件

<template>
  <A>
    <template v-slot:center="{ item, index }">
      <div>{{ item }} ---- {{ index }}</div>
    </template>
  </A>
</template>

<script setup lang="ts">
import A from "@/components/A.vue";
</script>

<style scoped></style>

在这里插入图片描述

v-slot可以简写成#
在这里插入图片描述
在这里插入图片描述

  • 动态插槽
    在这里插入图片描述

直接访问json数据

将json数据放在public目录下
在这里插入图片描述
启动服务,直接用浏览器访问即可
在这里插入图片描述

使用ts封装axios

export const axios = {
  get<T>(url: string): Promise<T> {
    return new Promise<T>((resolve) => {
      const xhr = new XMLHttpRequest();
      xhr.open("GET", url);
      xhr.send();
      xhr.onreadystatechange = () => {
        // 0 -(未初始化)还没有调用send()方法
        // 1 -(载入)已调用send()方法,正在发送请求
        // 2-(载入完成) send()方法执行完成,已经接收到全部响应内容3 -(交互)正在解析响应内容
        // 4 -(完成)响应内容解析完成,可以在客户端调用了

        if (xhr.readyState == 4 && xhr.status == 200) {
          // 模拟响应时间
          setTimeout(() => {
            resolve(JSON.parse(xhr.responseText));
          }, 2000);
        }
      };
    });
  },
};

使用
在这里插入图片描述

<script lang="ts" setup>
import { axios } from "@/server/axios";

interface Data {
  data: {
    name: string;
    age: string;
    url: string;
    desc: string;
  };
}

const { data } = await axios.get<Data>("./data.json");
</script>

异步组件和suspense

<template>
  <Suspense>
    <template #default>
      <!-- 数据加载完成时显示的内容 -->
      <SyncVue></SyncVue>
    </template>
    <template #fallback>
      <!-- 数据未加载完成时显示的内容 -->
      <Skeleton></Skeleton>
    </template>
  </Suspense>
</template>

<script setup lang="ts">
import { defineAsyncComponent } from "vue";
// 骨架屏
import Skeleton from "@/components/skeleton.vue";

// 异步引入组件
const SyncVue = defineAsyncComponent(() => import("@/components/sync.vue"));
</script>

<style scoped></style>

defineAsyncComponent的另一种写法
在这里插入图片描述

异步组件在打包的时候会被单独拆出来,在使用到的时候才会去加载,算一种调优手段
在这里插入图片描述

Teleport

加前
在这里插入图片描述
在这里插入图片描述

加后
在这里插入图片描述
在这里插入图片描述

keep-alive

未加
在这里插入图片描述
在这里插入图片描述
切换组件不缓存值
加上keep-live
在这里插入图片描述

在这里插入图片描述
切换也有值

如果只想缓存B组件
在这里插入图片描述
注意数组里面填的需要是组件的名称
没有的记得去组件里面加上
在这里插入图片描述

排除某个组件不缓存
在这里插入图片描述
这里同样也需要组件有名称

最大缓存组件数量
在这里插入图片描述
内部算法,将不常用的给忽略

加入keep-alive后的生命周期
在这里插入图片描述

在这里插入图片描述

transition

<template>
  <button @click="flag = !flag">切换</button>
  <Transition name="fade">
    <div v-if="flag" class="box"></div>
  </Transition>
</template>

<script setup lang="ts">
import { ref } from "vue";

const flag = ref(false);
</script>

<style scoped>
.box {
  width: 200px;
  height: 200px;
  background-color: green;
}

/* 进入之前 */
.fade-enter-from {
  width: 0px;
  height: 0px;
}

/* 进入时 */
.fade-enter-active {
  transition: all 1.5s ease;
}

/* 退出 */
.fade-enter-to {
  width: 200px;
  height: 200px;
}
</style>

在这里插入图片描述
自定义动画样式名
在这里插入图片描述
如结合第三方库animate.css使用

在这里插入图片描述
定义动画时间
在这里插入图片描述
transition生命周期
在这里插入图片描述
页面加载完成就触发动画
在这里插入图片描述
在这里插入图片描述

transition-group

  • 渲染列表动画时使用
    在这里插入图片描述

在这里插入图片描述

  • 实现动态数字列表移动过渡
<template>
  <div>
    <button @click="random">random</button>
    <TransitionGroup move-class="mct" class="wraps" tag="div">
      <div v-for="item in list" :key="item.id" class="items">
        {{ item.number }}
      </div>
    </TransitionGroup>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import _ from "lodash";

let list = ref(
  Array.apply(null, { length: 81 } as number[]).map((_, index) => {
    return {
      id: index,
      number: (index % 9) + 1,
    };
  })
);

const random = () => {
  list.value = _.shuffle(list.value);
};
</script>

<style scoped lang="less">
.wraps {
  display: flex;
  flex-wrap: wrap;
  width: calc(25px * 9 + 9px);
  .items {
    width: 25px;
    height: 25px;
    border: 1px solid #ccc;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}

.mct {
  transition: all 1.5s;
}
</style>

在这里插入图片描述

  • 状态过渡
<template>
  <div>
    <input type="number" step="20" v-model="num.current" />
    <div>
      {{ num.tweenedNumber.toFixed(0) }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, watch } from "vue";
import gsap from "gsap";

const num = reactive({
  current: 0,
  tweenedNumber: 0,
});

watch(
  () => num.current,
  (newVal, oldVal) => {
    gsap.to(num, {
      duration: 1,
      tweenedNumber: newVal,
    });
  }
);
</script>

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


在这里插入图片描述
数字变化动画

mitt

用来兄弟组件传参
在这里插入图片描述
加入

import { createApp } from "vue";
import App from "./App.vue";

import "./assets/main.css";
import A from "@/components/A.vue";
import mitt from "mitt";

const Mit = mitt();

declare module "vue" {
  export interface ComponentCustomProperties {
    $Bus: typeof Mit;
  }
}

const app = createApp(App);

app.config.globalProperties.$Bus = Mit

app.component("MyA", A);

app.mount("#app");

使用
B组件

<template>
  <div>我是B组件</div>
  <input type="text" v-model="msg" />
  <button @click="emit">发送</button>
</template>

<script lang="ts" setup>
import { ref, getCurrentInstance } from "vue";

const msg = ref("");
const instance = getCurrentInstance();
const emit = () => {
  instance?.proxy?.$Bus.emit("on-send", msg.value);
};
</script>
<style lang="scss" scoped></style>

C组件

<template>
  <div>我是C组件</div>
  <input type="text" v-model="msg" />
</template>

<script lang="ts" setup>
import { ref, getCurrentInstance } from "vue";

const msg = ref("");
const instance = getCurrentInstance();

instance?.proxy?.$Bus.on("on-send", (str) => {
  msg.value = "来自B===>" + JSON.stringify(str);
});
</script>
<style lang="scss" scoped></style>

在这里插入图片描述

父子组件v-model

  • 单个v-model
    父组件
<template>
  <div>我是父组件</div>
  <div>msg===>{{ msg }}</div>
  <input type="text" v-model="msg" />

  <A v-model="msg"></A>
</template>

<script setup lang="ts">
import { ref } from "vue";
import A from "@/components/A.vue";

const msg = ref<string>("");
</script>

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

子组件

<template>
  <div>我是A组件</div>
  <div>收到父组件值===>{{ modelValue }}</div>
  <input type="text" v-model="msgA" /><button @click="update">send</button>
</template>

<script lang="ts" setup>
import { ref } from "vue";

// modelValue是固定名称
defineProps<{
  modelValue: string;
}>();

const msgA = ref("");

// update:modelValue是固定名称
const emit = defineEmits(["update:modelValue"]);

const update = () => {
  console.log("触发了");

  emit("update:modelValue", msgA.value);
};
</script>
<style lang="scss" scoped></style>

  • 多v-model
    父组件
<template>
  <div>我是父组件</div>
  <div>msg===>{{ msg }}</div>
  msg: <input type="text" v-model="msg" /> text:
  <input type="text" v-model="text" />

  <A v-model="msg" v-model:text="text"></A>
</template>

<script setup lang="ts">
import { ref } from "vue";
import A from "@/components/A.vue";

const msg = ref<string>("");
const text = ref<string>("");
</script>

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

子组件

<template>
  <div>我是A组件</div>
  <div>收到msg===>{{ modelValue }}</div>
  <div>收到text===>{{ text }}</div>
  <input type="text" v-model="msgA" @input="updateMsg" />
  <input type="text" v-model="textA" @input="updateText" />
</template>

<script lang="ts" setup>
import { ref } from "vue";

// modelValue是固定名称
defineProps<{
  modelValue: string;
  text: string;
}>();

const msgA = ref("");
const textA = ref("");

// update:modelValue是固定名称
const emit = defineEmits(["update:modelValue", "update:text"]);

const updateMsg = () => {
  emit("update:modelValue", msgA.value);
};

const updateText = () => {
  emit("update:text", textA.value);
};
</script>
<style lang="scss" scoped></style>

  • 自定义v-model属性
    在这里插入图片描述

不加.isBt
在这里插入图片描述
在这里插入图片描述
加.isBt

在这里插入图片描述
在这里插入图片描述

directive自定义指令

在这里插入图片描述

  • 在mounted打印出所有信息
<template>
  <div>我是父组件</div>
  <A v-move:aaa.xiaohong="{ background: 'red' }"></A>
</template>

<script setup lang="ts">
import type { Directive } from "vue";
import A from "@/components/A.vue";

// 自定义指令名字必须以v开头
const vMove: Directive = {
  // 元素初始化的时候
  created() {
    console.log("===>created");
  },
  // 指令绑定到元素后调用,只调用一次
  beforeMount() {
    console.log("===>beforeMount");
  },
  // 元素插入父级dom调用
  mounted(...args: Array<any>) {
    console.log("===>mounted");
    console.log(args);
  },
  // 元素被更新之前调用
  beforeUpdate() {
    console.log("===>beforeUpdate");
  },
  // 元素更新后调用
  updated() {
    console.log("===>updated");
  },
  // 在元素被移除前调用
  beforeUnmount() {
    console.log("===>beforeUnmount");
  },
  // 执行被移除后调用,只调用一次
  unmounted() {
    console.log("===>unmounted");
  },
};
</script>

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

在这里插入图片描述

  • 具体解析
<template>
  <div>我是父组件</div>
  <A v-move:aaa.xiaohong="{ background: 'red' }" class="box"></A>
</template>

<script setup lang="ts">
import type { Directive, DirectiveBinding } from "vue";
import A from "@/components/A.vue";
type Dir = {
  background: string;
};

// 自定义指令名字必须以v开头
const vMove: Directive = {
  // 元素初始化的时候
  created() {
    console.log("===>created");
  },
  // 指令绑定到元素后调用,只调用一次
  beforeMount() {
    console.log("===>beforeMount");
  },
  // 元素插入父级dom调用
  mounted(el: HTMLElement, dir: DirectiveBinding<Dir>) {
    console.log("===>mounted");
    el.style.backgroundColor = dir.value.background;
  },
  // 元素被更新之前调用
  beforeUpdate() {
    console.log("===>beforeUpdate");
  },
  // 元素更新后调用
  updated() {
    console.log("===>updated");
  },
  // 在元素被移除前调用
  beforeUnmount() {
    console.log("===>beforeUnmount");
  },
  // 执行被移除后调用,只调用一次
  unmounted() {
    console.log("===>unmounted");
  },
};
</script>

<style scoped lang="less">
.box {
  height: 200px;
  width: 200px;
}
</style>

在这里插入图片描述

  • 简写
<template>
  <div>我是父组件</div>
  <input type="text" v-model="color" />
  <A v-move="{ background: color }" class="box"></A>
</template>

<script setup lang="ts">
import type { Directive, DirectiveBinding } from "vue";
import { ref } from "vue";
import A from "@/components/A.vue";

const color = ref("");

type Dir = {
  background: string;
};

const vMove: Directive = (el: HTMLElement, dir: DirectiveBinding<Dir>) => {
  el.style.backgroundColor = dir.value.background;
};
</script>

<style scoped lang="less">
.box {
  height: 200px;
  width: 200px;
}
</style>

在这里插入图片描述

  • 自定义拖拽指令
<template>
  <div v-move>
    <div class="box">我是父组件</div>
  </div>
</template>

<script setup lang="ts">
import type { Directive, DirectiveBinding } from "vue";
import { ref } from "vue";
import A from "@/components/A.vue";

const vMove: Directive = (el: HTMLElement, bingding: DirectiveBinding) => {
  console.log(el);

  let moveElement: HTMLDivElement = el.firstElementChild as HTMLDivElement;

  const mouseDown = () => {
    const move = (e: MouseEvent) => {
      // let X = e.clientX - el.offsetLeft;
      // let Y = e.clientY - el.offsetTop;
      el.style.left = e.clientX + "px";
      el.style.top = e.clientY + "px";
    };
    document.addEventListener("mousemove", move);
    document.addEventListener("mouseup", () => {
      document.removeEventListener("mousemove", move);
    });
  };

  moveElement.addEventListener("mousedown", mouseDown);
};
</script>

<style scoped lang="less">
.box {
  height: 200px;
  width: 200px;
  text-align: center;
  background-color: #ccc;
}
</style>

hooks

  • 自定义将图片转base64的hook
    useBase64.ts
import { onMounted } from "vue";

type Options = {
  el: string;
};

export default function (options: Options): Promise<{ baseUrl: string }> {
  return new Promise((resolve) => {
    onMounted(() => {
      const img: HTMLImageElement = document.querySelector(
        options.el
      ) as HTMLImageElement;
      console.log(img, "=====>");
      img.onload = () => {
        resolve({
          baseUrl: base64(img),
        });
      };
    });

    const base64 = (el: HTMLImageElement) => {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      canvas.width = el.width;
      canvas.height = el.height;
      ctx?.drawImage(el, 0, 0, canvas.width, canvas.height);
      return canvas.toDataURL("image/png");
    };
  });
}

App.vue

<template>
  <div v-move>
    <img id="img" width="300" height="300" src="./assets/inther.png" alt="" />
  </div>
</template>

<script setup lang="ts">
import useBase64 from "./hooks/useBase64";

useBase64({
  el: "#img",
}).then((res) => {
  console.log(res.baseUrl);
});
</script>

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

在这里插入图片描述

定义全局变量和函数

main.ts

import { createApp } from "vue";
import App from "./App.vue";

import "./assets/main.css";
import A from "@/components/A.vue";
import mitt from "mitt";

const Mit = mitt();

declare module "vue" {
  export interface ComponentCustomProperties {
    $Bus: typeof Mit;
  }
}

const app = createApp(App);

app.config.globalProperties.$Bus = Mit;

// 定义全局变量
app.config.globalProperties.$env = "env";

// 定义全局方法
app.config.globalProperties.$filters = {
  format<T>(str: T) {
    return `小鸿-${str}`;
  },
};

type Filter = {
  format<T>(str: T): string;
};

// 对全局变量和方法进行声明,解决报错
declare module "vue" {
  export interface ComponentCustomProperties {
    $filters: Filter;
    $env: string;
  }
}

app.component("MyA", A);

app.mount("#app");

App.vue

<template>
  <div>
    {{ $env }}
  </div>
  <div>
    {{ $filters.format("Hello World") }}
  </div>
</template>

<script setup lang="ts">
// 在script里使用

import { getCurrentInstance } from "vue";

const instance = getCurrentInstance();

console.log(instance?.proxy?.$env);
</script>

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

在这里插入图片描述

自定义插件

  • 目录结构
    在这里插入图片描述
  • index.ts
import type { App, VNode } from "vue";
import Loading from "./index.vue";
import { createVNode, render } from "vue";

export default {
  install(app: App) {
    // 将组件转成Vnode
    const Vn: VNode = createVNode(Loading);
    // 将组件挂载到body上
    render(Vn, document.body);
    // 全局挂载方法
    app.config.globalProperties.$loading = {
      show: Vn.component?.exposed?.show,
      hide: Vn.component?.exposed?.hide,
    };

    // 调用全局方法
    // app.config.globalProperties.$loading.show();
  },
};

  • index.vue
<template>
  <div v-if="isShow" class="loading">Loading</div>
</template>

<script lang="ts" setup>
import { ref } from "vue";
const isShow = ref(false);

const show = () => (isShow.value = true);

const hide = () => (isShow.value = false);

defineExpose({
  isShow,
  show,
  hide,
});
</script>
<style scoped>
.loading {
  background: black;
  opacity: 0.2;
  font-size: 30px;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  color: white;
}
</style>

  • main.ts
import { createApp } from "vue";
import App from "./App.vue";

import "./assets/main.css";
import Loading from "./components/Loading";

const app = createApp(App);

type Lod = {
  show: () => void;
  hide: () => void;
};

// 编写ts 解决loading 声明文件放置错误和智能提示
declare module "vue" {
  export interface ComponentCustomProperties {
    $loading: Lod;
  }
}
app.use(Loading);

app.mount("#app");

  • App.vue
<template>
  <div></div>
</template>

<script setup lang="ts">
import { getCurrentInstance } from "vue";

const instance = getCurrentInstance();

instance?.proxy?.$loading.show();

setTimeout(() => {
  instance?.proxy?.$loading.hide();
}, 5000);
</script>

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

  • 效果
    在这里插入图片描述
    5s后消失

deep

在这里插入图片描述

选择器

  • 插槽选择器

父组件
在这里插入图片描述
子组件
在这里插入图片描述
效果
在这里插入图片描述

  • 全局选择器
    在这里插入图片描述

在这里插入图片描述

环境变量

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
默认是生产环境
在这里插入图片描述
切换环境
在这里插入图片描述

在这里插入图片描述
在ts里使用
vite.config.ts

import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { loadEnv } from "vite";

// https://vitejs.dev/config/
export default ({ mode }: any) => {
  // 获取当前环境
  // development 生产环境
  // production 线上环境
  console.log(mode);
  // 获取对应环境变量文件里的内容
  console.log(loadEnv(mode, process.cwd()));

  return defineConfig({
    plugins: [vue()],
    resolve: {
      alias: {
        "@": fileURLToPath(new URL("./src", import.meta.url)),
      },
    },
  });
};

在这里插入图片描述

Pinia

重置

在这里插入图片描述

监听

Test里的内容每次改变都会触发
在这里插入图片描述
在这里插入图片描述
也可以加参数
detached: 组件销毁后是否继续监听
deep: 是否深度监听
flush: 监听的时机
在这里插入图片描述

调用action监听

在这里插入图片描述
在这里插入图片描述

加参数
组件销毁后是否继续监听
在这里插入图片描述

小案例

在这里插入图片描述
在这里插入图片描述

getters

在这里插入图片描述
在这里插入图片描述

action异步

在这里插入图片描述
在这里插入图片描述

响应式丢失

在这里插入图片描述
在这里插入图片描述

调试

在这里插入图片描述
在这里插入图片描述

router

  • router-link和a标签的区别
    router-link不会刷新页面
    a标签会刷新当前页面

  • 利用name跳转
    在这里插入图片描述

在这里插入图片描述

  • 编程式跳转
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 不保留历史记录
    在这里插入图片描述
  • 编程前进后退
    在这里插入图片描述
  • 路由传参
  1. query传参
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. params传参
    只能用name跳转
    在这里插入图片描述
    传递的产生不会展示在url上,而是存在内存里
    在这里插入图片描述

  3. 动态路由参数
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 路由重定向

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 别名
    在这里插入图片描述
    配置后访问/root,/root1,/root2都是同一页面

  • 前置守卫

在这里插入图片描述
beforeEach可以有多个,next()表示进入到下一个beforeEach

  • 后置守卫

在这里插入图片描述
这里用来做进度条

  • 路由元信息
    在这里插入图片描述
    在这里插入图片描述

  • 路由过渡动效
    在这里插入图片描述
    在这里插入图片描述

  • 滚动行为
    在这里插入图片描述
    切换回来可以保持之前的页面位置
    在这里插入图片描述
    也可以加上延时

  • 动态路由
    后端返回内容
    在这里插入图片描述
    动态添加
    在这里插入图片描述

json转ts插件

在这里插入图片描述
选中需要转换的json
ctrl+alt+shift+s
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值