博主头像
简单

tired

头图

Vue学习

Vue

1.创建应用

简单开发,导入vue.global.js在目录下,head中加入

<script src="vue.global.js"></script>

模块化开发,导入vue.esm-browser.js在目录下,在js中导入

<script type="module">
        import {createApp,reactive,ref} from './vue.esm-browser.js'
</script>

"渐进式"是指可以按需引入Vue.js的部分功能, 而不必全量引入整个框架

<div id="app">
    {{ msg }}

    <h2>{{ web.title }}</h2>
    <h3>{{ web.url }}</h3>
</div>
<div id="app"></div> 指定一个 id 为 app 的 div 元素
/*
{{ }} 插值表达式, 可以将 Vue 实例中定义的数据在视图中进行渲染
    如: Vue 实例中定义一个 msg 变量, 值为 "Hello world", 在模板中若使用插值表达式 {{ msg }} 则会被渲染成 "Hello world"

    响应式数据是指当数据发生变化时, 模板中依赖于该数据的部分会自动更新
*/
    //创建一个 Vue 应用程序
    Vue.createApp({
        //Composition API(组合式 API) 的 setup选项 用于设置响应式数据和方法等
        setup() {
            //Composition API 的 reactive()函数 用于创建响应式数据
            const web = Vue.reactive({ //Vue.reactive 创建一个响应式数据对象 web, 其中包含 title 和 url 属性
                title: "邓瑞编程",
                url: "dengruicode.com"
            })

            //返回数据
            return {
                msg: "success",
                web
            }
        }
    }).mount("#app") //将 Vue 应用程序挂载(mount) 到 app 元素上


//将 Vue 对象中的 createApp、reactive 属性赋值给 createApp、reactive 变量,解构后不用使用Vue.来调用
const { createApp, reactive } = Vue //解构赋值语法

createApp({
    setup() {
        const web = reactive({
            title: "邓瑞编程",
            url: "dengruicode.com"
        })

        return {
            msg: "success",
            web
        }
    }
}).mount("#app")

完整:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>
<body>
    
    <div id="app">
        {{ msg }}

        <h2>{{ number }}</h2>
    </div>

    <script type="module">
        import {createApp,reactive,ref} from './vue.esm-browser.js'

        createApp({
            setup() {
                const number = ref(10)

                const web = reactive({
                    title:"wsy",
                    url:"wsy.com",
                    show: true
                })

                return{
                    msg:"success",
                    number,
                    web                    
                }

            }
        }).mount("#app")
    </script>

</body>
</html>

2.ref和reactive(响应式对象数据)

const number = ref(10) //ref用于存储单个基本类型的数据, 如:数字、字符串等,但是也可以用于数组,例如const number = ref([1,2,3])

number.value = 20 //使用ref创建的响应式对象, 需要通过.value属性来访问和修改其值

const web = reactive({ //用于存储复杂数据类型, 如:对象或数组等
    title: "邓瑞编程",
    url: "dengruicode.com"
})
web.url = "www.dengruicode.com" //使用reactive创建的响应式对象, 可以直接通过属性名来访问和修改值

注意,在模板中使用 ref 时,我们不需要附加 .value。为了方便起见,当在模板中使用时,ref 会自动解包 (有一些注意事项)。

import { ref } from 'vue'

const count = ref(0)

{{ count }}

与 reactive 对象不同的是,当 ref 作为响应式数组或原生集合类型 (如 Map) 中的元素被访问时,它不会被解包:

const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)

3.v-on(监听事件,绑定方法)

img
img

v-on:事件="方法" 用来监听事件,也可以简写为 @事件="方法"

<!-- v-on:click 表示在 button 元素上监听 click 事件 -->
<button v-on:click="edit">修改</button> <br>

<!-- @click 简写形式 -->
<button @click="add(20, 30)">加法</button> <br>

<!-- 
enter space tab 按键修饰符
keyup是在用户松开按键时才触发
keydown是在用户按下按键时立即触发
-->
回车 <input type="text" @keyup.enter="add(40, 60)"> <br>
空格 <input type="text" @keyup.space="add(20, 30)"> <br>
Tab <input type="text" @keydown.tab="add(10, 20)"> <br>
w <input type="text" @keyup.w="add(5, 10)"> <br>

<!-- 组合快捷键 -->
Ctrl + Enter <input type="text" @keyup.ctrl.enter="add(40, 60)"> <br>
Ctrl + A <input type="text" @keyup.ctrl.a="add(20, 30)">
createApp({
    setup() {
        const web = reactive({
            title: "邓瑞编程",
            url: "dengruicode.com",
            user: 0
        })

        const edit = () => {
            web.url = "www.dengruicode.com"
            //msg = "邓瑞编程" //错误示例 不能直接改变msg的值,因为msg是一个普通变量, 不是响应式数据
        }

        const add = (a, b) => {
            web.user += a + b
        }

        const sub = (a, b) => {
            return a - b
        }

        return {
            msg: "success", //普通变量, 非响应式数据, 在模板中普通变量不会自动更新
            web, //响应式数据
            edit, //方法
            add,
            sub,
        }
    }
}).mount("#app")

4.v-show(显示隐藏)

当v-show="对象",这个对象为true时就渲染显示该部分,为false就不显示

<div id="app">
    <h3>{{ web.show }}</h3>
    <p v-show="web.show">邓瑞编程 dengruicode.com</p>

    <button @click="toggle">点击切换显示状态</button>
</div>
/*
v-show 通过 css display属性 来控制元素的显示或隐藏
v-show 适用于频繁切换元素的显示状态, 因为只改变 display 属性, 不需要重新渲染整个组件
*/

createApp({
    setup() {
        const web = reactive({
            show: true
        })

        const toggle = () => {
            web.show = !web.show
        }

        return {
            web,
            toggle
        }
    }
}).mount("#app")

5.v-if、v-else、v-else-if(条件渲染)

<div id="app">
    <h3>{{ web.show }}</h3>
    <p v-show="web.show">邓瑞编程</p>
    <p v-if="web.show">dengruicode.com</p>

    <button @click="toggle">点击切换显示状态</button>

    <p v-if="web.user < 1000">新网站</p>
    <p v-else-if="web.user >= 1000 && web.user < 10000">优秀网站</p>
    <p v-else-if="web.user >= 10000 && web.user < 100000">资深网站</p>
    <p v-else>超级网站</p>
</div>
/*
        v-if 用于对元素进行条件渲染. 当条件为 true 时, 渲染该元素, 为 false 时, 则不渲染
        v-if 适用于较少改变的场景, 因为频繁从 dom 中删除或添加元素, 会导致性能下降
    */
createApp({
    setup() {
        const web = reactive({
            show: true,
            user: 500
        })

        const toggle = () => {
            web.show = !web.show
        }

        return {
            web,
            toggle
        }
    }
}).mount("#app")

6.v-bind(动态绑定)

v-bind:value(或者src、class等等)="对象", 绑定数据对象后,当数据对象改变,绑定的内容也会进行改变渲染
单向绑定只是绑定对象数据,当修改对象后,不会对其他绑定了该对象的数据进行修改渲染

<div id="app">
    <!--静态值-->
    <h3>value="dengruicode.com"</h3>
    <input type="text" value="dengruicode.com">

    <!--单向绑定:value-->
    <h3>v-bind:value="web.url"</h3>
    <input type="text" v-bind:value="web.url">

    <h3>简写 :value="web.url"</h3>
    <input type="text" :value="web.url">

    <!-- :src -->
    <h3>src="windows.jpg"</h3>
    <img src="windows.jpg">

    <h3>:src="web.img"</h3>
    <img :src="web.img">

    <!-- :class -->
    <h3>class="textColor"</h3>
    <b class="textColor">邓瑞编程</b>

    <!-- :class="{ 类名: 条件表达式 }" 当条件表达式
    为真,<b class="textColor">dengruicode.com</b> 
    为假,<b>dengruicode.com</b>-->
    <h3>:class="{textColor:web.fontStatus}"</h3>
    <b :class="{textColor:web.fontStatus}">dengruicode.com</b>
</div>
createApp({
    setup() {
        const web = reactive({
            url: "www.dengruicode.com",
            img: "windows.jpg",
            fontStatus: true
        })

        return {
            web
        }
    }
}).mount("#app")

7.v-for(遍历数组对象)

v-for="参数" in 对象数据

<div id="app">
    <ul>
        <li v-for="(value, index) in data.number">
            index=> {{ index }} : value=> {{ value }}
        </li>
    </ul>

    <ul>
        <li v-for="value in data.user">
            value=> {{ value }}
        </li>
    </ul>

    <ul>
        <li v-for="(value, key) in data.user">
            key=> {{ key }} : value=> {{ value }}
        </li>
    </ul>

    <ul>
        <li v-for="(value, key, index) in data.user">
            index=> {{ index }} : key=> {{ key }} : value=> {{ value }}
        </li>
    </ul>

    <ul>
        <!-- <template> 标签可以用来包装多个元素或者多行代码, 不会在页面中渲染  -->
        <template v-for="(value, key, index) in data.user">
            <li v-if="index == 1">
                index=> {{ index }} : key=> {{ key }} : value=> {{ value }}
            </li>
        </template>
    </ul>

    <ul>
        <!-- :key="value.id" 为 每个 li 元素设置一个唯一的 key 值 -->
        <li v-for="(value, index) in data.teacher" :title="value.name" :key="value.id">
            index=> {{ index }} : value.id=>{{ value.id }} value.name=>{{ value.name }} value.web=>{{ value.web }}
        </li>
    </ul>
</div>
createApp({
    setup() {
        const data = reactive({
            number: ["十", "十一", "十二"], //数组
            user: { //对象
                name: "Luna",
                gender: "女"
            },
            teacher: [ //包含两个对象的数组
                { id: 100, name: "邓瑞", web: "dengruicode.com" },
                { id: 101, name: "David", web: "www.dengruicode.com" }
            ]
        })

        return {
            data
        }
    }
}).mount("#app")

8.v-model(双向绑定)

双向绑定既对当前使用了v-model的 对象数据进行修改,也会对其他绑定了该对象的部分也进行修改渲染

<div id="app">
    <h3>文本框 {{ data.text }}</h3>
    <h3>单选框 {{ data.radio }}</h3>
    <h3>复选框 {{ data.checkbox }}</h3>
    <h3>记住密码 {{ data.remember }}</h3>
    <h3>下拉框 {{ data.select }}</h3>

    <!-- 单向数据绑定 当数据发生改变时, 视图会自动更新. 但用户手动更改 input 的值, 数据不会自动更新 -->
    单向数据绑定 <input type="text" :value="data.text">

    <hr>
    <!-- 
        双向数据绑定 当数据发生改变时, 视图会自动更新. 当用户手动更改 input 的值, 数据也会自动更新
        对于 <input type="text">, v-model 绑定的是 input 元素的 value 属性
     -->
    双向数据绑定 <input type="text" v-model="data.text">

    <hr>
    <!-- 
        单选框
        对于 <input type="radio">, v-model 绑定的是 input 元素的选中状态
     -->
    <input type="radio" v-model="data.radio" value="1">写作
    <input type="radio" v-model="data.radio" value="2">画画

    <hr>
    <!-- 
        复选框
        对于 <input type="checkbox">, v-model 绑定的是 input 元素的选中状态
     -->
    <input type="checkbox" v-model="data.checkbox" value="a">写作
    <input type="checkbox" v-model="data.checkbox" value="b">画画
    <input type="checkbox" v-model="data.checkbox" value="c">运动

    <hr>
    <!-- 记住密码 -->
    <input type="checkbox" v-model="data.remember">记住密码

    <hr>
    <!-- 
        下拉框
        对于 <select>, v-model 绑定的是 select 元素的选中状态
     -->
    <select v-model="data.select">
        <option value="">请选择</option>
        <option value="A">写作</option>
        <option value="B">画画</option>
        <option value="C">运动</option>
    </select>
</div>
createApp({
    setup() {
        const data = reactive({
            text: "dengruicode.com", //文本框
            radio: "", //单选框
            checkbox: [], //复选框
            remember: false, //单个复选框-记住密码
            select: "" //下拉框
        })

        return {
            data
        }
    }
}).mount("#app")    

9.v-model修饰符

<div id="app">
    <h3>url: {{ web.url }}</h3>
    <h3>user: {{ web.user }}</h3>

    实时渲染 <input type="text" v-model="web.url"> <br>

    在失去焦点或按下回车键之后渲染 <input type="text" v-model.lazy="web.url"> <br>

    <!-- 输入 100人, web.user 的值仍为 100 -->
    输入框的值转换为数字类型 <input type="text" v-model.number="web.user"> <br>

    去除首尾空格 <input type="text" v-model.trim="web.url">
</div>
createApp({
    setup() {
        const web = reactive({
            url: "dengruicode.com",
            user: 10
        })

        return {
            web
        }
    }
}).mount("#app")

10.v-text、v-html(渲染数据)

<div id="app">
    <h3>{{ web.title }}</h3>

    <!-- v-text 将数据解析为纯文本格式 -->
    <h3 v-text="web.title"></h3>

    <!-- v-html 将数据解析为 html 格式 -->
    <h3 v-html="web.url"></h3>
</div>
createApp({
    setup() {
        const web = reactive({
            title: "邓瑞编程",
            url:"<i style='color:blue;'>www.dengruicode.com</i>"
        })

        return {
            web
        }
    }
}).mount("#app")

11.computed(计算属性)

computed的计算是有缓存的,当有执行过一次后,再次计算,会调用之前的缓存

<div id="app">
    <h3>add: {{ add() }}</h3>
    <h3>add: {{ add() }}</h3>

    <h3>sum: {{ sum }}</h3>
    <h3>sum: {{ sum }}</h3>

    x <input type="text" v-model.number="data.x"> <br>
    y <input type="text" v-model.number="data.y">
</div>
import { computed } from './vue.esm-browser.js'
createApp({
    setup() {
        const data = reactive({
            x: 10,
            y: 20
        })

        //方法-无缓存
        let add = () => {
            console.log("add") //打印两次
            return data.x + data.y
        }

        //计算属性-有缓存 [计算属性根据其依赖的响应式数据变化而重新计算]
        const sum = computed(() => {
            console.log("sum") //打印一次
            return data.x + data.y
        })

        return {
            data,
            sum,
            add
        }
    }
}).mount("#app")

12.监听器watch

<div id="app">
    爱好
    <select v-model="hobby">
        <option value="">请选择</option>
        <option value="1">写作</option>
        <option value="2">画画</option>
        <option value="3">运动</option>
    </select>

    <hr>

    年
    <select v-model="date.year">
        <option value="">请选择</option>
        <option value="2023">2023</option>
        <option value="2024">2024</option>
        <option value="2025">2025</option>
    </select>

    月
    <select v-model="date.month">
        <option value="">请选择</option>
        <option value="10">10</option>
        <option value="11">11</option>
        <option value="12">12</option>
    </select>
</div>
import { watch } from './vue.esm-browser.js'
createApp({
    setup() {
        const hobby = ref("") //爱好
        const date = reactive({ //日期
            year: "2023",
            month: "10"
        })

        //监听 hobby
        watch(hobby, (newValue, oldValue) => {
            console.log("oldValue", oldValue, "newValue", newValue)

            if (newValue == "2") {
                console.log("画画")
            }
        })

        //监听 date
        watch(date, (newValue, oldValue) => {
            /*
                    JS中对象和数组是通过引用传递的, 而不是通过值传递
                    当修改对象或数组的值时, 实际上修改的是对象或数组的引用, 而不是创建一个新的对象或数组
                    所以,如果修改了对象或数组的值,那么打印出来的结果则是修改后的值
                */
            console.log("oldValue", oldValue, "newValue", newValue)

            if (newValue.year == "2025") {
                console.log("2025")
            }

            if (newValue.month == "11") {
                console.log("11")
            }
        })

        //监听 date 中的某个属性 year
        watch(() => date.year, (newValue, oldValue) => {
            console.log("oldValue", oldValue, "newValue", newValue)

            if (date.year == "2024") {
                console.log("2024")
            }
        })

        return {
            hobby,
            date
        }
    }
}).mount("#app")

13.自动监听器watchEffect

<div id="app">
    爱好
    <select v-model="hobby">
        <option value="">请选择</option>
        <option value="1">写作</option>
        <option value="2">画画</option>
        <option value="3">运动</option>
    </select>

    <hr>

    年
    <select v-model="date.year">
        <option value="">请选择</option>
        <option value="2023">2023</option>
        <option value="2024">2024</option>
        <option value="2025">2025</option>
    </select>

    月
    <select v-model="date.month">
        <option value="">请选择</option>
        <option value="10">10</option>
        <option value="11">11</option>
        <option value="12">12</option>
    </select>
</div>
/*
        watch需要显式指定要监听的属性, 并且只有当监听的属性发生变化时才会执行
        若需要更精细地控制或需要获取到原值, 需要使用watch
    */
import { watchEffect } from './vue.esm-browser.js'

createApp({
    setup() {
        const hobby = ref("") //爱好
        const date = reactive({ //日期
            year: "2023",
            month: "10"
        })

        //自动监听
        watchEffect(() => {
            console.log("------ 监听开始")

            if (hobby.value == "2") {
                console.log("画画")
            }

            if (date.year == "2025") {
                console.log("2025")
            }

            if (date.month == "11") {
                console.log("11")
            }

            console.log("------ 监听结束")
        })

        return {
            hobby,
            date
        }
    }
}).mount("#app")

14.axios使用

导入:axios.min.js, 例如:

<script src="js/axios.min.js"></script>
//get请求
axios.get(`http://127.0.0.1/article/get/id/${id}`).then(response => {
    console.log("get.data:", response.data)

    if(response.data.status == "success"){
        if(response.data.data){
            data.list.push(response.data.data) //push 向数组末尾添加一个或多个元素
        }
    }
}).catch(error => {
    console.log("get.error:", error)
})

//post请求 [axios post的默认请求头是 application/json]
axios.post('http://127.0.0.1/article/postJson/search', param).then(response => {
    console.log("postJson.data:", response.data)

    if(response.data.status == "success"){
        for(let i=0; i<response.data.data.length; i++){
            data.list.push(response.data.data[i]) //push 向数组末尾添加一个或多个元素
        }
    }
}).catch(error => {
    console.log("postJson.error:", error)
})

15.使用Vite创建vue3项目

(1)npm create vite@latest

(2)选择y

(3)project name:要创建的项目名

(4)选择vue

(5) Done. Now run:

  • ​ cd demo
  • ​ npm install
  • ​ npm run dev

​ 删除文件

​ src\style.css

​ src\components\HelloWorld.vue

​ 删除代码

​ main.js

​ import './style.css'

16.使用vue(官方)创建vue3项目

下面把 create-vue 交互里每一个「Yes/No」选项拆开讲:

  • 选了 Yes 之后到底会 额外 给你什么文件 / 依赖 / 配置;
  • 这些配置在真实开发里到底解决什么问题。

你可以把它当成一份「勾选清单说明书」。

npm create vue@latest

──────────────────────────

  1. Project name
    • 作用:仅决定文件夹名,与 npm 包名一致(package.json 里的 "name" 字段)。
    • 额外产物:一个同名目录,无其他配置差异。

──────────────────────────

  1. Add TypeScript → Yes
    额外给你:
    • 文件后缀改成 .ts/.vue 里 <script setup lang="ts">
    • tsconfig.json、tsconfig.node.json(TypeScript 编译选项)
    • env.d.ts(让 TS 识别 *.vue、vite/client 类型)
    • 依赖:typescript、vue-tsc(build 时做类型检查)

开发收益:
静态类型检查、IDE 自动补全、重构更安心。

──────────────────────────

  1. JSX Support → Yes
    额外给你:
    • vite.config.ts 里自动加 jsx 插件:
    import vueJsx from '@vitejs/plugin-vue-jsx'
    plugins: [vue(), vueJsx()]

• 示例文件:src/components/HelloWorld.jsx / tsx
• 依赖:@vitejs/plugin-vue-jsx

开发收益:
可在 .jsx/.tsx 或 <script setup lang="tsx"> 里写 render 函数 / 高阶组件。

──────────────────────────

  1. Vue Router → Yes
    额外给你:
    • src/router/index.ts(路由表、history 模式)
    • src/views/ 目录 + HomeView.vue / AboutView.vue 示例
    • main.ts 里 app.use(router)
    • 依赖:vue-router@4

开发收益:
SPA 多页面切换、路由守卫、动态路由。

──────────────────────────

  1. Pinia → Yes
    额外给你:
    • src/stores/ 目录 + counter.ts 示例(defineStore)
    • main.ts 里 app.use(createPinia())
    • 依赖:pinia

开发收益:
全局状态管理,替代 Vuex,DevTools 支持热更新。

──────────────────────────

  1. Vitest → Yes(单元测试)
    额外给你:
    • vitest.config.ts(测试专用 Vite 配置)
    • src/components/__tests__/HelloWorld.spec.ts 示例
    • package.json script:"test:unit": "vitest"
    • 依赖:vitest、jsdom、@vue/test-utils

开发收益:
单文件组件也能跑 Jest-like 测试,速度比 Jest + vue-jest 快很多。

──────────────────────────

  1. Cypress → Yes(端到端测试)
    额外给你:
    • cypress/ 目录
    ├─ e2e/
    │ └─ example.cy.ts(访问首页断言标题存在)
    ├─ fixtures/
    ├─ support/
    • package.json script:"test:e2e": "cypress open"
    • 依赖:cypress

开发收益:
在真实浏览器里跑完整用户流程(登录、跳转、交互),防止集成缺陷。

──────────────────────────

  1. ESLint → Yes
    额外给你:
    • .eslintrc.cjs(extends: ["@vue/eslint-config-typescript/recommended", "@vue/eslint-config-prettier"])
    • package.json script:"lint": "eslint . --ext .vue,.js,.ts"
    • 依赖:eslint、@vue/eslint-config-* 系列

开发收益:
自动发现语法错误、风格违规;配合 IDE 红线提示 & 保存即修复。

──────────────────────────

  1. Prettier → Yes
    额外给你:
    • .prettierrc.json(printWidth、semi、singleQuote 等)
    • .vscode/extensions.json 推荐安装 Prettier 插件
    • 依赖:prettier

开发收益:
一键统一缩进、换行、引号风格,避免团队因格式争吵。

──────────────────────────

  1. DevTools / VS Code 建议
    create-vue 还会根据你的选择自动生成:
    • .vscode/extensions.json(推荐 Volar、ESLint、Prettier)
    • .vscode/settings.json(保存时自动格式化、ESLint 自动修复)

这些不算 Yes/No 选项,但会在你选了 ESLint/Prettier/TS 后自动出现。

──────────────────────────
一句话速记
TS / JSX 决定语言特性;Router / Pinia 决定架构;Vitest / Cypress 决定测试策略;ESLint / Prettier 决定代码质量。
全部选 Yes 你就拿到一个「可直接上线」的现代化 Vue3 工程模板;全部选 No 就是最小可运行示例。

17.区别

一句话区别
npm create vue@latest 是「官方 Vue 团队做的、只给 Vue3 用的『应用级』脚手架」;
npm create vite@latest 是「Vite 官方做的、面向所有框架的『通用』脚手架」。

下面把两条命令在 6 个维度拆开对比,你就能知道什么时候该用哪一个。

────────────────────────────

  1. 作者 & 维护者
    • create-vue:Vue 核心团队(Evan You、三咲智子等人)维护,发布节奏跟 Vue 版本走。
    • create-vite:Vite 核心团队(patak 等人)维护,发布节奏跟 Vite 版本走。

────────────────────────────

  1. 适用范围
    • create-vue:只生成 Vue3 项目。
    • create-vite:可选 Vanilla、Vue、React、Preact、Svelte、Solid、Lit、Qwik、Alpine……
    也就是说,用 create-vite 也可以选 Vue,但它不会给你 Pinia、Router、ESLint、Prettier 等「Vue 全家桶」预设。

────────────────────────────

  1. 交互式提问
    • create-vue:
    ‑ Project name
    ‑ TypeScript?
    ‑ JSX?
    ‑ Vue Router?
    ‑ Pinia?
    ‑ Vitest?
    ‑ Cypress?
    ‑ ESLint?
    ‑ Prettier?
    一口气帮你把“一个真实业务项目”需要的配置都问完。

​ • create-vite:

      ‑ Project name  
      ‑ Framework?  
      ‑ Variant?(如 vue-ts、vue、react-ts、react-swc-ts …)  
      只问框架和语言变体,不会问 Router、状态管理、测试、Lint。

────────────────────────────

  1. 生成的目录/文件差异
    • create-vue 会额外给你:
    src/router/、src/stores/、.eslintrc.cjs、.prettierrc.json、cypress/、vitest.config.ts、.vscode/extensions.json、README.md(带 VueLogo)。

​ • create-vite(选 vue-ts)只会给你最简的:

      src/main.ts、src/App.vue、src/style.css、vite.config.ts、index.html、tsconfig.json —— 没有 Router、没有         Pinia、没有测试、没有 ESLint。

────────────────────────────

  1. 默认依赖
    • create-vue:
    "dependencies": { vue, vue-router?, pinia? }
    "devDependencies": { vite, @vitejs/plugin-vue, eslint, prettier, vitest, cypress }

​ • create-vite:
​ "dependencies": { vue }

      "devDependencies": { vite, @vitejs/plugin-vue }

────────────────────────────

  1. 适用场景
    • 想一步到位得到「可直接写业务」的 Vue3 SPA → 用 npm create vue@latest。
    • 想从零开始、自己决定要不要 Router / Pinia / ESLint,或想搭非 Vue 项目 → 用 npm create vite@latest。
    • 想学习 Vite 配置、做最小复现 Demo → 用 create-vite 选 Vanilla 或对应框架最简模板最快。

────────────────────────────
一句话总结
create-vue = create-vite 的「Vue 全家桶特供版」。
前者给你「拎包入住」的 Vue3 应用,后者给你「毛坯房」让你自由装修。

  1. cd demo
    进入刚生成的项目目录(你之前把项目起名叫 demo)。
  2. npm install
    安装 package.json 里列出的所有依赖(vite、vue、router、pinia、eslint…)。这一步会把 node_modules 拉下来,项目才能真正跑起来。
  3. npm run format
    运行 Prettier 一键格式化所有代码(src、tests、config 等)。脚手架默认把 Prettier 规则配好了,执行后代码风格立刻统一。
  4. npm run dev
    启动 Vite 开发服务器,默认打开 http://localhost:5173,热更新实时预览页面。
  5. git init && git add -A && git commit -m "initial commit"(可选)
    在项目里初始化 Git 仓库 → 把所有文件加入暂存区 → 提交第一条提交记录。完成后你就可以正常用 git 做版本管理了。

18.组件

<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>

<template>
  <h1>Here is a child component!</h1>
  <ButtonCounter />
</template>

defineProps

defineProps是Vue3的编译时宏函数,用于接收父组件向子组件传递的属性(props) 注: 当使用Vue编译器编译包含defineProps的组件时,编译器会将这些宏替换为相应的运行时代码

例如:子组件

const props = defineProps(["propsName","propsUrl"])

父组件:

<!-- 父传子 - 方式1 -->
<Header propsName="邓瑞编程" propsUrl="dengruicode.com" />

子组件:

//接收方式2 - 对象
    /*
    const props = defineProps({
        user: Number,
        ip: String
    })
    */
    const props = defineProps({
        user: Number,
        ip: {
            type: String,
            required: true, //true表示必传属性,若未传则会提示警告信息
            default: 'localhost' //未传默认值
        }
    })

父组件:

//响应式数据
  const propsWeb = reactive({
    user: 10,
    ip: '127.0.0.1'
  })
<!-- 父传子 - 方式2 -->
<!-- <Footer v-bind="propsWeb" /> -->
<Footer :="propsWeb" />

defineEmits

defineEmits是Vue3的编译时宏函数,用于子组件向父组件发送自定义事件
例如:

子组件:

<script setup>
//子传父
    //定义一个名为 emits 的对象, 用于存储自定义事件
    const emits = defineEmits(["web","user"])
    //发送名为 web的自定义事件
    emits("web", {name:"邓瑞",url:"www.dengruicode.com"})
    
    //添加用户
    const userAdd = () => {
        //发送名为 user 的自定义事件
        emits("user", 10)
    }
</script>

<template>
    <h3>Header</h3>

    <button @click="userAdd">添加用户</button>
</template>

父组件:

<script setup>
//响应式数据
  const web = reactive({
    name: "邓瑞编程",
    url: 'dengruicode.com'
  })

  const user = ref(0)

  //子传父
  const emitsWeb = (data) => {
    console.log("emitsWeb:",data)
    web.url = data.url
  }

  const emitsUser = (data) => {
    console.log("emitsUser:",data)
    user.value += data
  }
</script>

<template>
  <!-- 子传父 -->
  <Header @web="emitsWeb" @user="emitsUser" />

  {{ web.url }} - {{ user }}
</template>

slot

插槽

<template>
  <div class="alert-box">
    <strong>Error!</strong>
    <br/>
    <slot />
  </div>
</template>
<AlertBox>
  Something bad happened.
</AlertBox>

使用 <slot> 作为一个占位符,父组件传递进来的内容就会渲染在这里

img1
img1

19.axios

下面给出一份「axios 在 2025 年 Vue 项目中的常用套路清单」——从安装、全局配置到各种业务场景,全部带可复制代码块。直接按场景 Ctrl + C / Ctrl + V 即可。

────────────────────

  1. 安装 & 全局挂载
    ────────────────────
npm i axios
Vue3 官方不再推荐把 axios 挂到 app.config.globalProperties,而是独立文件导出实例,方便 Tree-Shaking 和类型推导。

────────────────────

  1. 创建统一实例(src/utils/request.js)
    ────────────────────
import axios from 'axios'
import { ElMessage } from 'element-plus'   // UI 提示库示例

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE,  // 读取 .env 里的域名
  timeout: 10000,                          // 10 秒超时
  headers: { 'Content-Type': 'application/json' }
})

// 请求拦截器:统一携带 token
request.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) config.headers.Authorization = `Bearer ${token}`
    return config
  },
  error => Promise.reject(error)
)

// 响应拦截器:统一错误提示 + 数据剥离
request.interceptors.response.use(
  response => response.data,               // 直接返回业务数据
  error => {
    const msg = error.response?.data?.message || '网络错误'
    ElMessage.error(msg)
    return Promise.reject(error)           // 继续抛出,让组件 catch
  }
)

export default request

────────────────────

  1. 在组件/Store 里四种常见调用
    ────────────────────
    ① 查询(GET)
import request from '@/utils/request'

// 无参数
const list = await request.get('/articles')

// 带查询参数 → ?page=1&size=10
const list2 = await request.get('/articles', { params: { page: 1, size: 10 } })

② 提交(POST)

await request.post('/login', { username, password })

③ 上传文件(POST + FormData)

const fd = new FormData()
fd.append('file', file.raw)
const { url } = await request.post('/upload', fd, {
  headers: { 'Content-Type': 'multipart/form-data' }
})

④ 并发请求(等待全部完成)

const [user, order] = await Promise.all([
  request.get('/user/1'),
  request.get('/order/100')
])

────────────────────

  1. 统一错误码处理(可选)
    ────────────────────
    在响应拦截器里加 switch:
switch (error.response?.status) {
  case 401:
    router.push('/login')
    break
  case 403:
    ElMessage.warning('无权限')
    break
  case 500:
    ElMessage.error('服务器异常')
    break
}

────────────────────

  1. TypeScript 类型提示(src/types/request.d.ts)
    ────────────────────
declare module '@/utils/request' {
  import { AxiosInstance } from 'axios'
  const request: AxiosInstance
  export default request
}

────────────────────

  1. 常见业务场景速查
    ────────────────────
场景一行代码示例
下载文件await request({ url: '/download', method: 'get', responseType: 'blob' })
带进度条上传onUploadProgress: e => setProgress(Math.round(e.loaded * 100 / e.total))
取消请求const source = axios.CancelToken.source(); source.cancel()
微前端子应用baseURL 设成 window.__POWERED_BY_QIANKUN__ ? '/child-api' : '/api'

────────────────────

  1. 一句话总结
  • axios 负责「发请求 + 拦截器 + 错误处理」。
  • 在 Vue 中写成「统一实例 + async/await」即可覆盖 99 % 场景。
Vue学习
https://yufornote.xyz/index.php/archives/9/
本文作者 yu
发布时间 2025-08-12
许可协议 CC BY-NC-SA 4.0
已有 2 条评论
  1. 评论头像

    寻找华纳圣淘沙公司开户代理(183-8890-9465薇-STS5099】

    华纳圣淘沙官方合作开户渠道(183-8890-9465薇-STS5099】

    华纳圣淘沙公司开户代理服务(183-8890-9465薇-STS5099】

    华纳圣淘沙公司开户咨询热线(183-8890-9465薇-STS5099】

    联系客服了解华纳圣淘沙开户

    (183-8890-9465薇-STS5099】
    华纳圣淘沙公司开户专属顾问

    (183-8890-9465薇-STS5099】

  2. 评论头像

    In addition, a generous introductory bonus. new users to sign up and experience everything available. are significant for a successful start in the online gaming arena.
    also stands out of this gaming site. Participants have the option to connect, electronic mail, or phone. The speed of their responses, ensuring players can address concerns without delay. a commitment to customer satisfaction.
    Finally, focuses on. Using, players can feel safe while enjoying their gaming experience. provides in the entire game selection, building trust in the online casino industry.
    888startz [url=https://888starz-bettings.com/fr/]888startz[/url]

    888starz_blKi December 8th, 2025 at 05:23 am 回复
发表新评论