Vue3快速入门

资料

邓睿编程
【2024最新版】3小时学会Vue3,小白零基础视频教程,web前端快速入门实战课程
Vue3快速入门2 -案例篇
Vue.js - 渐进式 JavaScript 框架

Vue3快速入门

1.创建一个 vue 应用程序

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

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

    <h2>{{ web.title }}</h2>
    <h3>{{ web.url }}</h3>
</div>


js
/*
    <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 变量
const { createApp, reactive } = Vue //解构赋值语法

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

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

2.模块化开发

html 复制代码
html
<div id="app">
    {{ msg }}

    <h2>{{ web.title }}</h2>
    <h3>{{ web.url }}</h3>
</div>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'
    
    createApp({
        setup() {
            const web = reactive({
                title: "邓瑞编程",
                url: "dengruicode.com"
            })

            return {
                msg:"success",
                web
            }
        }
    }).mount("#app")
</script>


VSCode 扩展

       Live Server

3.ref和reactive

html 复制代码
html
<div id="app">
    msg: {{ msg }}

    <h3>web.title: {{ web.title }}</h3>
    <h3>web.url: {{ web.url }}</h3>
    <h3>web.number: {{ number }}</h3>
</div>
js
<script type="module">
    import { createApp, ref, reactive } from './vue.esm-browser.js'
    
    createApp({
        setup() {
            const number = ref(10) //ref用于存储单个基本类型的数据, 如:数字、字符串等
            number.value = 20 //使用ref创建的响应式对象, 需要通过.value属性来访问和修改其值

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

            return {
                msg: "success",
                number,
                web
            }
        }
    }).mount("#app")
</script>

4.绑定事件 v-on 简写@

html 复制代码
html
<div id="app">
    <h3>{{ msg }}</h3>
    <h3>{{ web.url }}</h3>
    <h3>{{ web.user }}</h3>
    <h3>{{ sub(100, 20) }}</h3>

    <!-- 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)">
</div>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'
    
    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")

</script>

5.显示和隐藏 v-show

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

    <button @click="toggle">点击切换显示状态</button>
</div>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'
    
    createApp({
        setup() {
            const web = reactive({
                show: true
            })

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

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

</script>

6.条件渲染 v-if

html 复制代码
html
<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>
js
<script type="module">
    /*
        v-show 通过 css display属性 来控制元素的显示或隐藏
        v-if 用于对元素进行条件渲染. 当条件为 true 时, 渲染该元素, 为 false 时, 则不渲染

        v-show 适用于频繁切换元素的显示状态, 因为只改变 display 属性, 不需要重新渲染整个组件
        v-if 适用于较少改变的场景, 因为频繁从 dom 中删除或添加元素, 会导致性能下降
    */
    import { createApp, reactive } from './vue.esm-browser.js'

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

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

            return {
                web,
                toggle
            }
        }
    }).mount("#app")
</script>

7.动态属性绑定 v-bind 简写:

html 复制代码
html
<div id="app">
    <!-- :value -->
    <h3>value="dengruicode.com"</h3>
    <input type="text" value="dengruicode.com">

    <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>

    <h3>:class="{textColor:web.fontStatus}"</h3>
    <b :class="{textColor:web.fontStatus}">dengruicode.com</b>
</div>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'

    createApp({
        setup() {
            const web = reactive({
                url: "www.dengruicode.com",
                img: "windows.jpg",
                fontStatus: true
            })

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

8.遍历数组或对象 v-for

html 复制代码
html
<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>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'

    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")
</script>

9.双向数据绑定 v-model

html 复制代码
html
<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>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'

    createApp({
        setup() {
            const data = reactive({
                text: "dengruicode.com", //文本框
                radio: "", //单选框
                checkbox: [], //复选框
                remember: false, //单个复选框-记住密码
                select: "" //下拉框
            })

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

10.v-model修饰符

html 复制代码
html
<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>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'

    createApp({
        setup() {
            const data = reactive({
                text: "dengruicode.com", //文本框
                radio: "", //单选框
                checkbox: [], //复选框
                remember: false, //单个复选框-记住密码
                select: "" //下拉框
            })

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

11.渲染数据 v-text 和 v-html

html 复制代码
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>
js
<script type="module">
    import { createApp, reactive } from './vue.esm-browser.js'

    createApp({
        setup() {
            const web = reactive({
                title: "邓瑞编程",
                url:"<i style='color:blue;'>www.dengruicode.com</i>"
            })

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

12.计算属性 computed

html 复制代码
html
<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>
js
<script type="module">
    import { createApp, reactive, 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")
</script>

13.侦听器 watch

html 复制代码
html
<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>
js
<script type="module">
    import { createApp, ref, reactive, 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")
</script>

14.自动侦听器 watchEffect

html 复制代码
html
<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>
js
<script type="module">
    /*
        watch需要显式指定要监听的属性, 并且只有当监听的属性发生变化时才会执行
        若需要更精细地控制或需要获取到原值, 需要使用watch
    */
    import { createApp, ref, reactive, 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")
</script>

Vue3快速入门2-案例篇

2.图片轮播案例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <div id="app">
        <h3>{{ number }}</h3>

        <!-- <img src="/images/1.jpg" style="width: 300px;"> -->
        <img :src=`/images/${number}.jpg` style="width: 300px;"> <hr>

        <button @click="prev">上一张</button>
        <button @click="next">下一张</button>

        <ul>
            <li v-for="(value, index) in 4">
                <a href="#" @click="jump(value)">{{ value }}</a>
            </li>
        </ul>
    </div>

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

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

                //上一张
                const prev = () => {
                    number.value--

                    if (number.value == 0) {
                        number.value = 4
                    }
                }

                //下一张
                const next = () => {
                    number.value++

                    if (number.value == 5) {
                        number.value = 1
                    }
                }

                //跳转
                const jump = (value) => {
                    number.value = value
                }

                return {
                    number,
                    prev,
                    next,
                    jump
                }
            }
        }).mount("#app")
    </script>
</body>

</html>

3.记事本案例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <div id="app">
        <input type="text" v-model="data.content">

        <button @click="add">添加</button> <hr>

        <ul>
            <li v-for="(value, index) in data.list">
                {{ value }} <button @click="del(index)">删除</button>
            </li>
        </ul>

        记录数 {{ data.list.length }} <br>

        <button @click="clear">清空</button>
    </div>

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

        createApp({
            setup() {
                const data = reactive({
                    content: "",
                    list: ["邓瑞编程", "dengruicode.com"],
                })

                //添加
                const add = () => {
                    if (data.content == "") {
                        alert("请填写内容")
                        return
                    }

                    data.list.push(data.content) //push 向数组末尾添加一个或多个元素
                    data.content = "" //清空文本框
                }

                //删除
                const del = (index) => {
                    data.list.splice(index, 1) //splice(要删除元素的索引位置, 要删除的元素数量)
                }

                //清空
                const clear = () => {
                    data.list = []
                }

                return {
                    data,
                    add,
                    del,
                    clear
                }
            }
        }).mount("#app")
    </script>
</body>

</html>

4.购物车案例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        table {
            width: 600px;
            color: #8f8e8e;
            text-align: center;
            border-collapse: collapse;
        }

        table thead {
            background: #F5F5F5;
        }

        table tr {
            height: 30px;
            line-height: 30px;
            border: 1px solid #ececec;
        }
    </style>
</head>

<body>
    <div id="app">
        <table>
            <thead>
                <tr>
                    <td><input type="checkbox" v-model="data.selected" @change="selectAll" /></td>
                    <td>商品</td>
                    <td>单价</td>
                    <td>库存</td>
                    <td colspan="2">操作</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(value, index) in data.list">
                    <td>
                        <input type="checkbox" v-model="data.checkboxList" :value="value" @change="checkSelect" />
                    </td>
                    <td>{{ value.name }}</td>
                    <td>{{ value.price }}</td>
                    <td>{{ value.stock }}</td>
                    <td>
                        <button @click="sub(value)">-</button>
                        {{ value.number }}
                        <button @click="add(value)">+</button>
                    </td>
                    <td><button @click="del(index,value.id)">删除</button></td>
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <td>总价 {{ totalPrice() }}</td>
                </tr>
            </tfoot>
        </table>
    </div>

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

        createApp({
            setup() {
                const data = reactive({
                    selected: false,
                    checkboxList: [],
                    list: [{
                        id: 1,
                        name: "铅笔",
                        price: 10,
                        number: 1,
                        stock: 3
                    },
                    {
                        id: 2,
                        name: "鼠标",
                        price: 20,
                        number: 2,
                        stock: 5
                    },
                    {
                        id: 3,
                        name: "键盘",
                        price: 30,
                        number: 1,
                        stock: 6
                    }],
                })

                //减
                const sub = (value) => {
                    value.number--

                    if (value.number <= 1) {
                        value.number = 1
                    }
                }

                //加
                const add = (value) => {
                    value.number++

                    if (value.number >= value.stock) {
                        value.number = value.stock
                    }
                }

                //删除
                const del = (index, id) => {
                    data.list.splice(index, 1) //splice(要删除元素的索引位置, 要删除的元素数量)

                    //filter 筛选符合条件的元素, 返回一个新的数组
                    let newArr = data.checkboxList.filter((value, index) => {
                        return value.id != id
                    })
                    data.checkboxList = newArr

                    checkSelect() //检查勾选状态
                }

                //总价
                const totalPrice = () => {
                    let total = 0
                    for (let i = 0; i < data.checkboxList.length; i++) {
                        total += data.checkboxList[i].price * data.checkboxList[i].number
                    }

                    return total
                }

                //全选/反选
                const selectAll = () => {
                    if (data.selected) { //true
                        data.checkboxList = data.list
                    } else { //false
                        data.checkboxList = []
                    }
                }

                //检查勾选状态
                const checkSelect = () => {
                    if (data.checkboxList.length != data.list.length || data.list.length == 0) {
                        data.selected = false
                    } else {
                        data.selected = true
                    }
                }

                return {
                    data,
                    sub,
                    add,
                    del,
                    totalPrice,
                    selectAll,
                    checkSelect
                }
            }
        }).mount("#app")
    </script>
</body>

</html>

5.购物车优化案例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        table {
            width: 600px;
            color: #8f8e8e;
            text-align: center;
            border-collapse: collapse;
        }

        table thead {
            background: #F5F5F5;
        }

        table tr {
            height: 30px;
            line-height: 30px;
            border: 1px solid #ececec;
        }
    </style>
</head>

<body>
    <div id="app">
        <table>
            <thead>
                <tr>
                    <!-- <td><input type="checkbox" v-model="data.selected" @change="selectAll" /></td> -->
                    <td><input type="checkbox" v-model="data.selected" /></td>
                    <td>商品</td>
                    <td>单价</td>
                    <td>库存</td>
                    <td colspan="2">操作</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(value, index) in data.list">
                    <!-- 
                    <td><input type="checkbox" v-model="data.checkboxList" :value="value" @change="checkSelect" /></td> 
                    -->
                    <td><input type="checkbox" v-model="data.checkboxList" :value="value" /></td>
                    <td>{{ value.name }}</td>
                    <td>{{ value.price }}</td>
                    <td>{{ value.stock }}</td>
                    <td>
                        <button @click="sub(value)">-</button>
                        {{ value.number }}
                        <button @click="add(value)">+</button>
                    </td>
                    <td><button @click="del(index,value.id)">删除</button></td>
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <!-- <td>总价 {{ totalPrice() }}</td> -->
                    <td>总价 {{ totalPrice }}</td>
                </tr>
            </tfoot>
        </table>
    </div>

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

        createApp({
            setup() {
                const data = reactive({
                    selected: false,
                    checkboxList: [],
                    list: [{
                        id: 1,
                        name: "铅笔",
                        price: 10,
                        number: 1,
                        stock: 3
                    },
                    {
                        id: 2,
                        name: "鼠标",
                        price: 20,
                        number: 2,
                        stock: 5
                    },
                    {
                        id: 3,
                        name: "键盘",
                        price: 30,
                        number: 1,
                        stock: 6
                    }],
                })

                //减
                const sub = (value) => {
                    value.number--

                    if (value.number <= 1) {
                        value.number = 1
                    }
                }

                //加
                const add = (value) => {
                    value.number++

                    if (value.number >= value.stock) {
                        value.number = value.stock
                    }
                }

                //删除
                const del = (index, id) => {
                    data.list.splice(index, 1) //splice(要删除元素的索引位置, 要删除的元素数量)

                    //filter 筛选符合条件的元素, 返回一个新的数组
                    let newArr = data.checkboxList.filter((value, index) => {
                        return value.id != id
                    })
                    data.checkboxList = newArr

                    //checkSelect() //检查勾选状态
                }

                /*
                //总价
                const totalPrice = () => {
                    let total = 0
                    for (let i = 0; i < data.checkboxList.length; i++) {
                        total += data.checkboxList[i].price * data.checkboxList[i].number
                    }

                    return total
                }
                */
                //计算属性-有缓存 [计算属性根据其依赖的响应式数据变化而重新计算]
                const totalPrice = computed(() => {
                    /*
                        reduce定义: 用于对数组中的所有元素进行迭代操作, 并将每次操作的结果累加到一个初始值上
                        reduce接收两个参数: 一个是累加器函数, 另一个是初始值
                        reduce: 将 data.checkboxList 数组中的每个 checkbox 对象的 price 和 number 属性进行相乘, 
                        并将结果累加到初始值 0 上, 最后返回累加的结果

                        total(累加器) 用于存储每次计算的结果, 初始值为 0
                        item(当前元素) 在每次迭代过程中, 当前元素的值会被传递给回调函数
                    */

                    return data.checkboxList.reduce((total, item) => total + item.price * item.number, 0)
                })

                /*
                //全选/反选
                const selectAll = () => {
                    if (data.selected) { //true
                        data.checkboxList = data.list
                    } else { //false
                        data.checkboxList = []
                    }
                }
                */
                //监听 data.selected
                let flag = true
                watch(() => data.selected, (newValue, oldValue) => {
                    //console.log("newValue:",newValue,"oldValue:",oldValue)

                    if (newValue) {
                        data.checkboxList = data.list
                    } else {
                        if (flag) {
                            data.checkboxList = []
                        }
                    }
                    //console.log(data.checkboxList)
                })                

                /*
                //检查勾选状态
                const checkSelect = () => {
                    if (data.checkboxList.length == data.list.length && data.list.length != 0) {
                        data.selected = true
                    } else {
                        data.selected = false
                    }
                }
                */
                //监听 data.checkboxList
                watch(() => data.checkboxList, (newValue, oldValue) => {
                    console.log("newValue:", newValue, "oldValue:", oldValue)
                    console.log(newValue.length)

                    if (newValue.length == data.list.length && data.list.length != 0) {
                        data.selected = true
                        flag = true
                    } else {
                        data.selected = false
                        flag = false
                    }
                })                

                return {
                    data,
                    sub,
                    add,
                    del,
                    totalPrice,
                    //selectAll,
                    //checkSelect
                }
            }
        }).mount("#app")
    </script>
</body>

</html>

6.使用Axios实现文章搜索案例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/axios.min.js"></script>
</head>

<body>
    <div id="app">
        <select v-model="data.type">
            <option value="0">请选择</option>
            <option value="1">ID</option>
            <option value="2">标题</option>
        </select>

        <input type="text" v-model="data.content">
        <button @click="search">搜索</button>

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

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

        createApp({
            setup() {
                const data = reactive({
                    type: "0", //搜索类型
                    content: "", //搜索内容
                    list: [],
                })

                //搜索
                const search = () => {
                    //console.log(data.content)
                    data.list = [] //清空

                    if (data.type == "1") {
                        let id = data.content //参数

                        //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)
                        })
                    } else if (data.type == "2") {
                        //参数
                        let param  = { 
                            title: data.content
                        }

                        //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)
                        })
                    }
                }

                return {
                    data,
                    search
                }
            }
        }).mount("#app")
    </script>
</body>

</html>

Vue3快速入门3-组件篇

1.基于Vite创建Vue3项目

html 复制代码
       官网
               https://cn.vitejs.dev
      基于Vite创建Vue3项目
               npm create vite@latest
               Ok to proceed? (y) >> y
               Project name: >> demo
               Select a framework: >> Vue
               Select a variant: >> JavaScript
               Done. Now run:
                       cd demo
                       npm install
                       npm run dev
               Local: http://localhost:5173
       删除文件
               src\style.css
               src\components\HelloWorld.vue
       删除代码
               main.js
                       import './style.css'
       修改代码
               src\App.vue
                       <script setup>
                       </script>
                       <template>
                               dengruicode.com
                       </template>
                       <style scoped>
                       </style>

2.Vue3好用的VsCode插件

html 复制代码
     Vue Language Features (Volar)
       TypeScript Vue Plugin (Volar)
       Vue VSCode Snippets
       别名路径跳转
       注
       Vue VSCode Snippets自定义模板
       C:\Users\David\.vscode\extensions\sdras.vue-vscode-snippets-3.1.1\snippets
       模板
               vbase-3-setup
               vbase-3-ts-setup
       重启vscode

3.导入组件

html 复制代码
<script setup>
  //导入子组件
  //App.vue是父组件,因为它包含了header.vue和footer.vue两个子组件
  import Header from "./components/header.vue"
  import Footer from "./components/footer.vue"
</script>

<template>
  <Header/>

  dengruicode.com
  
  <Footer/>
</template>

<style scoped>

</style>

4.父传子 defineProps

html 复制代码
App.vue

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

  //导入子组件
  //App.vue是父组件,因为它包含了header.vue和footer.vue两个子组件
  import Header from "./components/header.vue"
  import Footer from "./components/footer.vue"

  /*
  const propsWeb = {
    user: 10,
    ip: '127.0.0.1'
  }
  */
  //响应式数据
  const propsWeb = reactive({
    user: 10,
    ip: '127.0.0.1'
  })

  //添加用户
  const userAdd = () => {
    propsWeb.user++
    console.log(propsWeb.user)
  }
</script>

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

  dengruicode.com

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

  <!-- 父传子 - 方式2 -->
  <!-- <Footer v-bind="propsWeb" /> -->
  <Footer :="propsWeb" />
</template>

<style scoped></style>


header.vue

<script setup>
    //子组件

    //接收方式1 - 数组
    /*
        defineProps是Vue3的编译时宏函数,
        用于接收父组件向子组件传递的属性(props)

        注
        当使用Vue编译器编译包含defineProps的组件时,
        编译器会将这些宏替换为相应的运行时代码
    */
    const props = defineProps(["propsName","propsUrl"])
    console.log(props)
</script>

<template>
    <h3>Header</h3>
</template>

<style scoped>

</style>


footer.vue

<script setup>
    //子组件

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

    console.log(props)
</script>

<template>
    <h3>Footer</h3>
    user: {{ props.user }}
</template>

<style scoped>

</style>

5.子传父 defineEmits

html 复制代码
App.vue

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

  //导入子组件
  import Header from "./components/header.vue"

  //响应式数据
  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>

<style scoped></style>


header.vue

<script setup>
    //子组件

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

<template>
    <h3>Header</h3>

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

<style scoped>

</style>

6.跨组件通信-依赖注入

html 复制代码
App.vue

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

  //导入子组件
  import Header from "./components/header.vue"

  //provide用于父组件将 数据 提供给所有子组件
  /*
    若使用了provide和inject来进行数据传递,
    则一般不需要再使用defineProps
  */
  provide("provideWeb",{name:"邓瑞",url:"www.dengruicode.com"})

  //传递响应式数据
  const user = ref(0)
  provide("provideUser",user)

  //添加用户
  const userAdd = () => {
    user.value++
  }
  //用于父组件将 函数 提供给所有子组件
  provide("provideFuncUserAdd",userAdd)
</script>

<template>
  <h3>App.vue-Top组件</h3>

  {{ user }}

  <!-- 子组件 -->
  <Header/>
</template>

<style scoped></style>


header.vue

<script setup>
    import { provide, inject } from 'vue'

    //导入子组件
    import Nav from "./nav.vue"

    //子组件通过inject注入父组件提供的 响应式数据
    const user = inject("provideUser")
    console.log("provideUser:",user.value)

    //provide用于父组件将 数据 提供给所有子组件
    provide("provideUrl","dengruicode.com")
</script>

<template>
    <h3>header.vue-Middle组件</h3>

    <!-- 子组件 -->
    <Nav/>
</template>

<style scoped>

</style>


nav.vue

<script setup>
    //子组件
    import { inject } from 'vue'

    //子组件通过inject注入父组件提供的 数据
    const web = inject("provideWeb")
    console.log("provideWeb:",web)

    const url = inject("provideUrl")
    console.log("provideUrl:",url)

    //子组件通过inject注入父组件提供的 函数
    const funcUserAdd = inject("provideFuncUserAdd")
    console.log("provideFuncUserAdd:",funcUserAdd)
</script>

<template>
    <h3>nav.vue-Bottom组件</h3>

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

<style scoped>

</style>

7.匿名插槽和具名插槽

html 复制代码
插槽(slot)

       是指可以在父组件内自定义模板片段,

       在子组件中可以将定义的模板片段插入到子组件的特定位置



App.vue

<script setup>
  //导入子组件
  import Header from "./components/header.vue"
  import Footer from "./components/footer.vue"
</script>

<template>
  <h3>App.vue</h3>

  <!-- <Header/> -->
  <!-- 匿名插槽 -->
  <Header>
    <a href="http://dengruicode.com">邓瑞编程</a>
  </Header>

  <!-- 具名插槽 -->
  <Footer>
    <template v-slot:url>
      <a href="http://www.dengruicode.com">网址</a>
    </template>

    <!-- v-slot:user 简写 #user -->
    <template #user>
      1000
    </template>
  </Footer>

</template>

<style scoped>

</style>


header.vue

<script setup>
    
</script>

<template>
    <h3>header.vue - 子组件</h3>

    <!-- 匿名插槽 -->
    <slot/>
</template>

<style scoped>

</style>


footer.vue

<script setup>
    
</script>

<template>
    <h3>footer.vue - 子组件</h3>

    <!-- 具名插槽 -->
    <slot name="url" />
    <slot name="user" />
</template>

<style scoped>

</style>

8.作用域插槽

html 复制代码
作用域插槽

       子组件向父组件传递数据,并在父组件定义的模板中渲染



App.vue

<script setup>
  //导入子组件
  import Header from "./components/header.vue"
  import Footer from "./components/footer.vue"
</script>

<template>
  <h3>App.vue</h3>

  <!-- <Header/> -->
  <!-- 匿名插槽 -->
  <Header>
    <a href="http://dengruicode.com">邓瑞编程</a>
  </Header>

  <!-- 具名插槽 -->
  <Footer>
    <template v-slot:url>
      <a href="http://www.dengruicode.com">网址</a>
    </template>

    <!--
      v-slot:user 简写 #user

      作用域插槽
      子组件将url和title数据传递给 name="user" 的插槽,
      父组件通过 #user="data" 来接收这些数据

      <template #user="data">
        1000 {{ data.url }} {{ data.title }}
      </template>
    -->
    <!-- 解构 -->
    <template #user="{url,title}">
      1000 {{ url }} {{ title }}
    </template>
  </Footer>

</template>

<style scoped>

</style>


header.vue

<script setup>
    
</script>

<template>
    <h3>header.vue - 子组件</h3>

    <!-- 匿名插槽 -->
    <slot/>
</template>

<style scoped>

</style>


footer.vue

<script setup>
    
</script>

<template>
    <h3>footer.vue - 子组件</h3>

    <!-- 具名插槽 -->
    <slot name="url" />
    <slot name="user" url="dengruicode.com" title="邓瑞编程" />
</template>

<style scoped>

</style>

9.生命周期函数

html 复制代码
生命周期函数

       是组件实例从创建到销毁过程中不同时间点自动调用的函数



挂载阶段

       onBeforeMount

               在组件实例即将被挂载到DOM树之前调用

               此时模板还未编译或渲染到DOM,通常用于执行初始化操作,

               如:获取异步数据、设置初始属性值等

       onMounted

               在组件成功挂载到DOM并完成首次渲染后调用

               此时可以访问和操作DOM元素,

               并执行与页面交互相关的逻辑

更新阶段

       onBeforeUpdate (由于响应式数据变化)

               在组件更新之前即将重新渲染时调用

               可以根据新的参数判断是否需要进行特殊处理,

               甚至可以选择阻止此次更新过程

       onUpdated

               在组件完成更新并重新渲染后调用

               可以基于新的渲染结果处理更新后的数据

卸载阶段

       onBeforeUnmount

               在组件从DOM中销毁之前调用

               用于释放资源,如:清理计时器、解绑事件监听器等

       onUnmounted

               在组件已经从DOM中移除并销毁后调用

               确保组件所占用的所有资源都被正确释放

错误处理

       onErrorCaptured

               在捕获到组件中的错误时调用

               用于处理错误,如:记录错误日志等



注

组件挂载的过程

模板编译

       将组件的模板转换为JS代码

渲染

       在模板编译后生成的JS代码渲染到页面上,

       生成虚拟DOM

挂载

       在渲染完成后将虚拟DOM挂载到真实的DOM树上,

       使其在页面上显示出来



<script setup>
  import { onMounted, onUpdated, ref } from 'vue'

  //在组件成功挂载到DOM并完成首次渲染后调用
  onMounted(() => {
    console.log("onMounted")
  })

  //在组件更新之后调用
  onUpdated(() => {
    console.log("onUpdated:",user.value)
  })

  const user = ref(0)
  console.log("user:",user.value)
</script>

<template>
  <h3>App.vue</h3>

  {{ user }}

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

<style scoped>

</style>

10.toRef和toRefs

html 复制代码
<script setup>
  import { reactive, toRef, toRefs } from 'vue'

  /*
  let {name,url} = reactive({
    name:"邓瑞编程",
    url:"dengruicode.com"
  })
  */
  let web = reactive({
    name:"邓瑞编程",
    url:"dengruicode.com"
  })

  //toRefs将一个响应式对象的所有属性转换为ref对象
  //let {name,url} = toRefs(web)

  //toRef将一个响应式对象的某个属性转换为ref变量
  let url = toRef(web, "url")

  const setUrl = () => {
    console.log(url)
    url.value = "www.dengruicode.com"
  }
</script>

<template>
  {{ url }}

  <button @click="setUrl">设置网址</button>
</template>

<style scoped>

</style>

Vue3 快速入门4-Pinia

1.Pinia 简介

html 复制代码
  Pinia是一个轻量级的状态管理库
       Pinia官网
       https://pinia.vuejs.org/zh
       状态管理库是用于管理应用程序全局状态的工具
       以登录为例:
               使用Pinia创建一个userStore来集中管理用户的登录状态和过期时间
               当用户登录成功时:
                       设置userStore中用户的登录状态为已登录,并设置过期时间
               当用户退出登录时:
                       修改userStore中用户的登录状态为未登录,并删除过期时间
       Pinia 和 组件通信 的区别
       虽然Vue提供的父传子、子传父以及跨组件通信也可以用于状态共享,
       但在大型项目中,随着组件数量的增加,会导致以下问题:
       1.组件之间传递大量的props,会使项目变得非常繁琐和难以维护
       2.非父子组件间过度依赖provide/inject,使状态散落在各个组件之间

       Pinia 可以解决以下问题:
       1.全局状态管理
               所有组件都可以访问和修改状态,而不用在每个组件内部进行状态管理
       2.简化组件之间的通信
               避免在组件之间传递大量的props
       3.状态持久化
               可以将应用程序的状态保存到本地存储中,
               在应用程序重启后会保留状态,对于登录等场景非常有用
       总的来说,Pinia可以处理大型项目中复杂的状态管理需求,
       而父传子、子传父以及跨组件通信,可以解决一些简单的状态传递问题,
       更适合小型项目
       Pinia 和 localStorage 的区别
       localStorage
               LocalStorage只能存储字符串类型的数据
               LocalStorage有大小限制,通常为5MB左右
       Pinia
               Pinia可以存储任何类型的数据,包括对象、数组等
               Pinia没有大小限制,可以存储大量的数据
       总的来说,对于复杂的状态管理需求,使用Pinia是更好的选择,
       而对于简单的状态管理需求,使用localStorage是更简单的解决方案

2.安装 Pinia 以及定义和使用 Store

html 复制代码
安装Pinia

       npm install pinia



main.js

import { createApp } from 'vue'

//导入Pinia的createPinia方法,用于创建Pinia实例(状态管理库)
import { createPinia } from 'pinia'

import App from './App.vue'

//创建一个Pinia实例,用于在应用中集中管理状态(store)
const pinia = createPinia()

//createApp(App).mount('#app')
const app = createApp(App)
app.use(pinia) //将Pinia实例注册到Vue应用中
app.mount('#app')


web.js

import { reactive, ref } from 'vue'
import { defineStore } from 'pinia'

/*
  定义一个基于 Pinia 的 Store
  第1个参数 web 是 useWebStore 在应用中的唯一标识符(ID)
  第2个参数是 Setup函数 或 Option对象
*/
export const useWebStore = defineStore('web', () => {
  //定义一个响应式对象,存储网站信息
  const web = reactive({
    title: "邓瑞编程",
    url: "dengruicode.com"
  })

  //定义一个响应式引用,存储用户数
  const users = ref(1000)
  
  //定义方法
  const userAdd = () => {
    users.value++
  }

  return {
    web,
    users,
    userAdd
  }
})


App.vue

<script setup>
    import { useWebStore } from './stores/web.js'

    const webStore = useWebStore()
    
    console.log("webStore.web:",webStore.web)
    console.log("webStore.users:",webStore.users)
</script>

<template>
    {{ webStore.web.url }}

    {{ webStore.users }}

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

<style scoped>

</style>

3.Pinia 持久化存储插件

html 复制代码
官网
https://prazdevs.github.io/pinia-plugin-persistedstate/zh
安装
npm i pinia-plugin-persistedstate
注
pinia持久化插件也是存储到localStorage中,
为什么不直接使用localStorage?
自动状态同步
       持久化插件自动将Pinia的状态存储到localStorage中,
       无需手动处理状态的读取和写入
易用性
       无需手动处理localStorage的键值对存储、数据转换等繁琐过程
与Vue组件状态紧密集成
       持久化插件与Vue组件的响应式数据完美结合
       当状态改变时,依赖这些状态的组件会自动更新视图
       与仅仅从localStorage中读取静态数据相比更加灵活和强大

main.js

import { createApp } from 'vue'

//导入Pinia的createPinia方法,用于创建Pinia实例(状态管理库)
import { createPinia } from 'pinia'

//从 pinia-plugin-persistedstate 模块中导入 piniaPluginPersistedstate
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

import App from './App.vue'

//创建一个Pinia实例,用于在应用中集中管理状态(store)
const pinia = createPinia()

//将插件添加到 pinia 实例上
pinia.use(piniaPluginPersistedstate)

//createApp(App).mount('#app')
const app = createApp(App)
app.use(pinia) //将Pinia实例注册到Vue应用中
app.mount('#app')


web.js

import { reactive, ref } from 'vue'
import { defineStore } from 'pinia'

/*
  定义一个基于 Pinia 的 Store
  第1个参数 web 是 useWebStore 在应用中的唯一标识符(ID)
  第2个参数是 Setup函数 或 Option对象
*/
export const useWebStore = defineStore('web', () => {
  //定义一个响应式对象,存储网站信息
  const web = reactive({
    title: "邓瑞编程",
    url: "dengruicode.com"
  })

  //定义一个响应式引用,存储用户数
  const users = ref(1000)
  
  //定义方法
  const userAdd = () => {
    users.value++
  }

  return {
    web,
    users,
    userAdd
  }
},
{
  //持久化存储到 localStorage 中
  persist: true
})
相关推荐
学前端的小朱13 小时前
Echarts实现大屏可视化
websocket·echarts·nodejs·vue3·vite·koa·cors
&活在当下&6 天前
element plus的table组件,点击table的数据是,会出现一个黑色边框
vue3·element plus
&活在当下&6 天前
Element plus 下拉框组件选中一个选项后显示的是 value 而不是 label
前端·javascript·vue3·element plus
瑶琴AI前端7 天前
从0到1实现vue3+vite++elementuiPlus+ts的后台管理系统(一)
前端·typescript·vue3
啊·贤15 天前
初级报错:循环引用
前端·javascript·vue3·axios
代码老祖18 天前
vue3+view-ui-plus+vite+less 实现自定义iview样式
前端·ui·vue3·vite·view design
i紸定i19 天前
uniapp使用ucharts修改Y、X轴标题超出换行
微信小程序·小程序·uni-app·vue·vue3·ucharts
Serenity_Qin20 天前
vue3 + ts 使用 el-tree
前端·vue.js·typescript·vue3·element-plus
前端李易安22 天前
vue3中是如何实现双向数据绑定的
前端·javascript·vue.js·vue3
陈逸子风22 天前
(系列十三)Vue3+Echarts搭建超好看的系统面板
vue3·webapi·权限·流程·表单