export default { //vue2
data(){ return {count:0} },
methods:{ addCount(){this.count++} }

}
<script setup>

import { ref } from 'vue'//vue3
const count = ref(0)
const addCount = ()=> count.value++
</script>
特点:
代码量变少分散式维护变成集中式维护2. Vue3更多的优势
2. 使用create-vue创建项目
前置条件 - 已安装16.0或更高版本的Node.js
执行如下命令,这一指令将会安装并执行 create-vue
npm init vue@latest
组合式API - setup选项1. setup选项的写法和执行时机
<script>
export default {
setup(){},
beforeCreate(){}
}
</script>
2. setup中写代码的特点
在setup函数中写的数据和方法需要在末尾以对象的方式return,才能给模版使用
<script>
export default {
setup(){
const message = 'this is message'
const logMessage = ()=>{console.log(message)}
// 必须return才可以
return { message,logMessage }
}
}
</script>
3. <script setup>语法糖
script标签添加 setup标记,不需要再写导出语句,默认会添加导出语句
<script setup>
const message = 'this is message'
const logMessage = ()=>{
console.log(message)
}
</script>
组合式API - reactive和ref函数1. reactive
接受对象类型数据的参数传入并返回一个响应式的对象
<script setup>
import { reactive } from 'vue'// 导入
const state = reactive({msg:'this is msg'})// 执行函数 传入参数 变量接收
const setSate = ()=>{ // 修改数据更新视图
state.msg = 'this is new msg'
}
</script>
<template>
{{ state.msg }}
<button @click="setState">change msg</button>
</template>
2. ref
<script setup>
import { ref } from 'vue'// 导入
const count = ref(0)// 执行函数 传入参数 变量接收
const setCount = ()=>{// 修改数据更新视图必须加上.value
count.value++
}
</script>
<template>
<button @click="setCount">{{count}}</button>
</template>
3. reactive 对比 ref
都是用来生成响应式数据不同点reactive不能处理简单类型的数据ref参数类型支持更好,但是必须通过.value做访问修改ref函数内部的实现依赖于reactive函数在实际工作中的推荐,推荐使用ref函数,减少记忆负担
组合式API - computed计算属性基本思想和Vue2保持一致,组合式API下的计算属性只是修改了API写法
<script setup>
import {ref, computed } from 'vue'// 导入
const count = ref(0)// 原始数据
const doubleCount = computed(()=>count.value 2)// 计算属性
const list = ref([1,2,3,4,5,6,7,8])// 原始数据
const filterList = computed(item=>item > 2)// 计算属性list
</script>
组合式API - watch
侦听一个或者多个数据的变化,数据变化时执行回调函数,俩个额外参数 immediate控制立刻执行,deep开启深度侦听
1. 侦听单个数据
<script setup>
import { ref, watch } from 'vue'// 1. 导入watch
const count = ref(0)
watch(count, (newValue, oldValue)=>{// 2. 调用watch 侦听变化
console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
})
</script>
2. 侦听多个数据
侦听多个数据,第一个参数可以改写成数组的写法
<script setup>
import { ref, watch } from 'vue'// 1. 导入watch
const count = ref(0)
const name = ref('cp')// 2. 调用watch 侦听变化
watch([count, name], ([newCount, newName],[oldCount,oldName])=>{
console.log(`count或者name变化了,[newCount, newName],[oldCount,oldName])
})
</script>
3. immediate
在侦听器创建时立即出发回调,响应式数据变化之后继续执行回调
<script setup>
import { ref, watch } from 'vue'// 1. 导入watch
const count = ref(0)// 2. 调用watch 侦听变化
watch(count, (newValue, oldValue)=>{
console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
},{immediate: true})
</script>
4. deep
通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep
<script setup>
import { ref, watch } from 'vue'// 1. 导入watch
const state = ref({ count: 0 })
watch(state, ()=>{// 2. 监听对象state
console.log('数据变化了')
})
const changeStateByCount = ()=>{// 直接修改不会引发回调执行
state.value.count++
}
</script>
<script setup>
import { ref, watch } from 'vue'// 1. 导入watch
const state = ref({ count: 0 })
watch(state, ()=>{// 2. 监听对象state 并开启deep
console.log('数据变化了')
},{deep:true})
const changeStateByCount = ()=>{// 此时修改可以触发回调
state.value.count++
}
</script>
声明周期
1. 选项式对比组合式
2. 生命周期函数基本使用
导入生命周期函数执行生命周期函数,传入回调<scirpt setup>
import { onMounted } from 'vue'
onMounted(()=>{
// 自定义逻辑
})
</script>
3. 执行多次
生命周期函数执行多次的时候,会按照顺序依次执行
<scirpt setup>
import { onMounted } from 'vue'
onMounted(()=>{// 自定义逻辑})
onMounted(()=>{// 自定义逻辑})
</script>
组合式API - 父子通信1. 父传子
基本思想
父组件中给子组件绑定属性子组件内部通过props选项接收数据2. 子传父
基本思想
父组件中给子组件标签通过@绑定事件子组件内部通过 emit 方法触发事件组合式API - 模版引用
概念:通过 ref标识 获取真实的 dom对象或者组件实例对象
1. 基本使用
实现步骤:
调用ref函数生成一个ref对象通过ref标识绑定ref对象到标签defineExpose默认情况下在 <script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法容许访问
说明:指定testMessage属性可以被访问到
组合式API - provide和inject
1. 作用和场景
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
2. 跨层传递普通数据
实现步骤
顶层组件通过 provide 函数提供数据底层组件通过 inject 函数提供数据3. 跨层传递响应式数据
在调用provide函数时,第二个参数设置为ref对象
4. 跨层传递方法
顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件的数据
什么是pinia
Pinia 是 Vue 的专属状态管理库,可以实现跨组件或页面共享状态,是 vuex 状态管理工具的替代品,和 Vuex相比,具备以下优势
提供更加简单的API (去掉了 mutation )提供符合组合式API风格的API (和 Vue3 新语法统一)去掉了modules的概念,每一个store都是一个独立的模块搭配 TypeScript 一起使用提供可靠的类型推断创建空Vue项目并安装Pinia1. 创建空Vue项目
npm init vue@latest
2. 安装Pinia并注册
npm i pinia
import { createPinia } from 'pinia'
const app = createApp(App)
// 以插件的形式注册
app.use(createPinia())
app.use(router)
app.mount('#app')
3.实现counter
核心步骤:
定义store组件使用store1- 定义store
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useCounterStore = defineStore('counter', ()=>{
const count = ref(0)// 数据 (state)
const increment = ()=>{ count.value++ }// 修改数据的方法 (action)
return { count,increment }// 以对象形式返回
})
2- 组件使用store
<script setup>
import { useCounterStore } from '@/stores/counter'// 1. 导入use方法
const counterStore = useCounterStore()// 2. 执行方法得到store store里有数据和方法
</script>
<template>
<button @click="counterStore.increment">{{ counterStore.count }}</button>
</template>
3-实现getters
const count = ref(0)// 数据(state)
const doubleCount = computed(() => count.value 2)// getter (computed)
4-异步action
思想:action函数既支持同步也支持异步,和在组件中发送网络请求写法保持一致
步骤:
store中定义action组件中触发actionstore中定义action
const API_URL = ''
export const useCounterStore = defineStore('counter', ()=>{
const list = ref([])// 数据
const loadList = async ()=>{// 异步action
const res = await axios.get(API_URL)
list.value = res.data.data.channels
}
return {list,loadList}
})
组件中调用action
<script setup>
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
counterStore.loadList()// 调用异步action
</script>
<template>
<ul>
<li v-for="item in counterStore.list" :key="item.id">{{ item.name }}</li>
</ul>
</template>
storeToRefs保持响应式解构直接基于store进行解构赋值,响应式数据(state和getter)会丢失响应式特性,使用storeToRefs辅助保持响应式
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
// 使用它storeToRefs包裹之后解构保持响应式
const { count } = storeToRefs(counterStore)
const { increment } = counterStore
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
------------------------------------------------------------------------------------------------------------------------
创建项目并整理目录npm init vue@latest
jsconfig.json配置别名路径
配置别名路径可以在写代码时联想提示路径
{
"compilerOptions" : {
"baseUrl" : "./",
"paths" : {
"@/":["src/"]
}
}
}
elementPlus引入
1. 安装elementPlus和自动导入插件
npm i elementPlus
npm install -D unplugin-vue-components unplugin-auto-import
2. 配置 vite.config.js 自动按需导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [// 配置插件
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
})
3. 测试组件
<template>
<el-button type="primary">i am button</el-button>
</template>
定制elementPlus主题1. 安装sass
基于vite的项目默认不支持css预处理器,需要开发者单独安装
npm i sass -D
2. 准备定制化的样式文件 styles/element/index.scss
/ 只需要重写你需要的即可 /
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': (
// 主色
'base': #27ba9b,
),
'success': (
// 成功色
'base': #1dc779,
),
'warning': (
// 警告色
'base': #ffb302,
),
'danger': (
// 危险色
'base': #e26237,
),
'error': (
// 错误色
'base': #cf4444,
),
)
)
3. 自动导入配置
这里自动导入需要深入到elementPlus的组件中,按照官方的配置文档来
自动导入定制化样式文件进行样式覆盖按需定制主题配置 (需要安装 unplugin-element-plus)vite.config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// 导入对应包
import ElementPlus from 'unplugin-element-plus/vite'
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
// 按需定制主题配置
ElementPlus({
useSource: true,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
preprocessorOptions: {
scss: {
// 自动导入定制化样式文件进行样式覆盖
additionalData: `
@use "@/styles/element/index.scss" as ;
`,
}
}
}
})
axios安装并简单封装1. 安装axios
npm i axios
2. 基础配置
官方文档地址:https://axios-http.com/zh/docs/intro
基础配置通常包括:
实例化 - baseURL + timeout拦截器 - 携带token 401拦截等utils/http.js
import axios from 'axios'
// 创建axios实例
const httpinstance = axios.create({
baseURL: 'http://pcapi-xiaotuxian-front-devtest.itheima.net',
timeout: 5000
})
// axios请求拦截器
httpinstance.interceptors.request.use(config => {
return config
}, e => Promise.reject(e))
// axios响应式拦截器
httpinstance.interceptors.response.use(res => res.data, e => {
return Promise.reject(e)
})
export default http
3. 封装请求函数并测试 apis/TestApi.js
import http from '@/utils/http'
export function getCategoryAPI () {
return http({
url: 'home/category/head'
})
}
路由整体设计
路由设计原则:找页面的切换方式,如果是整体切换,则为一级路由,如果是在一级路由的内部进行的内容切换,则为二级路由
views/Login/index.vue
<template>我是登录页</template>
views/Layout/index.vue
<template>我是首页</template>
views/Home/index.vue
<template>我是home</template>
views/Category/index.vue
<template>我是分类</template>
router/index.js
// createRouter:创建router实例对象
// createWebHistory:创建history模式的路由
import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/views/Login/index.vue'
import Layout from '@/views/Layout/index.vue'
import Home from '@/views/Home/index.vue'
import Category from '@/views/Category/index.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
// path和component对应关系的位置
routes: [
{
path: '/',
component: Layout,
children: [
{
path: '',
component: Home
},
{
path: 'category',
component: Category
}
]
},
{
path: '/login',
component: Login
}
]
})
export default router
静态资源引入和Error Lens安装
1. 静态资源引入
图片资源 - 把 images 文件夹放到 assets 目录下样式资源 - 把 common.scss 文件放到 styles 目录下2. Error Lens插件安装
scss变量自动导入
var.scss
$xtxColor: #27ba9b;
$helpColor: #e26237;
$sucColor: #1dc779;
$warnColor: #ffb302;
$priceColor: #cf4444;
css: {
preprocessorOptions: {
scss: {
// 自动导入scss文件
additionalData: `
@use "@/styles/element/index.scss" as ;
@use "@/styles/var.scss" as ;
`,
}
}
}
补充eslint配置/ eslint-env node /
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript'
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
'vue/multi-word-component-names': 0, // 不再强制要求组件命名
},
}
-------------------------------------------------------------------------------------------------------------------------