vue3学习笔记(一)组件基础+路由+组合式API+Pinia

文章目录

1. vite 的基本使用

vite官网:https://vitejs.cn
vue官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite

  • vite:新一代前端构建工具。
  • 相比 webpack 优势如下:
    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热重载(HMR)。
    • 真正的按需编译,不再等待整个应用编译完成。

1.1 创建vite的项目

按照顺序执行如下的命令,即可基于vite 创建 vue 3.x 的工程化项目:

npm init vite@latest
// 中间根据提示来构建vue3项目
cd deom
npm install
npm run dev

在这里插入图片描述

1.2 梳理项目的结构

使用 vite 创建的项目结构如下:

  • node_modules 目录用来存放第三方依赖包
  • public 是公共的静态资源目录
  • src 是项目的源代码目录(程序员写的所有代码都要放在此目录下)
  • .gitignore 是 Git 的忽略文件
  • index.html 是SPA 单页面应用程序中唯一的HTML 页面
  • package.json 是项目的包管理配置文件
  • vite.config.js 是 vite 的配置文件

在这里插入图片描述

在 src 这个项目源代码目录之下,包含了如下的文件和文件夹:

  • assets 目录用来存放项目中所有的静态资源文件(css、fonts等)
  • components 目录用来存放项目中所有的自定义组件
  • App.vue 是项目的根组件
  • index.css 是项目的全局样式表文件(上图没有)
  • main.js 是整个项目的打包入口文件

1.3 vite 项目的运行流程

在工程化的项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。其中:
① App.vue 用来编写待渲染的模板结构
② index.html 中需要预留一个el 区域
③ main.js 把 App.vue 渲染到了 index.html 所预留的区域中

  • 步骤一:在 App.vue 中编写模板结构
    清空 App.vue 的默认内容,并书写如下的模板结构:
<template>
  <h1>这是App.vue根组件</h1>
</template>
  • 步骤二:打开 index.html 页面,确认预留了el 区域:
<body>
  <!--id 为app的div元素,就是将来vue要控制的区域 -->
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
  • 步骤三:在main.js 中进行渲染
    按照 vue 3.x 的标准用法,把 App.vue 中的模板内容渲染到index.html 页面的el 区域中:
// 1.从vue中按需引入一个名为createApp的工厂函数:作用创建vue的“单页面应用程序实例”
import {
    createApp } from "vue";
// 2. 导入待渲染的App组件
import App from "./App.vue";
// 3.调用createApp()函数,返回值是“单页面应用程序实例对象”,用常量spa_app接收
// 同时把App组件作为参数传给createApp函数,表示要把App渲染到index.html页面上
const spa_app = createApp(App);
// 4. 挂载:调用spa_app实例的mount方法,用来指定vue实际要控制的区域
spa_app.mount("#app");
// createApp(App).mount("#app"); 可以简写

建议安装vue3开发者工具插件
在这里插入图片描述

2. 组件的基本使用

2.1 注册组件的两种方式

vue 中注册组件的方式分为“全局注册”和“局部注册”两种,其中:

  • 被全局注册的组件,可以在全局任何一个组件内使用
  • 被局部注册的组件,只能在当前注册的范围内使用

2.2 全局注册组件

使用 app.component() 方法注册的全局组件,直接以标签的形式进行使用即可

import {
    createApp } from "vue";
import App from "./App.vue";
// 1.在main.js文件中,  导入需要被全局注册的组件
import Left from "./components/Left.vue";
import Right from "./components/Right.vue";
const spa_app = createApp(App);
// 2. 调用spa_app实例的component()方法全局注册组件
spa_app.component("my-left", Left);
spa_app.component("my-right", Right);
spa_app.mount("#app");
<template>
  <h1>这是App.vue根组件</h1>
  <!-- 在其他组件中,直接以标签的形式,使用全局注册过的组件 -->
  <my-left></my-left>
  <my-right></my-right>
</template>

2.3 局部祖册

<template>
  <h1>这是App.vue根组件</h1>
  <my-left></my-left>
</template>
<script>
// 导入需要的组件
import Left from "./components/Left.vue";
export default {
     
  // 2. 通过 components节点,为当前组件注册私有子组件
  components: {
     
    "my-left": Left,
  },
};
</script>

2.4 全局注册和局部注册的区别

  • 被全局注册的组件,可以在全局任何一个组件内使用
  • 被局部注册的组件,只能在当前注册的范围内使用

应用场景:

  • 如果某些组件在开发期间的使用频率很高,推荐进行全局注册;
  • 如果某些组件只在特定的情况下会被用到,推荐进行局部注册。

2.5 组件注册时名称的大小写

在进行组件的注册时,定义组件注册名称的方式有两种:

  • ① 使用 kebab-case 命名法(俗称短横线命名法,例如 my-swiper 和 my-search)
    短横线命名法的特点:必须严格按照短横线名称进行使用
  • ② 使用 PascalCase 命名法(俗称帕斯卡命名法或大驼峰命名法,例如 MySwiper 和 MySearch)
    帕斯卡命名法的特点:既可以严格按照帕斯卡名称进行使用,又可以转化为短横线名称进行使用

2.6 通过 name 属性注册组件

在注册组件期间,除了可以直接提供组件的注册名称之外,还可以把组件的 name 属性作为注册后组件的名称,示例代码如下:

在这里插入图片描述

3. 自定义事件

3.1 什么是自定义事件

在封装组件时,为了让组件的使用者可以监听到组件内状态的变化,此时需要用到组件的自定义事件。

在这里插入图片描述

3.2 自定义事件的 3 个使用步骤

  • 在封装组件时:
    ① 声明自定义事件
    ② 触发自定义事件
  • 在使用组件时:
    ③ 监听自定义事件

3.2.1 声明自定义事件

开发者为自定义组件封装的自定义事件,必须事先在 emits 节点中声明,示例代码如下:

<template>
  <div>
    <h2>Counter 组件</h2>
    <p>count 的值为 {
   {
    count }}</p>
    <button @click="add">点击加1</button>
  </div>
</template>
<script>
export default {
   
  // 1.申明自定义事件
  emits: ["countChange"],// 为当前Counter组件在emits节点下申明自定义事件
</script>

3.2.2 触发自定义事件

在 emits 节点下声明的自定义事件,可以通过 this.$emit('自定义事件的名称') 方法进行触发,示例代码如下:

<template>
  <div>
    <h2>Counter 组件</h2>
    <p>count 的值为 {
  { count }}</p>
    <button @click="add">点击加1</button>
  </div>
</template>
<script>
export default {
     
  // 1.申明自定义事件
  emits: ["countChange"],
  data() {
     
    return {
     
      count: 0,
    };
  },
  methods: {
     
    add() {
     
      this.count++;
      // 2. this.$emit()触发自定义事件,
      // 参数为在emits节点下申明过的自定义事件名
      this.$emit("countChange");
       // 当点击加1按钮,调用了add()函数,自动触发了countChange事件
    },
  },
};
</script>

3.2.3 监听自定义事件

在使用自定义的组件时,可以通过 v-on (简写@)的形式监听自定义事件。示例代码如下:

<template>
  <div class="app-container">
    <h1>这是App.vue根组件</h1>
    <!-- 当前在app组件中,使用了Counter组件,并监听了countChange事件-->
    <!--一旦监听到了Counter组件的countChange事件,就调用getCount函数-->
    <Counter @countChange="getCount"></Counter>
  </div>
</template>
<script>
import Counter from "./components/Counter.vue";
export default {
     
  components: {
     
    Counter,
  },
  methods: {
     
    getCount() {
     
      console.log("触发了countChange自定义事件");
    },
  },
};
</script>

3.3 自定义事件传参

在调用 this.$emit() 方法触发自定义事件时,可以通过第 2 个参数为自定义事件传参,示例代码如下:

// ======事件触发方
methods: {
   
  add() {
   
    this.count++;
    // 2. 触发自定义事件时,通过第二个参数传参
    this.$emit("countChange", this.count);
  },
},
//===========事件监听方
methods: {
   
  getCount(val) {
   
    console.log("触发了countChange自定义事件", val);
  },
},

4. 组件上的 v-model

4.1 为什么需要在组件上使用 v-model

v-model 是双向数据绑定指令,当需要维护组件内外数据的同步时,可以在组件上使用 v-model 指令。示意图如下:

在这里插入图片描述

counter 组件中数据的变化,也会自动同步到外界

外界数据的变化会自动同步到 counter 组件中

4.2 在组件上使用 v-model 的步骤

4.2.1 父向子

① 父组件通过 v-bind: 属性绑定的形式,把数据传递给子组件
② 子组件中,通过 props 接收父组件传递过来的数据

在这里插入图片描述

实现点击父组件app中加1按钮,把数据同步到子组件中

<!-- ===================App父组件 -->
<template>
  <div class="app-container">
    <h1>这是App.vue根组件---{
  { count }}</h1>
    <!-- 通过number自定义属性,给 Counter 组件传一个 count 的值 -->
    <Counter v-model="count" :number="count"></Counter>
    <button @click="count++">点击加1</button>
  </div>
</template>
<script>
import Counter from "./components/Counter.vue";
export default {
     
  data() {
     
    return {
     
      count: 0,
    };
  },
  components: {
     
    Counter,
  },
};
</script>

<!-- =========================Counter子组件 -->
<template>
  <div>
    <h2>Counter 组件</h2>
    <p>count 的值为 {
  { number }}</p>
  </div>
</template>
<script>
export default {
     
  // 接收从外部传来的数据
  props: ["number"],
};
</script>

4.2.2 子向父

① 在 v-bind: 指令之前添加 v-model 指令
② 在子组件中声明 emits 自定义事件,格式为 update:xxx
③ 调用 $emit() 触发自定义事件,更新父组件中的数据

在这里插入图片描述

点击子组件的加1按钮,把数据同步给父组件

//==================app父组件
<template>
  <div class="app-container">
    <h1>这是App.vue根组件---{
  { count }}</h1>
    <Counter v-model:number="count"></Counter>
  </div>
</template>
<script>
import Counter from "./components/Counter.vue";
export default {
     
  data() {
     
    return {
     
      count: 0,
    };
  },
  components: {
     
    Counter,
  },
};
</script>
// =================== Counter子组件
<template>
  <div>
    <h2>Counter 组件</h2>
    <p>count 的值为 {
  { number }}</p>
    <button @click="add">点击加1</button>
  </div>
</template>
<script>
export default {
     
  props: ["number"],
  emits: ["update:number"],
  methods: {
     
    add() {
     
      this.$emit("update:number", this.number + 1);
    },
  },
};
</script>

5. 组件的生命周期

注意:选项式 API 和组合式 API 的生命周期有差异,具体参照vue3官方;下面以选项式为例

5.1 组件运行的过程

在这里插入图片描述

组件的生命周期指的是:组件从创建 -> 运行(渲染) -> 销毁的整个过程,强调的是一个时间段。

5.2 如何监听组件的不同时刻

vue 框架为组件内置了不同时刻的生命周期函数,生命周期函数会伴随着组件的运行而自动调用。例如:
① 当组件在内存中被创建完毕之后,会自动调用 created 函数
② 当组件被成功的渲染到页面上之后,会自动调用 mounted 函数
③ 当组件被销毁完毕之后,会自动调用 unmounted 函数

5.3 如何监听组件的更新

当组件的 data 数据更新之后,vue 会自动重新渲染组件的 DOM 结构,从而保证 View 视图展示的数据和 Model 数据源保持一致。

当组件被重新渲染完毕之后,会自动调用 updated 生命周期函数。

5.4 组件中主要的生命周期函数

生命周期函数 执行时机 所属阶段 执行次数 应用场景
created 组件在内存中创建完毕后 创建阶段 唯一1次 发 ajax 请求初始数据
mounted 组件初次在页面中渲染完毕后 创建阶段 唯一1次 操作 DOM 元素
updated 组件在页面中被重新渲染完毕后 运行阶段 0或以上 -
unmounted 组件被销毁后(页面和内存) 销毁阶段 唯一1次 -

5.5 组件中全部的生命周期函数

生命周期函数 执行时机 所属阶段 执行次数 应用场景
beforeCreate 在内存中开始创建组件之前 创建阶段 唯一1次 -
created 组件在内存中创建完毕后 创建阶段 唯一1次 发 ajax 请求初始数据
beforeMount 在把组件初次渲染到页面之前 创建阶段 唯一1次 -
mounted 组件初次在页面中渲染完毕后 创建阶段 唯一1次 操作 DOM 元素
beforeUpdate 在组件被重新渲染之前 运行阶段 唯一1次 操作 DOM 元素
updated 组件在页面中被重新渲染完毕后 运行阶段 0或 以上 -
beforeUnmount 在组件被销毁之前 销毁阶段 唯一1次 -
unmounted 组件被销毁后(页面和内存) 销毁阶段 唯一1次 -

疑问:为什么不在 beforeCreate 中发 ajax 请求初始数据?
答:在 beforeCreate生命周期函数中,data还没初始化,不能访问data里面的数据。 所以ajax 请求回来的数据没地方存,在 beforeCreate 中发 ajax 请求初始数据没有意义。

5.6 完整的生命周期图示

可以参考 vue 官方文档给出的 “生命周期图示 ”,进一步理解组件生命周期执行的过程:

在这里插入图片描述

6. 组件之间的数据共享

6.1 组件之间的关系

在项目开发中,组件之间的关系分为如下 3 种:
① 父子关系(AB,AC)
② 兄弟关系(BC,BE)
③ 后代关系(AD,AJ)
在这里插入图片描述

6.2 父子组件之间的数据共享

父子组件之间的数据共享又分为:
① 父 -> 子共享数据
② 子 -> 父共享数据
③ 父 <-> 子双向数据同步

6.2.1 父组件向子组件共享数据

父组件通过 v-bind (简写:)属性绑定向子组件共享数据。同时,子组件需要使用 props 接收数据。示例代码如下:

子组件:

<template>
  <div>
    <h1>Myleft组件</h1>
    <p>{
   {
    msg }}</p>
    <p>名字:{
   {
    user.name }}年龄:{
   {
    user.age }}</p>
  </div>
</template>

<script>
export default {
   
  props: ["msg", "user"],
};
</script>

父组件:

<template>
  <div>
    <h1>App根组件</h1>
    <Myleft :msg="message" :user="userinfo"></Myleft>
  </div>
</template>
<script>
import Myleft from "./components/Myleft.vue";
export default {
   
  data() {
   
    return {
   
      message: "hello vue",
      userinfo: {
    name: "zs", age: 20 },
    };
  },
  components: {
   
    Myleft,
  },
};
</script>

6.2.2 子组件向父组件共享数据

子组件通过自定义事件的方式向父组件共享数据。示例代码如下:

父组件:

<template>
  <div>
    <h1>App根组件</h1>
    <!-- 1. 监听子组件的自定时事件n1change -->
    <Myleft @n1change="getn1"></Myleft>
    <p>{
   {
    n1FromSon }}</p>
  </div>
</template>
<script>
import Myleft from "./components/Myleft.vue";
export default {
   
  data() {
   
    return {
   
      n1FromSon: 0,
    };
  },
  methods: {
   
    // 2. 通过形参,接收子组件传递过来的参数
    getn1(n1) {
   
      this.n1FromSon = n1;
    },
  },
  components: {
   
    Myleft,
  },
};
</script>

子组件:

<template>
  <div>
    <h1>Myleft组件</h1>
    <p>{
   {
    n1 }}</p>
    <button @click="addN1">点我加1</button>
  </div>
</template>

<script>
export default {
   
  emits: ["n1change"], // 声明自定义事件
  data() {
   
    return {
   
      n1: 0,
    };
  },
  methods: {
   
    addN1() {
   
      this.n1++;
      // 数据变化时,触发自定义事件,并传了参数
      this.$emit("n1change", this.n1);
    },
  },
};
</script>

6.2.3 父子组件之间数据的双向同步

父组件在使用子组件期间,可以使用 v-model 指令维护组件内外数据的双向同步:
在这里插入图片描述
父组件:

<template>
  <div>
    <h1>App根组件的 count 为{
   {
    count }}</h1>
    <button @click="count++">App的按钮加1</button>
    <Counter v-model:number="count"></Counter>
    <p></p>
  </div>
</template>
<script>
import Counter from "./components/Counter.vue";
export default {
   
  data() {
   
    return {
   
      count: 0,
    };
  },
  components: {
   
    Counter,
  },
};
</script>

子组件:

<template>
  <div>
    <h1>Counter组件的 number 为 {
   {
    number }}
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用 Vite + Vue3 + TypeScript + Pinia + Vue Router + Axios + SCSS 并自动导入 API 的设置,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了 Node.js,并且版本大于等于 12.0.0。 2. 创建一个新的 Vue 项目,可以使用 Vue CLI 或者手动创建一个空文件夹。 3. 在项目根目录下,打开终端并执行以下命令安装 Vite: ```bash npm init vite@latest ``` 按照提示选择你的项目配置,包括选择 Vue 3、TypeScript 和其他选项。 4. 进入项目目录并安装依赖: ```bash cd your-project-name npm install ``` 5. 安装 Pinia 插件: ```bash npm install pinia ``` 6. 创建一个 `src/store` 目录,并在其中创建 `index.ts` 文件,用于定义和导出你的 Pinia store。 ```typescript // src/store/index.ts import { createPinia } from 'pinia' export const store = createPinia() // 可以在这里定义你的 store 模块 ``` 7. 在项目根目录下创建 `src/api` 目录,用于存放 API 请求相关的文件。 8. 在 `src/api` 目录下创建一个 `index.ts` 文件,用于自动导入所有 API 文件。 ```typescript // src/api/index.ts const modules = import.meta.globEager('./*.ts') const apis: any = {} for (const path in modules) { if (path !== './index.ts') { const moduleName = path.replace(/^.\/|\.ts$/g, '') apis[moduleName] = modules[path].default } } export default apis ``` 这样,你就可以在 `src/api` 目录下创建各种 API 请求的文件,例如 `user.ts`: ```typescript // src/api/user.ts import axios from 'axios' export function getUser(id: number) { return axios.get(`/api/user/${id}`) } ``` 然后,在你的组件中使用自动导入的 API: ```typescript import { defineComponent, ref } from 'vue' import { useUserStore } from '@/store' import apis from '@/api' export default defineComponent({ setup() { const userStore = useUserStore() const userId = ref(1) const fetchUser = async () => { const response = await apis.user.getUser(userId.value) userStore.setUser(response.data) } return { userId, fetchUser, } }, }) ``` 以上就是使用 Vite + Vue3 + TypeScript + Pinia + Vue Router + Axios + SCSS 并自动导入 API 的基本设置。你可以根据自己的需求进一步配置和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值