一、Vue 3 概述 1. Vue.js 简介 Vue.js 是一个渐进式的 JavaScript 框架,专注于构建用户界面。Vue 可以与其他库或现有项目进行集成,也可以用于搭建复杂的单页应用(SPA)。
2. Vue.js 的特点和优势 
渐进式框架 :可以逐步采用 Vue,灵活性高。响应式数据绑定 :通过数据和视图的双向绑定,简化了数据管理。组件化 :支持组件化开发,促进代码复用和可维护性。虚拟 DOM :通过虚拟 DOM 提高渲染性能,降低直接操作 DOM 的开销。生态系统完整 :提供路由管理、状态管理和构建工具等完整的生态支持。 
3. Vue 3 的新特性 3.1 性能优化 
虚拟 DOM 的优化 :Vue 3 通过 Proxy API 替代了 Vue 2 中的 Object.defineProperty,使得数据的响应式跟踪更加高效。更小的包体积 :Vue 3 的核心库体积更小,提升了加载速度。 
示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const  { createApp, ref } = Vue ;const  App  = {  setup (     const  count = ref (0 );          const  increment  = (       count.value ++;     };     return  { count, increment };   },   template : `<div>                 <p>Count: {{ count }}</p>                <button @click="increment">Increment</button>              </div>` }; createApp (App ).mount ('#app' );
3.2 Composition API Composition API 是 Vue 3 的一个新特性,允许开发者在 setup() 函数中组织逻辑,提升代码的可读性和复用性。
示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const  { createApp, ref, computed } = Vue ;const  App  = {  setup (     const  num1 = ref (1 );     const  num2 = ref (2 );          const  sum = computed (() =>  num1.value  + num2.value );     return  { num1, num2, sum };   },   template : `<div>                 <input v-model="num1" type="number" />                <input v-model="num2" type="number" />                <p>Sum: {{ sum }}</p>              </div>` }; createApp (App ).mount ('#app' );
3.3 Fragments 在 Vue 3 中,组件可以返回多个根节点,而不需要被包裹在一个根节点中。
示例代码: 1 2 3 4 5 6 7 8 9 10 const  { createApp } = Vue ;const  App  = {  template : `      <h1>Hello</h1>     <h2>World</h2>   ` }; createApp (App ).mount ('#app' );
3.4 Teleport Teleport 允许组件被渲染到 DOM 的其他位置,这在实现模态框、下拉菜单等时非常方便。
示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const  { createApp, ref } = Vue ;const  App  = {  setup (     const  showModal = ref (false );     const  toggleModal  = (       showModal.value  = !showModal.value ;     };     return  { showModal, toggleModal };   },   template : `      <div>       <button @click="toggleModal">Toggle Modal</button>       <teleport to="body">         <div v-if="showModal" style="border: 1px solid black; padding: 20px; background: white; position: fixed; top: 20%; left: 50%; transform: translate(-50%, -50%);">           <p>This is a modal!</p>           <button @click="toggleModal">Close</button>         </div>       </teleport>     </div>   ` }; createApp (App ).mount ('#app' );
3.5 Suspense Suspense 组件用于处理异步组件的加载状态,可以在组件加载时显示一个占位符(fallback)。
示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const  { createApp, defineAsyncComponent } = Vue ;const  AsyncComponent  = defineAsyncComponent (() =>  {  return  new  Promise ((resolve ) =>  {     setTimeout (() =>  resolve ({ template : '<h2>Loaded!</h2>'  }), 2000 );   }); }); const  App  = {  template : `      <div>       <h1>Hello</h1>       <Suspense>         <template #default>           <AsyncComponent />         </template>         <template #fallback>           <h2>Loading...</h2>         </template>       </Suspense>     </div>   ` }; createApp (App ).mount ('#app' );
二、环境搭建 1. 开发环境准备 1.1 安装 Node.js 和 npm Node.js 是一个 JavaScript 运行环境,用于在服务器端执行 JavaScript 代码。npm 是 Node.js 的包管理工具,用于安装和管理 JavaScript 库和工具。
安装步骤 :
下载 Node.js :访问 Node.js 官方网站 ,根据你的操作系统(Windows、macOS 或 Linux)下载合适的安装包。安装 Node.js :运行下载的安装包,并按照提示完成安装。安装过程中请确保选中“Add to PATH”选项,这样可以在命令行中直接使用 node 和 npm 命令。验证安装 :安装完成后,可以打开命令行(终端)并输入以下命令来验证安装是否成功:
node -v:查看 Node.js 的版本。npm -v:查看 npm 的版本。 
 
 
1.2 创建 Vue 3 项目 可以使用 Vue CLI 或 Vite 创建 Vue 3 项目,这两者都是创建 Vue 项目的常用工具。
1.2.1 使用 Vue CLI Vue CLI 是 Vue.js 官方提供的一个脚手架工具,适合中大型项目。
安装 Vue CLI :
在命令行中执行以下命令安装 Vue CLI: 
验证安装: 
 
创建 Vue 3 项目 :
使用 CLI 创建新项目: 
在创建过程中,会提示选择配置,可以选择默认配置或手动选择特性(如 TypeScript、Vue Router、Vuex 等)。 
进入项目目录: 
启动开发服务器: 
 
 
1.2.2 使用 Vite Vite 是一个新兴的前端构建工具,提供更快速的构建和热重载体验,适合小型和中型项目。
创建 Vue 3 项目 :
在命令行中执行以下命令创建新项目:1 npm init vite@latest my-vue-app -- --template vue 
 
进入项目目录: 
安装依赖: 
启动开发服务器: 
 
 
2. 项目结构 无论是通过 Vue CLI 还是 Vite 创建的 Vue 3 项目,项目的基本结构都比较相似。以下是项目目录结构及各个文件的说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 my-vue-app/ ├── node_modules/          # 项目依赖的第三方库  ├── public /                # 静态资源目录,直接拷贝到最终构建中  │   └── favicon.ico        # 应用的图标  ├── src/                   # 源代码目录  │   ├── assets/            # 静态资源(图片、字体、样式等)  │   ├── components/        # Vue 组件  │   ├── App.vue            # 根组件  │   ├── main.js            # 入口文件  │   └── router/            # 路由配置(如果使用了 Vue Router)  │       └── index .js       # 路由定义  ├── .gitignore             # Git 忽略文件列表  ├── package.json           # 项目信息和依赖管理  ├── README.md              # 项目说明文件  └── vite.config.js         # Vite 配置文件(如果使用 Vite)  
2.1 目录结构和文件说明 
**node_modules/**:存放所有项目依赖的第三方库,npm 安装的所有包都会放在这里。 
**public/**:用于存放静态文件,如图片、favicon、以及一些不需要 Webpack 处理的文件。这些文件会被直接拷贝到构建输出中。 
**src/**:项目的源代码目录,所有的业务逻辑和组件都放在这里。
**assets/**:存放静态资源,如图片、字体、样式等。 
**components/**:存放自定义的 Vue 组件,建议按功能或模块分组。 
App.vue :根组件,整个应用的入口组件,通常包含应用的结构和样式。main.js :入口文件,负责创建 Vue 实例并将根组件挂载到 DOM。**router/**:如果使用了 Vue Router,这里存放路由配置文件。
index.js :路由的定义,包含路由路径、组件与其他路由配置。 
 
 
 
.gitignore :Git 忽略文件,列出不需要添加到版本控制中的文件和目录。package.json :包含项目的依赖、脚本、版本、描述等信息,是 Node.js 项目的核心配置文件。README.md :项目的说明文档,通常包括项目介绍、安装和使用说明、贡献指导等信息。vite.config.js :如果使用 Vite,这里存放 Vite 的配置文件,可以进行构建和开发的配置。 
三、基础知识 1. Vue 实例 1.1 创建 Vue 实例 在 Vue 中,所有的应用都是通过创建 Vue 实例来开始的。Vue 实例是 Vue 应用的核心,它将数据、模板和视图绑定在一起。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import  { createApp } from  'vue' ;const  app = createApp ({  data (     return  {       message : 'Hello Vue!'      };   } }); app.mount ('#app' ); 
在这个示例中,我们创建了一个 Vue 应用,定义了一个 data 数据属性 message,并将应用挂载到 id 为 app 的 DOM 元素上。
1.2 生命周期钩子 每个 Vue 实例在创建、更新和销毁的不同阶段都有一系列的生命周期钩子。生命周期钩子允许开发者在特定的时间点执行代码。
常用生命周期钩子 :
created :实例创建后立即调用。mounted :挂载后调用,适合进行与 DOM 相关的操作。updated :数据变化导致视图更新后调用。beforeUnmount :组件销毁前调用。unmounted :组件销毁后调用。 
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const  app = createApp ({  data (     return  {       message : 'Hello Vue!'      };   },   created (     console .log ('实例已创建' );   },   mounted (     console .log ('组件已挂载' );   },   unmounted (     console .log ('组件已销毁' );   } }); app.mount ('#app' ); 
在这个示例中,我们在实例的生命周期钩子中添加了简单的日志输出,便于观察生命周期的变化。
2. 模板语法 2.1 Mustache 语法 Mustache 语法是一种简单的文本插值方式,使用双大括号 {{ }} 来绑定数据。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <div  id ="app" >   <h1 > {{ message }}</h1 >  </div > <script > const  app = createApp ({  data (     return  {       message : 'Hello Vue!'      };   } }); app.mount ('#app' ); </script > 
在这个示例中,Vue 会将 {{ message }} 替换为 data 中的 message 的值。
2.2 指令 指令是 Vue 模板中的特殊特性,用于对 DOM 元素进行操作。
**v-bind**:动态绑定 HTML 属性。 
**v-model**:实现双向数据绑定。 
**v-if**:条件渲染。 
**v-for**:列表渲染。 
**v-show**:控制元素的显示与隐藏。 
**v-on**:绑定事件监听器。 
 
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <div  id ="app" >   <h1 > {{ message }}</h1 >    <button  @click ="toggle" > Toggle Message</button >    <p  v-if ="isVisible" > This is a toggle message!</p >    <ul >      <li  v-for ="item in items"  :key ="item.id" > {{ item.text }}</li >    </ul >    <input  v-model ="inputValue"  placeholder ="Type something"  />    <p > Typed: {{ inputValue }}</p >  </div > <script > const  app = createApp ({  data (     return  {       message : 'Hello Vue!' ,       isVisible : true ,       inputValue : '' ,       items : [         { id : 1 , text : 'Item 1'  },         { id : 2 , text : 'Item 2'  },         { id : 3 , text : 'Item 3'  }       ]     };   },   methods : {     toggle (       this .isVisible  = !this .isVisible ;     }   } }); app.mount ('#app' ); </script > 
在这个示例中,我们演示了多种指令的用法,包括动态绑定、条件渲染、列表渲染和双向数据绑定。
3. 计算属性和侦听器 3.1 计算属性的使用 计算属性是基于响应式数据的动态计算值,适合用于生成基于数据的值。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <div  id ="app" >   <input  v-model ="firstName"  placeholder ="First Name"  />    <input  v-model ="lastName"  placeholder ="Last Name"  />    <p > Full Name: {{ fullName }}</p >  </div > <script > const  app = createApp ({  data (     return  {       firstName : '' ,       lastName : ''      };   },   computed : {     fullName (       return  `${this .firstName}  ${this .lastName} ` ;     }   } }); app.mount ('#app' ); </script > 
在这个示例中,fullName 是一个计算属性,它根据 firstName 和 lastName 的值动态生成完整的名字。
3.2 侦听器的使用和区别 侦听器用于观察响应式数据的变化,并在数据变化时执行操作。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <div  id ="app" >   <input  v-model ="count"  placeholder ="Enter a number"  />    <p > Count: {{ count }}</p >  </div > <script > const  app = createApp ({  data (     return  {       count : 0      };   },   watch : {     count (newValue, oldValue ) {       console .log (`Count changed from ${oldValue}  to ${newValue} ` );       if  (newValue > 10 ) {         alert ('Count is greater than 10!' );       }     }   } }); app.mount ('#app' ); </script > 
在这个示例中,当 count 的值变化时,侦听器会输出变化的值,并在 count 超过 10 时弹出警告。
四、组件 1. 组件基本概念 1.1 组件的定义和注册 组件是 Vue 中的基本构建块。组件可以包含自己的模板、逻辑和样式,使得代码更加模块化和可重用。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <template >   <div  id ="app" >      <HelloWorld  msg ="Welcome to Your Vue.js App" />    </div >  </template > <script > import  HelloWorld  from  './components/HelloWorld.vue' ;export  default  {  components : {     HelloWorld    } } </script > <style > </style > 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <template >   <div >      <h1 > {{ msg }}</h1 >    </div >  </template > <script > export  default  {  props : {     msg : String    } } </script > <style  scoped > h1  {  color : blue; } </style > 
在这个示例中,我们定义了一个 HelloWorld 组件,并在 App.vue 中注册和使用它。组件通过 props 接收外部数据。
1.2 组件的模板、script 和 style 每个组件由三个部分组成:模板(template)、脚本(script)和样式(style)。模板定义了组件的结构,脚本包含逻辑和状态,样式定义了组件的外观。
模板 :使用 Vue 的模板语法定义组件的 HTML 结构。脚本 :在 script 标签中定义组件的逻辑、数据和方法。样式 :在 style 标签中定义组件的样式,可以使用 scoped 属性限制样式的作用域。 
2. 组件间通信 2.1 Props 的使用 props 是父组件向子组件传递数据的方式。子组件通过 props 接收父组件传递的数据。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <template >   <div >      <Child  :name ="parentName"  />    </div >  </template > <script > import  Child  from  './Child.vue' ;export  default  {  components : {     Child    },   data (     return  {       parentName : 'Parent Component'      };   } } </script > <template >   <div >      <p > Received from parent: {{ name }}</p >    </div >  </template > <script > export  default  {  props : {     name : String    } } </script > 
在这个示例中,Parent.vue 通过 props 向 Child.vue 传递一个名为 name 的属性,子组件可以直接使用这个属性。
2.2 Emit 事件 子组件通过 $emit 方法向父组件发送事件,从而实现子组件向父组件的通信。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <template >   <div >      <Child  @childEvent ="handleChildEvent"  />    </div >  </template > <script > import  Child  from  './Child.vue' ;export  default  {  components : {     Child    },   methods : {     handleChildEvent (data ) {       console .log ('Event received from child:' , data);     }   } } </script > <template >   <button  @click ="sendEvent" > Send Event to Parent</button >  </template > <script > export  default  {  methods : {     sendEvent (       this .$emit('childEvent' , 'Hello from Child!' );     }   } } </script > 
在这个示例中,Child.vue 通过 $emit 发送一个名为 childEvent 的事件,父组件 Parent.vue 监听这个事件,并执行 handleChildEvent 方法。
2.3 Provide/Inject provide/inject 是一种用于祖孙组件之间通信的方式,可以在不直接通过 props 和事件传递的情况下共享数据。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 <template >   <div >      <Parent  />    </div >  </template > <script > import  Parent  from  './Parent.vue' ;export  default  {  components : {     Parent    },   provide (     return  {       sharedData : 'Data from Grandparent'      };   } } </script > <template >   <Child  />  </template > <script > import  Child  from  './Child.vue' ;export  default  {  components : {     Child    } } </script > <template >   <p > {{ sharedData }}</p >  </template > <script > export  default  {  inject : ['sharedData' ] } </script > 
在这个示例中,Grandparent.vue 提供了 sharedData,而 Child.vue 通过 inject 接收这个数据。这样,Child 可以直接访问 Grandparent 提供的数据。
3. 插槽 3.1 默认插槽 默认插槽允许父组件在子组件中插入内容。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 <template >   <Child >      <p > This is content from the parent.</p >    </Child >  </template > <template >   <div >      <slot > </slot >    </div >  </template > 
在这个示例中,Parent.vue 的内容通过默认插槽被插入到 Child.vue 中。
3.2 具名插槽 具名插槽允许父组件为插槽指定名称,以便在子组件中插入特定的内容。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <template >   <Child >      <template  v-slot:header >        <h1 > This is a header</h1 >      </template >      <template  v-slot:footer >        <footer > This is a footer</footer >      </template >    </Child >  </template > <template >   <div >      <slot  name ="header" > </slot >      <p > This is the main content.</p >      <slot  name ="footer" > </slot >    </div >  </template > 
在这个示例中,Parent.vue 为 Child.vue 中的两个具名插槽提供了内容:一个是 header,另一个是 footer。
3.3 作用域插槽 作用域插槽允许父组件访问子组件中的数据。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template >   <Child >      <template  v-slot:default ="{ msg }" >        <p > {{ msg }}</p >      </template >    </Child >  </template > <template >   <slot  :msg ="message" > </slot >  </template > <script > export  default  {  data (     return  {       message : 'This is a message from the child.'      };   } } </script > 
在这个示例中,Child.vue 提供了一个作用域插槽,父组件通过 v-slot 访问到子组件 message 数据。
五、Composition API 1. 基本概念 1.1 什么是 Composition API Composition API 是 Vue 3 引入的新特性,旨在提供一种更灵活和可组合的方式来组织和复用逻辑。与传统的选项 API(Options API)不同,Composition API 通过函数的方式来处理状态和逻辑,使得组件的逻辑更加清晰和易于管理。
1.2 使用 setup() 函数 setup() 函数是 Composition API 的核心,它在组件创建之前被调用,并且是组件实例化的第一个生命周期钩子。所有的响应式状态、计算属性和方法都可以在 setup() 中定义。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <template >   <div >      <h1 > {{ message }}</h1 >      <button  @click ="increment" > Increment</button >      <p > Count: {{ count }}</p >    </div >  </template > <script > import  { ref } from  'vue' ;export  default  {  setup (          const  message = ref ('Hello Composition API' );     const  count = ref (0 );          const  increment  = (       count.value ++;     };          return  {       message,       count,       increment     };   } } </script > 
在这个示例中,我们在 setup() 函数中定义了一个响应式的 message 和 count,并创建了一个 increment 方法来增加计数。
2. 响应式 API 2.1 ref 和 reactive 的使用 
**ref**:用于创建一个基本数据类型的响应式引用。 
**reactive**:用于创建一个对象的响应式状态,适合用于复杂数据结构。 
 
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <template >   <div >      <h2 > User Info</h2 >      <p > Name: {{ user.name }}</p >      <p > Age: {{ user.age }}</p >      <button  @click ="updateAge" > Increase Age</button >    </div >  </template > <script > import  { reactive } from  'vue' ;export  default  {  setup (          const  user = reactive ({       name : 'John Doe' ,       age : 25      });     const  updateAge  = (       user.age ++;     };     return  {       user,       updateAge     };   } } </script > 
在这个示例中,我们使用 reactive 创建了一个 user 对象,包含 name 和 age 属性,并提供了一个方法来增加年龄。
2.2 computed 和 watch 的使用 
**computed**:用于创建计算属性,可以基于响应式状态自动计算值。 
**watch**:用于观察响应式数据的变化,并在变化时执行某些操作。 
 
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <template >   <div >      <input  v-model ="firstName"  placeholder ="First Name"  />      <input  v-model ="lastName"  placeholder ="Last Name"  />      <p > Full Name: {{ fullName }}</p >      <button  @click ="resetNames" > Reset Names</button >    </div >  </template > <script > import  { ref, computed, watch } from  'vue' ;export  default  {  setup (     const  firstName = ref ('' );     const  lastName = ref ('' );          const  fullName = computed (() =>  {       return  `${firstName.value}  ${lastName.value} ` ;     });          watch (fullName, (newValue ) =>  {       console .log ('Full name changed:' , newValue);     });     const  resetNames  = (       firstName.value  = '' ;       lastName.value  = '' ;     };     return  {       firstName,       lastName,       fullName,       resetNames     };   } } </script > 
在这个示例中,我们使用 computed 创建了一个 fullName 计算属性,并使用 watch 观察它的变化。当 fullName 变化时,控制台会打印新的全名。
3. 逻辑复用 3.1 自定义组合函数 (Composition Functions) 自定义组合函数是一种逻辑复用的方法,可以将组合的逻辑提取到单独的函数中,从而在多个组件中使用。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { ref } from 'vue'; export function useCounter() {   const count = ref(0);   const increment = () => {     count.value++;   };   const reset = () => {     count.value = 0;   };   return {     count,     increment,     reset   }; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template >   <div >      <p > Count: {{ count }}</p >      <button  @click ="increment" > Increment</button >      <button  @click ="reset" > Reset</button >    </div >  </template > <script > import  { useCounter } from  './useCounter.js' ;export  default  {  setup (     const  { count, increment, reset } = useCounter ();     return  {       count,       increment,       reset     };   } } </script > 
在这个示例中,我们定义了一个自定义组合函数 useCounter,它返回一个响应式计数器的状态和操作方法。然后我们在组件 Counter.vue 中使用这个组合函数,以实现计数功能。
六、路由管理 1. Vue Router 基础 1.1 安装和配置 Vue Router 在 Vue 3 中使用 Vue Router 进行路由管理,首先需要安装 Vue Router:
1 npm install vue-router@4 
然后,在 Vue 应用中配置 Vue Router。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import  { createRouter, createWebHistory } from  'vue-router' ;import  Home  from  '../views/Home.vue' ;import  About  from  '../views/About.vue' ;const  routes = [  {     path : '/' ,     name : 'Home' ,     component : Home    },   {     path : '/about' ,     name : 'About' ,     component : About    } ]; const  router = createRouter ({  history : createWebHistory (),   routes }); export  default  router;
接下来,在主应用文件中引入并使用这个路由。
1 2 3 4 5 6 7 8 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;import  router from  './router' ;const  app = createApp (App );app.use (router); app.mount ('#app' ); 
在这个示例中,我们创建了两个基本路由:一个指向主页 Home,另一个指向关于页面 About。
1.2 路由定义和嵌套路由 路由可以通过定义 children 属性来实现嵌套。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const  routes = [  {     path : '/' ,     name : 'Home' ,     component : Home ,     children : [       {         path : 'profile' ,         name : 'Profile' ,         component : () =>  import ('../views/Profile.vue' )        }     ]   } ]; 
在这个示例中,Profile 是 Home 的嵌套路由,当用户访问 /profile 时,会渲染 Profile.vue 组件。
2. 路由导航 2.1 编程式导航 可以使用编程式导航来在路由之间进行跳转。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <template >   <div >      <h1 > Home Page</h1 >      <button  @click ="goToAbout" > Go to About</button >    </div >  </template > <script > import  { useRouter } from  'vue-router' ;export  default  {  setup (     const  router = useRouter ();     const  goToAbout  = (       router.push ('/about' );     };     return  {       goToAbout     };   } } </script > 
在这个示例中,用户点击按钮时会通过 router.push 方法导航到关于页面。
2.2 路由守卫 路由守卫用于在路由变化时执行某些逻辑,例如身份验证。
代码示例 :
1 2 3 4 5 6 7 8 9 router.beforeEach ((to, from , next ) =>  {   const  isAuthenticated = false ;     if  (to.name  !== 'Home'  && !isAuthenticated) {     next ({ name : 'Home'  });    } else  {     next ();    } }); 
在这个示例中,如果用户未登录(即 isAuthenticated 为 false),且试图访问不是首页的路由,则会被重定向到首页。
3. 路由参数 3.1 动态路由和查询参数 动态路由允许在路径中定义参数,例如用户 ID。查询参数则可以通过 URL 传递额外的数据。
代码示例 :
1 2 3 4 5 6 7 8 const  routes = [  {     path : '/user/:id' ,     name : 'User' ,     component : () =>  import ('../views/User.vue' )   } ]; 
在 User.vue 组件中,可以通过 $route.params 访问动态路由参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template >   <div >      <h1 > User ID: {{ userId }}</h1 >    </div >  </template > <script > import  { onMounted, ref } from  'vue' ;export  default  {  setup (props, { root } ) {     const  userId = ref ('' );     onMounted (() =>  {       userId.value  = root.$route .params .id ;     });     return  {       userId     };   } } </script > 
用户可以访问 /user/123,User.vue 会显示 User ID: 123。
3.2 查询参数 查询参数在 URL 中以 ? 开头,后面跟着键值对。例如:/user?id=123。
代码示例 :
1 2 3 4 5 6 7 8 const  routes = [  {     path : '/user' ,     name : 'User' ,     component : () =>  import ('../views/User.vue' )   } ]; 
在 User.vue 中获取查询参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template >   <div >      <h1 > User ID: {{ userId }}</h1 >    </div >  </template > <script > import  { onMounted, ref } from  'vue' ;export  default  {  setup (props, { root } ) {     const  userId = ref ('' );     onMounted (() =>  {       userId.value  = root.$route .query .id ;      });     return  {       userId     };   } } </script > 
在这个示例中,访问 /user?id=123,User.vue 将显示 User ID: 123。
七、状态管理 1. Vuex 简介 1.1 Vuex 的基本概念和原理 Vuex 是 Vue.js 的状态管理库,旨在为 Vue 应用提供集中式的状态管理。它通过一个全局的状态树来管理应用的所有组件共享的状态,使得状态的变化变得可预测和可追踪。
基本原理 :
State :保存应用的状态数据。Getters :计算属性,基于 state 计算并返回值,能够在多个组件中共享。Mutations :更改状态的唯一方法,必须是同步函数,直接修改 state。Actions :可以包含异步操作,触发 mutations 来改变 state。 
1.2 安装和配置 Vuex 首先需要安装 Vuex。
然后在 Vue 应用中配置 Vuex。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import  { createStore } from  'vuex' ;const  store = createStore ({  state : {     count : 0    },   mutations : {     increment (state ) {       state.count ++;     },     decrement (state ) {       state.count --;     }   },   getters : {     doubleCount (state ) {       return  state.count  * 2 ;     }   },   actions : {     incrementAsync ({ commit } ) {       setTimeout (() =>  {         commit ('increment' );       }, 1000 );     }   } }); export  default  store;
在主应用文件中引入并使用这个 store:
1 2 3 4 5 6 7 8 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;import  store from  './store' ;const  app = createApp (App );app.use (store); app.mount ('#app' ); 
2. 状态管理 2.1 State, Getters, Mutations, Actions 的使用 在 Vuex 中,状态管理由 State、Getters、Mutations 和 Actions 四个部分组成。下面是它们的具体使用方法。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template >   <div >      <h1 > Count: {{ count }}</h1 >      <h2 > Double Count: {{ doubleCount }}</h2 >      <button  @click ="increment" > Increment</button >      <button  @click ="decrement" > Decrement</button >      <button  @click ="incrementAsync" > Increment Async</button >    </div >  </template > <script > import  { mapState, mapGetters, mapActions } from  'vuex' ;export  default  {  computed : {     ...mapState (['count' ]),     ...mapGetters (['doubleCount' ])   },   methods : {     ...mapActions (['increment' , 'decrement' , 'incrementAsync' ])   } } </script > 
在这个示例中:
使用 mapState 来绑定 state 中的 count。 
使用 mapGetters 绑定计算属性 doubleCount。 
使用 mapActions 来绑定 increment、decrement 和 incrementAsync 方法。 
 
2.2 具体实现的 Mutations 和 Actions Mutations  是唯一可以直接修改 state 的方法:
1 2 3 4 5 6 7 8 mutations : {  increment (state ) {     state.count ++;   },   decrement (state ) {     state.count --;   } } 
Actions  可以包含异步操作,使用 commit 触发 mutation:
1 2 3 4 5 6 7 actions : {  incrementAsync ({ commit } ) {     setTimeout (() =>  {       commit ('increment' );     }, 1000 );   } } 
3. 模块化 Vuex 当应用的状态管理变得复杂时,可以将 store 拆分为多个模块。每个模块都有自己的 state、mutations、actions 和 getters。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const  state = {  count : 0  }; const  mutations = {  increment (state ) {     state.count ++;   },   decrement (state ) {     state.count --;   } }; const  actions = {  incrementAsync ({ commit } ) {     setTimeout (() =>  {       commit ('increment' );     }, 1000 );   } }; const  getters = {  doubleCount (state ) {     return  state.count  * 2 ;   } }; export  default  {  namespaced : true ,   state,   mutations,   actions,   getters }; 
在主 store 中引入模块:
1 2 3 4 5 6 7 8 9 10 11 import  { createStore } from  'vuex' ;import  counter from  './modules/counter' ;const  store = createStore ({  modules : {     counter   } }); export  default  store;
在组件中使用模块化的 Vuex:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <template >   <div >      <h1 > Count: {{ count }}</h1 >      <h2 > Double Count: {{ doubleCount }}</h2 >      <button  @click ="increment" > Increment</button >      <button  @click ="decrement" > Decrement</button >      <button  @click ="incrementAsync" > Increment Async</button >    </div >  </template > <script > import  { mapState, mapGetters, mapActions } from  'vuex' ;export  default  {  computed : {     ...mapState ('counter' , ['count' ]),     ...mapGetters ('counter' , ['doubleCount' ])   },   methods : {     ...mapActions ('counter' , ['increment' , 'decrement' , 'incrementAsync' ])   } } </script > 
在这个示例中,使用了 mapState、mapGetters 和 mapActions 的 namespace 参数来访问模块 counter 的状态和方法。
八、表单处理 1. 表单输入绑定 1.1 单向和双向数据绑定 在 Vue 中,表单输入可以通过单向和双向数据绑定来处理。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <template >   <div >      <h1 > 单向数据绑定</h1 >      <input  type ="text"  :value ="message"  @input ="updateMessage"  />      <p > 输入的内容: {{ message }}</p >      <h1 > 双向数据绑定</h1 >      <input  type ="text"  v-model ="message"  />      <p > 输入的内容: {{ message }}</p >    </div >  </template > <script > export  default  {  data (     return  {       message : ''      };   },   methods : {     updateMessage (event ) {       this .message  = event.target .value ;     }   } } </script > 
在这个示例中:
第一部分演示了单向数据绑定,通过 :value 和 @input 手动更新数据。 
第二部分使用 v-model 实现双向数据绑定,简化了数据管理。 
 
2. 表单验证 2.1 基本验证方法 可以在 Vue 中通过编写自定义方法来实现简单的表单验证。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <template >   <div >      <h1 > 表单验证示例</h1 >      <form  @submit.prevent ="submitForm" >        <div >          <label  for ="email" > Email:</label >          <input  type ="email"  v-model ="email"  />          <span  v-if ="emailError" > {{ emailError }}</span >        </div >        <div >          <label  for ="password" > Password:</label >          <input  type ="password"  v-model ="password"  />          <span  v-if ="passwordError" > {{ passwordError }}</span >        </div >        <button  type ="submit" > 提交</button >      </form >    </div >  </template > <script > export  default  {  data (     return  {       email : '' ,       password : '' ,       emailError : '' ,       passwordError : ''      };   },   methods : {     validateEmail (       const  valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ .test (this .email );       this .emailError  = valid ? ''  : '无效的邮箱地址' ;     },     validatePassword (       this .passwordError  = this .password .length  < 6  ? '密码必须至少包含 6 个字符'  : '' ;     },     submitForm (       this .validateEmail ();       this .validatePassword ();              if  (!this .emailError  && !this .passwordError ) {         alert ('提交成功!' );       }     }   } } </script > 
在这个示例中,我们创建了一个简单的表单,其中包含邮箱和密码字段。提交表单时,会执行验证,并根据验证结果显示错误信息。
2.2 使用第三方库 (如 VeeValidate) VeeValidate 是一个流行的 Vue 表单验证库,提供了更强大的功能和简化的验证方式。
安装 VeeValidate :
1 npm install vee-validate@next @vee-validate/rules @vee-validate/i18n 
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <template >   <div >      <h1 > VeeValidate 示例</h1 >      <Form  @submit ="onSubmit" >        <Field  name ="email"  as ="input"  type ="email"  v-model ="email"  :rules ="rules.email"  />        <ErrorMessage  name ="email"  />               <Field  name ="password"  as ="input"  type ="password"  v-model ="password"  :rules ="rules.password"  />        <ErrorMessage  name ="password"  />               <button  type ="submit" > 提交</button >      </Form >    </div >  </template > <script > import  { Form , Field , ErrorMessage  } from  'vee-validate' ;import  * as  rules from  '@vee-validate/rules' ;import  { defineRule } from  'vee-validate' ;Object .keys (rules).forEach (rule  =>  defineRule (rule, rules[rule]); }); export  default  {  data (     return  {       email : '' ,       password : '' ,       rules : {         email : 'required|email' ,         password : 'required|min:6'        }     };   },   methods : {     onSubmit (       alert ('提交成功!' );     }   } } </script > 
在这个示例中,我们使用 VeeValidate 提供的 Form、Field 和 ErrorMessage 组件,定义了邮箱和密码的验证规则。通过 onSubmit 方法处理表单提交。
九、异步请求 1. AJAX 请求 1.1 使用 Axios 发送请求 Axios 是一个基于 Promise 的 HTTP 客户端,用于向后端发送请求。首先,你需要安装 Axios。
安装 Axios :
然后在 Vue 组件中导入并使用 Axios 发送请求。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <template >   <div >      <h1 > 获取用户数据</h1 >      <button  @click ="fetchUsers" > 获取用户</button >      <ul >        <li  v-for ="user in users"  :key ="user.id" > {{ user.name }}</li >      </ul >      <p  v-if ="error" > {{ error }}</p >    </div >  </template > <script > import  axios from  'axios' ;export  default  {  data (     return  {       users : [],       error : null      };   },   methods : {     async  fetchUsers (       try  {         const  response = await  axios.get ('https://jsonplaceholder.typicode.com/users' );         this .users  = response.data ;        } catch  (err) {         this .error  = '无法获取用户数据' ;          console .error (err);       }     }   } } </script > 
在这个示例中:
当用户点击“获取用户”按钮时,会调用 fetchUsers 方法。 
使用 axios.get 方法发送 GET 请求。 
如果请求成功,我们将返回的数据赋值给 users,如果请求失败,捕获错误并更新 error 状态。 
 
1.2 处理响应和错误 在处理响应时,可以使用 response 对象的一些属性,例如 data、status 和 headers。同时,处理错误时,可以根据错误的状态码来决定如何响应。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 async  fetchUsers (  try  {     const  response = await  axios.get ('https://jsonplaceholder.typicode.com/users' );     console .log ('响应状态:' , response.status );      console .log ('响应头:' , response.headers );      this .users  = response.data ;   } catch  (error) {     if  (error.response ) {              this .error  = `错误 ${error.response.status} : ${error.response.data.message || '无法获取数据' } ` ;     } else  if  (error.request ) {              this .error  = '请求已发出,但没有响应' ;     } else  {              this .error  = '请求发生错误: '  + error.message ;     }     console .error (error);   } } 
2. 与后端 API 交互 2.1 获取数据 通过 Axios 可以轻松地与后端 API 进行交互,获取数据的过程如下:
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <template >   <div >      <h1 > 获取数据示例</h1 >      <button  @click ="getData" > 获取数据</button >      <pre > {{ data }}</pre >      <p  v-if ="error" > {{ error }}</p >    </div >  </template > <script > import  axios from  'axios' ;export  default  {  data (     return  {       data : null ,       error : null      };   },   methods : {     async  getData (       try  {         const  response = await  axios.get ('https://jsonplaceholder.typicode.com/posts' );         this .data  = response.data ;        } catch  (err) {         this .error  = '数据获取失败' ;         console .error (err);       }     }   } } </script > 
在这个示例中,点击按钮后,发送 GET 请求以获取帖子数据,并将结果存储在 data 中。
2.2 提交数据 除了获取数据,还可以使用 POST 请求提交数据。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <template >   <div >      <h1 > 提交数据示例</h1 >      <form  @submit.prevent ="submitData" >        <input  v-model ="newPost.title"  placeholder ="标题"  required  />        <textarea  v-model ="newPost.body"  placeholder ="内容"  required > </textarea >        <button  type ="submit" > 提交</button >      </form >      <p  v-if ="responseMessage" > {{ responseMessage }}</p >      <p  v-if ="error" > {{ error }}</p >    </div >  </template > <script > import  axios from  'axios' ;export  default  {  data (     return  {       newPost : {         title : '' ,         body : ''        },       responseMessage : '' ,       error : null      };   },   methods : {     async  submitData (       try  {         const  response = await  axios.post ('https://jsonplaceholder.typicode.com/posts' , this .newPost );         this .responseMessage  = '数据提交成功: '  + response.data .id ;        } catch  (err) {         this .error  = '提交数据失败' ;         console .error (err);       }     }   } } </script > 
在这个示例中:
用户可以输入标题和内容并提交。 
使用 axios.post 方法将数据提交到服务器。 
成功响应后显示提交成功的消息。 
 
十、性能优化 1. 性能分析 Vue DevTools 是一个强大的工具,可以帮助你分析和调试 Vue 应用的性能。它可以监控组件的渲染时间、状态变化以及 Vuex 状态管理。
安装 Vue DevTools :
你可以在 Chrome 或 Firefox 浏览器中安装 Vue DevTools 插件。 
 
使用 Vue DevTools :
打开开发者工具,切换到 Vue 选项卡。 
你可以查看组件树,监控每个组件的状态和属性。 
使用“性能”选项卡来查看性能分析,查看哪些组件渲染时间较长,帮助定位性能瓶颈。 
 
1.2 性能监测工具 除了 Vue DevTools,还可以使用其他性能监测工具,比如 Lighthouse(Chrome DevTools 内置)和 WebPageTest,这些工具能够帮助你评估整体应用性能,并提供优化建议。
Lighthouse :可以分析页面加载性能、可访问性、最佳实践和 SEO。WebPageTest :可以详细报告页面加载时间、请求数和资源大小等信息。 
2. 常见优化技巧 2.1 懒加载 懒加载是指在需要的时候再加载某些资源,可以显著减少初始加载时间。对于路由组件,Vue Router 支持懒加载。
代码示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 const  router = createRouter ({  history : createWebHistory (),   routes : [     {       path : '/about' ,       component : () =>  import ('./views/About.vue' )      },     {       path : '/home' ,       component : () =>  import ('./views/Home.vue' )      }   ] }); 
在这个示例中,About 和 Home 组件在访问时才会被加载,而不是在应用启动时加载。
2.2 组件缓存 使用 keep-alive 组件可以缓存不常变化的组件,避免重复渲染,提高性能。
代码示例 :
1 2 3 4 5 6 7 8 9 <template >   <div >      <router-view  v-slot ="{ Component }" >        <keep-alive >          <Component  />        </keep-alive >      </router-view >    </div >  </template > 
在这个示例中,keep-alive 会缓存被包裹的组件,当你在不同路由之间切换时,不会重新渲染已缓存的组件。
2.3 服务器端渲染 (SSR) 服务器端渲染(SSR)可以提高首屏加载速度和 SEO 性能。Vue 3 提供了官方的 vue-server-renderer。
使用 Nuxt.js 构建 SSR 应用 :
1 npx create-nuxt-app my-ssr-app 
在创建项目时选择 SSR 模式,然后你可以在页面组件中直接编写 Vue 逻辑。Nuxt.js 将负责处理 SSR。
示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <template >   <div >      <h1 > {{ title }}</h1 >      <p > {{ content }}</p >    </div >  </template > <script > export  default  {  async  asyncData (     const  response = await  fetch ('https://jsonplaceholder.typicode.com/posts/1' );     const  post = await  response.json ();     return  {       title : post.title ,       content : post.body      };   } } </script > 
在这个示例中,asyncData 方法在服务器端和客户端都可以执行,为页面提供初始数据。
十一、部署与发布 1. 构建项目 1.1 使用 Vue CLI 构建项目 如果你是使用 Vue CLI 创建的项目,可以通过以下命令构建项目:
构建完成后,生成的文件会位于 dist 目录中。这些文件就是可以部署到服务器上的静态文件。
1.2 使用 Vite 构建项目 如果你是使用 Vite 创建的项目,同样可以通过以下命令构建项目:
Vite 也会将生成的文件放在 dist 目录。
2. 部署到服务器 2.1 部署到静态文件托管服务 2.1.1 GitHub Pages 
安装 gh-pages :gh-pages 包:
1 npm install gh-pages --save-dev 
**修改 vue.config.js**(如果使用 Vue CLI):vue.config.js 文件,设置 publicPath:
1 2 3 module .exports  = {  publicPath : process.env .NODE_ENV  === 'production'  ? '/your-repo-name/'  : '/'  }; 
添加部署脚本 :package.json 文件的 scripts 部分添加以下部署命令:
1 2 3 "scripts" :  {   "deploy" :  "npm run build && npx gh-pages -d dist"  } 
执行部署命令 :
 
2.1.2 Netlify 
在 Netlify 创建帐户并登录 。新建站点 :选择“新建站点”,然后选择“从 Git 部署”。连接至 GitHub :选择你的 GitHub 仓库。配置构建设置 :
构建命令:npm run build 
发布目录:dist 
 
点击“部署站点” ,待部署完成后,你会获得一个可以访问的 URL。 
2.2 部署到传统服务器 
构建项目 :dist 目录包含了所有静态文件。
上传文件 :dist 目录中的文件上传到你的服务器相应目录中(例如 /var/www/html)。
配置 Web 服务器 :
1 2 3 location  / {    try_files  $uri  $uri / /index.html; } 
这样,所有的路由请求都会重定向到 index.html,以便 Vue Router 可以处理。
 
十二、进阶主题 1. TypeScript 支持 1.1 Vue 3 中使用 TypeScript 的最佳实践 Vue 3 原生支持 TypeScript,使用 TypeScript 可以帮助你提高代码的可维护性和可读性。下面是一些最佳实践:
使用 Vue CLI 创建 TypeScript 项目 : 
在选择配置时,选择 TypeScript。
定义组件类型 :defineComponent 来定义组件并使用类型注解: 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <template>   <div > {{ message }}</div >  </template> <script  lang ="ts" > import  { defineComponent } from  'vue' ;export  default  defineComponent ({  data (     return  {       message : 'Hello, TypeScript!'      };   } }); </script > 
使用 props 类型 :defineProps 来定义 Props 的类型: 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script lang="ts" > import  { defineComponent } from  'vue' ;export  default  defineComponent ({  props : {     title : {       type : String ,       required : true      }   },   setup (props ) {     return  () =>  <h1 > {props.title}</h1 >    } }); </script> 
2. 自定义指令 2.1 创建和使用自定义指令 自定义指令可以让你在 DOM 元素上添加自定义行为。下面是如何创建和使用自定义指令的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;const  app = createApp (App );app.directive ('focus' , {      mounted (el ) {     el.focus ();    } }); app.mount ('#app' ); 
1 2 3 <template >   <input  v-focus  placeholder ="我会自动聚焦"  />  </template > 
在这个示例中,我们创建了一个名为 v-focus 的自定义指令,当元素插入到 DOM 时会自动聚焦。
3. 插件开发 3.1 开发和安装 Vue 插件 Vue 插件可以扩展 Vue 的功能。下面是如何创建和使用一个插件的步骤。
1 2 3 4 5 6 7 8 export  default  {  install (app ) {     app.config .globalProperties .$log  = (message ) =>  {       console .log (message);     };   } }; 
1 2 3 4 5 6 7 8 9 10 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;import  MyPlugin  from  './my-plugin' ;const  app = createApp (App );app.use (MyPlugin );  app.mount ('#app' ); 
1 2 3 4 5 6 7 8 9 10 11 12 13 <template >   <button  @click ="logMessage" > 点击我</button >  </template > <script > export  default  {  methods : {     logMessage (       this .$log('Hello from Vue plugin!' );      }   } }; </script > 
在这个示例中,我们创建了一个简单的插件,提供了一个全局的 $log 方法来输出日志。
4. 使用第三方库 4.1 集成 Element Plus、Vuetify 等 UI 库 在 Vue 3 中,可以很方便地集成 UI 库。以下是如何使用 Element Plus 和 Vuetify 的示例。
4.1.1 集成 Element Plus 
安装 Element Plus : 
1 npm install element-plus 
在项目中导入 Element Plus : 
1 2 3 4 5 6 7 8 9 10 11 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;import  ElementPlus  from  'element-plus' ;import  'element-plus/lib/theme-chalk/index.css' ;const  app = createApp (App );app.use (ElementPlus );  app.mount ('#app' ); 
使用 Element Plus 组件 : 
1 2 3 <template >   <el-button  type ="primary" > Element Plus 按钮</el-button >  </template > 
4.1.2 集成 Vuetify 
安装 Vuetify : 
1 npm install vuetify@next 
在项目中导入 Vuetify : 
1 2 3 4 5 6 7 8 9 10 11 12 13 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;import  { createVuetify } from  'vuetify' ;import  'vuetify/styles' ; const  vuetify = createVuetify (); const  app = createApp (App );app.use (vuetify);  app.mount ('#app' ); 
使用 Vuetify 组件 : 
1 2 3 <template >   <v-btn  color ="primary" > Vuetify 按钮</v-btn >  </template > 
十三、项目实战 1. 项目概述 我们将创建一个 Todo List 应用,用户可以添加、删除和标记任务为完成。应用将使用 Vue 3、TypeScript、Vue Router、Vuex(状态管理)以及自定义指令等技术栈。
2. 项目结构 项目结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 todo-app/ ├── public/ │   └── index.html  ├── src / │   ├── assets/ │   ├── components/ │   │   ├── TodoItem.vue  │   │   └── TodoList.vue  │   ├── store/ │   │   └── index.ts  │   ├── router/ │   │   └── index.ts  │   ├── App.vue  │   ├── main .ts  │   └── styles.css  └── package.json 
3. 初始化项目 使用 Vue CLI 创建项目,并选择 TypeScript 和 Vue Router:
1 2 3 vue create todo-app cd  todo-appvue add router 
选择“使用历史模式”以避免 URL 中的哈希符号。
4. 配置 Vuex 状态管理 在 src/store/index.ts 中配置 Vuex:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import  { createStore } from  'vuex' ;export  interface  Todo  {  id : number ;   text : string ;   completed : boolean ; } export  interface  State  {  todos : Todo []; } const  store = createStore<State >({  state : {     todos : []   },   mutations : {     addTodo (state, text : string  ) {       const  newTodo : Todo  = {         id : Date .now (),         text,         completed : false        };       state.todos .push (newTodo);     },     toggleTodo (state, id : number  ) {       const  todo = state.todos .find (todo  =>id  === id);       if  (todo) {         todo.completed  = !todo.completed ;       }     },     removeTodo (state, id : number  ) {       state.todos  = state.todos .filter (todo  =>id  !== id);     }   },   actions : {     addTodo ({ commit }, text : string  ) {       commit ('addTodo' , text);     },     toggleTodo ({ commit }, id : number  ) {       commit ('toggleTodo' , id);     },     removeTodo ({ commit }, id : number  ) {       commit ('removeTodo' , id);     }   },   getters : {     allTodos : state  =>todos ,     completedTodos : state  =>todos .filter (todo  =>completed ),     pendingTodos : state  =>todos .filter (todo  =>completed )   } }); export  default  store;
5. 配置路由 在 src/router/index.ts 中配置路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import  { createRouter, createWebHistory } from  'vue-router' ;import  TodoList  from  '../components/TodoList.vue' ;const  routes = [  {     path : '/' ,     name : 'Home' ,     component : TodoList    } ]; const  router = createRouter ({  history : createWebHistory (process.env .BASE_URL ),   routes }); export  default  router;
6. 创建组件 6.1 TodoList.vue 在 src/components/TodoList.vue 中创建 Todo 列表和输入框:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 <template>   <div>     <h1>Todo List</h1>     <input v-model="newTodo" @keypress.enter="addTodo" placeholder="添加新的任务" />     <ul>       <li v-for="todo in todos" :key="todo.id">         <TodoItem :todo="todo" @toggle="toggleTodo" @remove="removeTodo" />       </li>     </ul>   </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; import { useStore } from 'vuex'; import TodoItem from './TodoItem.vue'; export default defineComponent({   components: { TodoItem },   setup() {     const store = useStore();     const newTodo = ref('');     const addTodo = () => {       if (newTodo.value.trim()) {         store.dispatch('addTodo', newTodo.value);         newTodo.value = '';       }     };     const toggleTodo = (id: number) => {       store.dispatch('toggleTodo', id);     };     const removeTodo = (id: number) => {       store.dispatch('removeTodo', id);     };     return {       newTodo,       todos: store.getters.allTodos,       addTodo,       toggleTodo,       removeTodo     };   } }); </script> <style> /* 适当的样式 */ input {   padding: 10px;   margin-bottom: 20px; } ul {   list-style: none;   padding: 0; } </style> 
6.2 TodoItem.vue 在 src/components/TodoItem.vue 中创建每个 Todo 项目的显示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <template>   <div>     <span :class="{ completed: todo.completed }" @click="toggle">{{ todo.text }}</span>     <button @click="remove">删除</button>   </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { Todo } from '../store'; export default defineComponent({   props: {     todo: {       type: Object as () => Todo,       required: true     }   },   emits: ['toggle', 'remove'],   setup(props, { emit }) {     const toggle = () => {       emit('toggle', props.todo.id);     };     const remove = () => {       emit('remove', props.todo.id);     };     return {       toggle,       remove     };   } }); </script> <style> .completed {   text-decoration: line-through;   color: gray; } </style> 
7. 主应用配置 在 src/App.vue 中配置主应用:
1 2 3 4 5 6 7 8 9 <template>   <router-view /> </template> <script> export default {   name: 'App' }; </script> 
8. 入口文件 在 src/main.ts 中配置入口文件:
1 2 3 4 5 6 7 8 9 10 import  { createApp } from  'vue' ;import  App  from  './App.vue' ;import  store from  './store' ;import  router from  './router' ;import  './styles.css' ;createApp (App )  .use (store)   .use (router)   .mount ('#app' ); 
9. 运行应用 在项目目录中运行以下命令以启动开发服务器:
打开浏览器,访问 http://localhost:8080(或控制台输出的地址),你应该能看到 Todo List 应用,能够添加、删除和标记任务。
结语