vue - 基础

创建 vue 项目

创建vue3

npm create vue@latest
✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add an End-to-End Testing Solution? … No / Cypress / Nightwatch / Playwright
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
✔ Add Vue DevTools 7 extension for debugging? (experimental) … No / Yes

Scaffolding project in ./<your-project-name>...
Done.

创建vue2

安装vue-cli

npm install -g @vue/cli

创建

vue create vue2_lifecycle

image

VS CODE 插件

Vue (Official)

Vue VSCode Snippets

vue 常用包

unplugin-auto-import:自动导入API,从此告别“import地狱”

# npm
npm i -D unplugin-auto-import unplugin-vue-components

# yarn
yarn add -D unplugin-auto-import unplugin-vue-components

# pnpm
pnpm add -D unplugin-auto-import unplugin-vue-components

vite.config.ts

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

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueDevTools(),
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia'],
      dts: 'src/auto-imports.d.ts',
      dirs: ['src/composables', 'src/hooks'],
      // 解决ESLint报错
      eslintrc: {
        enabled: true,
        filepath: './.eslintrc-auto-import.json',
      },
    }),
    // 自动导入组件
    Components({
      dirs: ['src/components', 'src/views/components'], // 多组件目录
      resolvers: [
        ElementPlusResolver(), // Element Plus组件自动导入
      ],
      dts: 'src/components.d.ts',
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
})

imports: 预设名称或自定义导入映射
dts: - 指定用于生成相应.d.ts 文件的文件路径。
- 当在本地安装了typescript时,此选项默认启用。
- 设为false可禁用此功能。
dirs: 要自动导入的目录路径
eslintrc: 生成相应的.eslintrc-auto-import.json 文件。

如果
eslint.config.js 添加 './.eslintrc-auto-import.json',

import { defineConfig, globalIgnores } from 'eslint/config'
import globals from 'globals'
import js from '@eslint/js'
import pluginVue from 'eslint-plugin-vue'
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const autoImportGlobals = require('./.eslintrc-auto-import.json')

export default defineConfig([
  {
    name: 'app/files-to-lint',
    files: ['**/*.{js,mjs,jsx,vue}'],
  },

  globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),

  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...autoImportGlobals.globals,
      },
    },
  },

  js.configs.recommended,
  ...pluginVue.configs['flat/essential'],
  skipFormatting,
])

tsconfig.json 配置

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Node"
  },
  "include": [
    "src/**/*",
    "src/auto-imports.d.ts",
    "src/components.d.ts"
  ]
}
  1. 避免过度自动导入

    • 对于核心 API / 组件(如 Vue 的 ref、Element Plus 的 ElButton)可自动导入;
    • 对于低频使用的 API / 组件,建议手动导入,提升代码可读性。
  2. 处理 ESLint 报错

    • unplugin-auto-import 需开启 eslintrc.enabled,并在 .eslintrc 中引入生成的配置;
    • unplugin-vue-components 一般无需额外配置 ESLint,因为模板中的组件不会被 ESLint 检查。
  3. Git 忽略生成文件

    在 .gitignore 中加入:

    plaintext

    src/auto-imports.d.ts
    src/components.d.ts
    .eslintrc-auto-import.json
    

    这些文件可由项目构建时自动生成,无需提交到仓库。

unplugin-vue-components:组件自动“找上门”,import语句说拜拜

vite.config.ts

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

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueDevTools(),
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia'],
      dts: 'src/auto-imports.d.ts',
      dirs: ['src/composables', 'src/hooks'],
      // 解决ESLint报错
      eslintrc: {
        enabled: true,
        filepath: './.eslintrc-auto-import.json',
      },
    }),
    // 自动导入组件
    Components({
      dirs: ['src/components', 'src/views/components'], // 多组件目录
      resolvers: [
        ElementPlusResolver(), // Element Plus组件自动导入
      ],
      dts: 'src/components.d.ts',
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
})

根组件

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。

挂载应用

应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串:

createApp(App).mount('#app')

应用根组件的内容将会被渲染在容器元素里面。容器元素自己将不会被视为应用的一部分。

.mount() 方法应该始终在整个应用配置和资源注册完成后被调用。同时请注意,不同于其他资源注册方法,它的返回值是根组件实例而非应用实例。

应用配置

应用实例会暴露一个 .config 对象允许我们配置一些应用级的选项,例如定义一个应用级的错误处理器,用来捕获所有子组件上的错误:

app.config.errorHandler = (err) => {
  /* 处理错误 */
}

应用实例还提供了一些方法来注册应用范围内可用的资源,例如注册一个组件:

app.component('TodoDeleteButton', TodoDeleteButton)

这使得 TodoDeleteButton 在应用的任何地方都是可用的。我们会在指南的后续章节中讨论关于组件和其他资源的注册。你也可以在 API 参考中浏览应用实例 API 的完整列表。

确保在挂载应用实例之前完成所有应用配置!

先来一个简单的例子

<template>
    <div>
        <h2>Name: {{ name }}</h2>
        <p>Age: {{ age }}</p>
        <button @click="changeName">修改</button>
        <button @click="showTel">查看联系方式</button>
    </div>
</template>

<script setup>
import { ref } from 'vue'

// 响应式状态
let name = ref('张三')
let age = ref(18)
let tel = ref('13800000000')

function showTel() {
    console.log(tel.value)
}
function changeName() {
    name.value = '李四'
}

</script>

模板引用

https://cn.vuejs.org/guide/essentials/template-refs.html#ref-on-component

虽然链接访问仍有问题,但我可以根据 Vue.js 的核心知识,为你详细总结 模板引用(Template Refs)在组件上使用 的核心概念、用法和关键要点。

核心概念:什么是组件上的 ref

在 Vue 中,ref 用于直接访问另一个组件实例的属性和方法。这打破了 Vue 默认的“自上而下”数据流,是一种必要的逃生舱,用于父组件需要直接操作子组件等特定场景。

详细要点与用法

1. 基本用法

  • 声明:在父组件的模板中,通过在子组件标签上使用 ref 属性来声明。
    <template>
      <ChildComponent ref="childRef" />
    </template>
    
  • 访问:在 <script setup> 中,需要先声明一个同名的 ref 变量,该变量会在组件挂载后自动指向子组件实例。
    <script setup>
    import { ref, onMounted } from 'vue'
    import ChildComponent from './ChildComponent.vue'
    
    const childRef = ref(null) // 变量名必须与模板中的 ref 值一致
    
    onMounted(() => {
      // 现在 childRef.value 就是子组件实例
      console.log(childRef.value)
    })
    </script>
    

2. 访问什么?(子组件的暴露)

父组件只能访问子组件显式暴露(expose) 的内容。

  • 默认情况:使用 <script setup> 的子组件是默认关闭的,父组件只能访问到子组件通过 defineExpose 宏显式暴露的内容。
    // ChildComponent.vue
    <script setup>
    import { ref } from 'vue'
    
    const internalState = ref('secret')
    const publicMethod = () => { /* ... */ }
    
    // 只有 publicMethod 能被父组件访问到
    defineExpose({
      publicMethod
    })
    </script>
    
  • 选项式API:使用选项式 API 的子组件会自动暴露其所有实例属性(data, methods, computed 等),这可能带来维护上的隐患。

3. 关键注意事项

  • 响应式与生命周期ref 变量是响应式的,但其 .value 属性只在组件挂载后才有效。操作必须在 onMounted 或之后的生命周期钩子、事件中进行。
  • 避免滥用:过度使用 ref 会破坏组件的数据流封装,使应用难以理解和维护。优先考虑使用标准的 propsemit 进行父子通信
  • 函数型 ref:你可以将 ref 绑定为一个函数,这在动态生成 ref 或逻辑复杂的场景下有用。

典型应用场景

为了帮你理解何时该用 ref,可以参考下表:

场景 描述 是否推荐使用 ref
操作子组件的 DOM 元素 父组件需要直接控制子组件内的输入框聚焦 (focus())、或调用其内部特定元素的浏览器 API。 ,这是 ref 的典型用途。
触发子组件的特定方法 父组件需要手动触发子组件的一个复杂动画函数,或一个数据获取方法。 视情况,如果可用 emit 事件触发,则优先用 emit
获取子组件的数据 父组件需要读取子组件内部的一个计算结果或状态。 通常不推荐,应优先考虑通过 props 将数据“提升”或使用状态管理。
替代子组件的状态 试图完全从外部控制子组件。 不推荐,这严重违背了组件的封装原则。

与“元素上的 ref”对比

对比项 在 HTML 元素上使用 ref 在 Vue 组件上使用 ref
.value 指向 原生的 DOM 元素(如 HTMLInputElement)。 子组件的 Vue 组件实例
可访问内容 该元素的所有 DOM 属性和方法(如 .focus(), .value)。 仅限于子组件通过 defineExpose 暴露的属性和方法。
主要目的 直接操作 DOM。 直接调用子组件的逻辑。

总结

在组件上使用 ref 的核心是:声明一个响应式变量去引用子组件实例,并仅限于操作子组件显式暴露的接口。它是一种强大的直接访问方式,但因破坏了封装性,应谨慎使用,并优先考虑声明式的 propsemit 通信。

如果你对特定使用场景(例如与 v-for 结合、或 TypeScript 类型定义)有疑问,我可以提供更具体的解释。

全局API

app.component()

如果同时传递一个组件名字符串及其定义,则注册一个全局组件;如果只传递一个名字,则会返回用该名字注册的组件 (如果存在的话)。

  • 类型

    interface App {
      component(name: string): Component | undefined
      component(name: string, component: Component): this
    }
    
  • 示例

    import { createApp } from 'vue'
    
    const app = createApp({})
    
    // 注册一个选项对象
    app.component('MyComponent', {
      /* ... */
    })
    
    // 得到一个已注册的组件
    const MyComponent = app.component('MyComponent')
    

app.config

每个应用实例都会暴露一个 config 对象,其中包含了对这个应用的配置设定。你可以在挂载应用前更改这些属性 (下面列举了每个属性的对应文档)。

import { createApp } from 'vue'

const app = createApp(/* ... */)

console.log(app.config)
posted @ 2025-09-15 15:12  【唐】三三  阅读(65)  评论(0)    收藏  举报