Vue3、Vite、Pinia基础学习

Vue3

1、创建一个Vue3应用

<script src="vue.global.js"></script>
<body>
    <div id="app">
        {{msg}}
        <h2>{{person.title}}</h2>
        <h2>{{person.name}}</h2>
    </div>
    <script>
        // 采用解构的方式可以省略Vue.createApp和Vue.reactive前的Vue
        const{createApp,reactive}=Vue;

        Vue.createApp({
            // setup选项用于设置响应式数据和方法
            setup(){
                const person=Vue.reactive({
                    title:"Vue学习",
                    name:"sss",
                })
                return{
                    msg:"success",
                    person
                }
            }
        }).mount("#app")    //mount用于挂载到id为app的标签上
    </script>
</body>

2、Vue3模块化开发

<body>
    <div id="app">
        {{msg}}
        <h2>{{person.title}}</h2>
        <h2>{{person.name}}</h2>
    </div>
    <!-- 模块化开发 -->
    <script type="module">
        // 采用解构的方式可以省略Vue.createApp和Vue.reactive前的Vue
        import {createApp,reactive} from './vue.esm-browser.js'

        createApp({
            // setup选项用于设置响应式数据和方法
            setup(){
                const person=reactive({
                    title:"Vue学习",
                    name:"sss",
                })
                return{
                    msg:"success",
                    person
                }
            }
        }).mount("#app")    //mount用于挂载到id为app的标签上
    </script>
</body>

3、ref和reactive的区别

<body>
    <div id="app">
        {{msg}}
        <h2>{{person.title}}</h2>
        <h2>{{person.name}}</h2>
    </div>
    <script type="module">
        import {createApp,reactive} from './vue.esm-browser.js'

        createApp({
            setup(){
                const number=ref(10);//ref用于存储单个基本类型的数据,如:数字、字符串、数组等
                const arr=ref([1,2,3,4]);

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

                // reactive用于存储复杂数据类型,如对象或数组等
                const person=reactive({
                    title:"Vue学习",
                    name:"sss",
                })
                person.name="scu";//使用reactive创建的响应式对象,可以直接通过属性名来访问和修改值

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

4、绑定事件v-on

<body>
    <div id="app">
        {{msg}}
        <h2>{{person.title}}</h2>
        <h2>{{person.name}}</h2>

        <!-- 绑定事件 -->
        <button v-on:click="edit">修改</button>
        <br>
        <!-- v-on简写形式 -->
        <button @click="edit">修改(简写形式)</button>
    </div>
    <script type="module">
        import {createApp,reactive} from './vue.esm-browser.js'

        createApp({
            setup(){
                const person=reactive({
                    title:"Vue学习",
                    name:"sss",
                })
                
                //构建函数
                const edit=()=>{
                    person.name="hjklakhs";
                }

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

5、按键修饰符

按键修饰符:

  • enter回车
  • space空格
  • tab键
  • keyup是在用户松开按键时才触发
  • keydown是在用户按下按键时立即触发
<body>
    <div id="app">
        {{msg}}
        <h2>{{person.title}}</h2>
        <h2>{{person.name}}</h2>
        <h2>{{person.user}}</h2>

        <!-- 按键修饰符 -->
        回车<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(30,40)"><br>
        w   <input type="text" @keyup.w="add(32,43)"><br>

        <!-- 组合快捷键 -->
        ctrl + Enter <input type="text" @keyup.ctrl.enter="add(34,58)"><br>
        ctrl + A     <input type="text" @keyup.ctrl.a="add(22,30)"><br>

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

        createApp({
            setup(){
                const person=reactive({
                    title:"Vue学习",
                    name:"sss",
                    user:0
                })

                const add=(x,y)=>{
                    person.user+=x+y;
                }

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

6、显示和隐藏v-show

  • v-show通过css display属性来控制元素的显示或隐藏
  • v-show适用于频繁切换元素的显示状态,因为只改变display属性,不需要重新渲染整个组件
<body>
    <div id="app">
        {{web.show}}
        <hr>
        <!-- 显示和隐藏v-show -->
        <p v-show="web.show">西游记 黑神话悟空</p>

        <button @click="toggle()">切换状态</button>
    </div>
    <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>
</body>

7、条件渲染v-if

  • v-if用于对元素进行条件渲染,当条件为true时,渲染该元素,为false时,则不渲染
  • v-if适用于较少改变的场景,因为频繁从dom中删除或添加元素,会导致性能下降
<body>
    <div id="app">
        {{web.show}}
        <hr>
        <!-- v-if条件渲染 -->
        <p v-if="web.show">西游记 黑神话悟空</p>

        <button @click="toggle()">切换状态</button>

        <!-- v-if-else -->
        <p v-if="web.user<1000">新网站</p>
        <p v-else-if="web.user>=1000&&web.user<=10000">优秀网站</p>
        <p v-else="web.user">资深网站</p>
    </div>
    <script type="module">
        import{createApp,reactive} from './vue.esm-browser.js'
        createApp({
            setup(){
                const web=reactive({
                    show:true,
                    user:10005
                })
                const toggle=()=>{
                    web.show=!web.show;
                }
                return{
                    web,
                    toggle
                }
            }
        }).mount("#app")
    </script>
</body>

8、动态属性绑定v-bind

  • 单向数据绑定:当数据发生改变时,视图会自动更新,但用户手动更改input的值,数据不会自动更新。
  • 单向数据绑定<input type="text"  :value="data.txt">
    <style>
        .textColor{
            color: rebeccapurple;
        }
    </style>

<body>
    <div id="app">
        <!-- 动态属性绑定v-bind -->
        <!-- :value -->
        <h3>value="www.baidu.com"</h3>
        <!-- <input type="text" value="www.baidu.com"> -->
        <input type="text" v-bind:value="web.url">
        <!-- 简写 -->
        <input type="text" :value="web.url">

        <!-- :src -->
        <h3>src="dhimg1.png"</h3>
        <!-- <img src="../resource/image/dhimg1.png" alt=""> -->
        <img :src="web.img" alt="">

        <!-- :class -->
        <h3>class="textColor"</h3>
        <!-- <b class="textColor">西游记</b> -->
        <b :class="{textColor:web.Status}">西游记</b>
    </div>
    <script type="module">
        import{createApp,reactive} from './vue.esm-browser.js'
        createApp({
            setup(){
                const web=reactive({
                    url:"www.baidu.com",
                    img:"../resource/image/dhimg1.png",
                    Status:true
                })
                return{
                    web
                }
            }
        }).mount("#app")
    </script>
</body>

9、遍历数组或对象v-for

<body>
    <div id="app">
        <!-- 遍历数组或对象v-for -->
        <ul>
            <li v-for="(value,index) in web.number">
                {{index}}:{{value}}
            </li>
        </ul>
        <ul>
            <li v-for="(value,key,index) in web.user">
                {{index}}:{{key}}:{{value}}
            </li>
        </ul>
        <ul>
            <template v-for="(value,key,index) in web.user">
                <li v-if="index==1">
                    {{index}}:{{key}}:{{value}}
                </li>
            </template>
        </ul>
        <ul>
            <li v-for="(value,index) in web.teacher" :title="value.name" :key="value.id">
                {{index}}:{{value.id}}:{{value.name}}:{{value.web}}
            </li>
        </ul>
    </div>
    <script type="module">
        import{createApp,reactive} from './vue.esm-browser.js'
        createApp({
            setup(){
                const web=reactive({
                    number:["十","十一","十二"],//数组
                    user:{
                        name:"sss",
                        age:20
                    },//对象
                    teacher:[
                        {id:100,name:"lucy",web:"baidu.com"},
                        {id:101,name:"jucy",web:"bai.com"}
                    ]//包含两个对象的数组
                })
                return{
                    web
                }
            }
        }).mount("#app")
    </script>
</body>

10、双向数据绑定v-model

  • 双向数据绑定:当数据发生改变时,视图会自动更新,用户手动更改input的值,数据也会自动更新。对于<input type="text">,v-model绑定的是input元素的value属性。
  • 双向数据绑定<input type="text"  v-model=“data.txt">
<body>
    <div id="app">
        <!-- 双向数据绑定v-model -->
        <h3>文本框{{data.text}}</h3>
        <h3>单选框{{data.radio}}</h3>
        <h3>复选框{{data.checkbox}}</h3>
        <h3>记住密码{{data.remember}}</h3>
        <h3>下拉框{{data.select}}</h3>
        <!-- 单向数据绑定 -->
        <input type="text" :value="data.text">
        <br>
        <!-- 双向数据绑定 -->
        <input type="text" v-model="data.text">
        <br>
        <!-- 单选框 -->
        <input type="radio" v-model="data.radio" value="1">写作
        <input type="radio" v-model="data.radio" value="2">画画
        <br>
        <!-- 复选框 -->
        <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">运动
        <br>
        <!-- 单个复选框 -->
        <input type="checkbox" v-model="data.remember">记住密码
        <br>
        <!-- 下拉框 -->
        <select v-model="data.select">
            <option value="">请选择</option>
            <option value="A">写作</option>
            <option value="B">画画</option>
            <option value="C">运动</option>
        </select>
    </div>
    <script type="module">
        import{createApp,reactive} from './vue.esm-browser.js'
        createApp({
            setup(){
                const data=reactive({
                    text:"baidu.com",//文本框
                    radio:"",//单选框
                    checkbox:[],//复选框
                    remember:false,//单个复选框 记住密码
                    select:""//下拉框
                })
                return{
                    data
                }
            }
        }).mount("#app")
    </script>
</body>

11、v-model修饰符

  • 在失去焦点或按下回车键之后渲染用 v-model.lazy
  • 输入框的值转换为数字类型用 v-model.number
  • 去除首尾空格 v-model.trim

<body>
    <div id="app">
        <h3>{{web.url}}</h3>
        <h3>{{web.user}}</h3>
        实时渲染<input type="text" v-model="web.url"><br>
        在失去焦点或按下回车键之后渲染<input type="text" v-model.lazy="web.url"><br>
        输入框的值转换为数字类型<input type="text" v-model.number="web.user"><br>
        去除首尾空格<input type="text" v-model.trim="web.url">
    </div>
    <script type="module">
        import{createApp,reactive} from './vue.esm-browser.js'
        createApp({
            setup(){
                const web=reactive({
                    url:"baidu.com",
                    user:10
                })
                return{
                    web
                }
            }
        }).mount("#app")
    </script>
</body>

12、渲染数据v-text和v-html

  • v-text将数据解析为纯文本格式
  • v-html将数据解析为html格式
<body>
    <div id="app">
        <h3>{{web.title}}</h3>
        <h3 v-text="web.title"></h3>
        <h3 v-html="web.url"></h3>
        <h3 v-text="web.url"></h3>
    </div>
    <script type="module">
        import{createApp,reactive} from './vue.esm-browser.js'
        createApp({
            setup(){
                const web=reactive({
                    url:"<i style='color:blue;'>baidu.com</i>",
                    title:"javascript"
                })
                return{
                    web
                }
            }
        }).mount("#app")
    </script>
</body>

13、计算属性computed

<body>
    <div id="app">
        <h3>{{add()}}</h3>
        <h3>{{add()}}</h3>
        <!-- sub是属性不是方法 -->
        <h3>{{sub}}</h3>
        <h3>{{sub}}</h3>
        x <input type="text" v-model.number="data.x"><br>
        y <input type="text" v-model.number="data.y">
    </div>
    <script type="module">
        // 导入computed
        import{createApp,reactive,computed} from './vue.esm-browser.js'
        createApp({
            setup(){
                const data=reactive({
                    x:10,
                    y:20
                })
                // 方法:无缓存
                const add=()=>{
                    console.log("add");//打印流程
                    return data.x+data.y;
                }
                // 计算属性-有缓存(计算属性根据其依赖的响应式数据变化而重新计算)
                const sub=computed(()=>{
                    console.log("sub");
                    return data.x-data.y;
                })
                return{
                    data,
                    add,
                    sub
                }
            }
        }).mount("#app")
    </script>
</body>

14、侦听器watch

<body>
    <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="data.year">
            <option value="">请选择</option>
            <option value="2023">2023</option>
            <option value="2024">2024</option>
            <option value="2025">2025</option>
        </select>
        月
        <select v-model="data.month">
            <option value="">请选择</option>
            <option value="10">10</option>
            <option value="11">11</option>
            <option value="12">12</option>
        </select>
    </div>
    <script type="module">
        // 导入watch
        import{createApp,reactive,ref,watch} from './vue.esm-browser.js'
        createApp({
            setup(){
                const hobby=ref("");//爱好
                const data=reactive({
                    year:"2023",
                    month:"10"
                })
                // 侦听对象hobby
                watch(hobby,(newValue,oldValue)=>{
                    console.log(newValue,oldValue);
                    if(newValue=="2"){
                        console.log("画画");
                    }
                })
                // 监听date
                watch(data,(oldValue,newValue)=>{
                    /*
                    JS中对象和数组是通过引用传递的,而不是通过值传递
                    当修改对象或数组的值时,实际上修改的是对对象或数组的引用,而不是创建一个新的对象或数组
                    所以,如果修改了对象或数组的值,那么打印出来的结果则是修改后的值
                    */
                    console.log(oldValue,newValue);
                    if(newValue.year=="2025"){
                        console.log("2025");
                    }
                })
                // 监听date中的某个属性year
                watch(()=>data.year,(newValue,oldValue)=>{
                    console.log(oldValue,newValue);
                    if(data.year=="2024"){
                        console.log("2024");
                    }
                })
                return{
                    hobby,
                    data
                }
            }
        }).mount("#app")
    </script>
</body>

15、自动侦听器watchEffect

<body>
    <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="data.year">
            <option value="">请选择</option>
            <option value="2023">2023</option>
            <option value="2024">2024</option>
            <option value="2025">2025</option>
        </select>
        月
        <select v-model="data.month">
            <option value="">请选择</option>
            <option value="10">10</option>
            <option value="11">11</option>
            <option value="12">12</option>
        </select>
    </div>
    <script type="module">
        // 导入watchEffect
        import{createApp,reactive,ref,watchEffect} from './vue.esm-browser.js'
        createApp({
            setup(){
                const hobby=ref("");//爱好
                const data=reactive({
                    year:"2023",
                    month:"10"
                })
                // 自动监听
                watchEffect(()=>{
                    console.log("监听开始");
                    if(hobby.value=="2"){
                        console.log("画画");
                    }
                    if(data.year=="2025"){
                        console.log("2025");
                    }
                    if(data.month=="10"){
                        console.log("10");
                    }
                    console.log("监听结束");
                })
                return{
                    hobby,
                    data
                }
            }
        }).mount("#app")
    </script>
</body>

16、图片轮播案例

<body>
    <div id="app">
        <h3>{{number}}</h3>
        <img :src=`../resource/image/dhimg${number}.png`  style="width: 300px;"><br>
        <button @click="next">下一张</button>
        <button @click="prev">上一张</button>
        <hr>
        <ul>
            <li v-for="value in 4">
                <a href="#" @click="jump(value)">{{value}}</a>
            </li>
        </ul>
    </div>
    <script type="module">
        import{createApp,reactive,ref} from './vue.esm-browser.js'
        createApp({
            setup(){
                const number=ref(2)
                const next=()=>{
                    number.value++;
                    if(number.value=="5"){
                        number.value=1;
                    }
                }
                const prev=()=>{
                    number.value--;
                    if(number.value=="0"){
                        number.value=5;
                    }
                }
                const jump=(value)=>{
                    number.value=value;
                }
                return{
                    number,
                    next,
                    prev,
                    jump
                }
            }
        }).mount("#app")
    </script>
</body>

17、记事本案例

<body>
    <div id="app">
        <input type="text" v-model="data.content">
        <button @click="add">添加</button>
        <ul>
            <li v-for="(value,index) in data.list">
                {{value}}
                <button @click="del(index)">删除</button>
            </li>
        </ul>
        {{data.list.length}}
        <button @click="clear">清空</button>
    </div>
    <script type="module">
        import{createApp,reactive,ref} from './vue.esm-browser.js'
        createApp({
            setup(){
                const data=reactive({
                    content:"baidu.com",
                    list:["sss","yyy"]
                })
                const add=()=>{
                    data.list.push(data.content);
                    console.log(data.list)
                }
                const del=(index)=>{
                    data.list.pop(index);
                }
                const clear=()=>{
                    data.list=[];
                }
                return{
                    data,
                    add,
                    del,
                    clear
                }
            }
        }).mount("#app")
    </script>
</body>

18、购物车案例

<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" :value="value" v-model="data.checkboxList" @change="changeSelect"></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,ref} 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 selectAll=()=>{
                    console.log(data.selected);
                    if(data.selected){
                        data.checkboxList=data.list;
                    }else{
                        data.checkboxList=[];
                    }
                }
                const changeSelect=()=>{
                    if(data.checkboxList.length==data.list.length&&data.list.length!=0){
                        data.selected=true;
                    }else{
                        data.selected=false;
                    }
                }
                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 add=(value)=>{
                    value.number++;
                    if(value.number>=value.stock){
                        value.number=value.stock;
                    }
                }
                const sub=(value)=>{
                    value.number--;
                    if(value.number<=1){
                        value.number=1;
                    }
                }
                const del=(index,id)=>{
                    data.list.splice(index,1);
                    let newArr=data.checkboxList.filter((value,index)=>{
                        return value.id!=id;
                    })
                    data.checkboxList=newArr;
                    changeSelect();
                }
                return{
                    data,
                    selectAll,
                    changeSelect,
                    totalPrice,
                    add,
                    sub,
                    del
                }
            }
        }).mount("#app")
    </script>
</body>

19、购物车案例优化

<body>
    <div id="app">
        <table>
            <thead>
                <tr>
                    <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" :value="value" v-model="data.checkboxList" @change="changeSelect"></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,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
                    }],
                })
                let flag=true;
                watch(()=>data.selected,(newValue,oldValue)=>{
                    if(newValue){
                        data.checkboxList=data.list;
                    }else{
                        if(flag){
                            data.checkboxList=[];
                        }
                    }
                })
                watch(()=>data.checkboxList,(newValue,oldValue)=>{
                    if(newValue.length==data.list.length&&data.list.length!=0){
                        data.selected=true;
                    }else{
                        data.selected=false;
                        flag=false;
                    }
                })
                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 add=(value)=>{
                    value.number++;
                    if(value.number>=value.stock){
                        value.number=value.stock;
                    }
                }
                const sub=(value)=>{
                    value.number--;
                    if(value.number<=1){
                        value.number=1;
                    }
                }
                const del=(index,id)=>{
                    data.list.splice(index,1);
                    let newArr=data.checkboxList.filter((value,index)=>{
                        return value.id!=id;
                    })
                    data.checkboxList=newArr;
                }
                return{
                    data,
                    totalPrice,
                    add,
                    sub,
                    del
                }
            }
        }).mount("#app")
    </script>
</body>

Vite

1、基于Vite创建Vue3项目

  • 在指定目录下打开cmd执行命令 npm create vite@latest

  • 打开src文件夹删除style.css文件和HelloWorld.vue文件
  • 打开main.js文件删除  import './style.css'
  • 打开App.vue文件删除 import HelloWorld from './components/HelloWorld.vue' 和 默认样式

2、导入组件

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

<template>
  <Header/>

  
  <Footer/>
</template>

<style scoped>

</style>

3、父传子defineProps

/*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,
    //   url:"ww.baidu.com"
    // }
    const propsweb = reactive({
      user:10,
      url:"www.baidu.com"
    })
    const userAdd=()=>{
      propsweb.user++;
      console.log(propsweb.user);
    }
</script>

<template>
  <!-- 父传子 - 方式1 -->
  <Header propsname="孙悟空" propsurl="baidu.com" />

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

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

<style scoped>

</style>

/*header.vue文件*/
<script setup>
    //接收方式:数组
    const props = defineProps(["propsname","propsurl"])
    console.log(props);
</script>

<template>
    <h3>header</h3>
</template>

<style scoped>

</style>

/*footer.vue文件*/
<script setup>
    //接收方式:对象
    const props=defineProps({
        user:Number,
        url:{
            type:String,
            required:false,//true表示必传属性,若未传则会提示警告信息
            default:"baidu.com"//未传默认值
        }
    })
    console.log(props)
</script>

<template>
    <h3>footer</h3> {{ props.user }}
</template>

<style scoped>

</style>

4、子传父defineEmits

/*App.vue文件*/
<script setup>
    import{reactive,ref} from 'vue'
    import Header from './components/header.vue'

    // 响应式数据
    const web = reactive({
      name:"孙悟空",
      url:"baidu.com"
    })
    const user = ref(0)
    const emitsGetWeb=(data)=>{
      console.log(data)
      web.url=data.url;
    }
    const emitsUserAdd=(data)=>{
      console.log(data);
      user.value+=data;
    }
</script>

<template>
    <Header @getweb="emitsGetWeb" @userAdd="emitsUserAdd"/>
    {{ web.url }} - {{ user }}
</template>

<style scoped>

</style>
/*header.vue文件*/
<script setup>
    const emits = defineEmits(["getweb","userAdd"])
    emits("getweb",{name:"黑神话",url:"www.baidu.com"})
    const add=()=>{
        emits("userAdd",10)
    }
</script>

<template>
    <h3>header</h3>
    <button @click="add">添加用户</button>
</template>

<style scoped>

</style>

5、跨组件通信-依赖注入

/*App.vue文件*/
<script setup>
    import{ref,provide,reactive} from 'vue'
    // 导入子组件
    import Header from './components/header.vue'

    // 响应式数据
    const web = reactive({
      name:"孙悟空",
      url:"baidu.com"
    })
    //provide用于父组件将数据提供给所有子组件
    /*
      若使用了provide和inject来进行数据传递,
      则一般不需要再使用defineProps
    */
    provide("provideWeb",web)

    const user = ref(0)
    provide("provideUser",user)

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

<template>
    <h3>App.vue-Top组件</h3>
    user:{{ user }}
    <!-- 子组件 -->
    <Header/>
</template>

<style scoped>

</style>

/*header.vue文件*/
<script setup>
    // 导入子组件
    import Footer from "./footer.vue"
    import {inject} from 'vue'
    //子组件通过inject注入父组件提供的响应式数据
    const user = inject("provideUser")
    console.log("provideUser",user)
</script>

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

<style scoped>

</style>

/*footer.vue文件*/
<script setup>
    import { inject } from 'vue';
    //子组件通过inject注入父组件提供的响应式数据
    const web=inject("provideWeb");
    console.log("provideWeb",web);
    //子组件通过inject注入父组件提供的响应式数据
    const FuncUserAdd = inject("provideFuncUserAdd")
    console.log(FuncUserAdd)
</script>

<template>
    <h3>footer.vue-Bottom组件</h3> 
    <button @click="FuncUserAdd">添加用户</button>
</template>

<style scoped>

</style>

6、匿名插槽和具体插槽v-slot

  • 插槽是指可以在父组件内自定义模板片段,在子组件中可以将定义的模板片段插入到子组件的特定位置。

/*App.vue文件*/
<script setup>
    // 导入子组件
    import Header from './components/header.vue';
    import Footer from './components/footer.vue';
</script>

<template>
    <h3>App.vue</h3>
    <Header>
        <a href="baidu.com">百度</a>
    </Header>
    <Footer>
          <!-- <template v-slot:url> -->
          <!-- v-slot简写形式 -->
          <template #url>
            <a href="www.baidu.com">网址</a>
          </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"/>
</template>

<style scoped>

</style>

7、作用域插槽

  • 作用域插槽:子组件向父组件传递数据,并在父组件定义的模板中渲染

/*App.vue文件*/
<script setup>
    // 导入子组件
    import Header from './components/header.vue';
    import Footer from './components/footer.vue';
</script>

<template>
    <h3>App.vue</h3>
    <Header>
        <a href="baidu.com">百度</a>
    </Header>
    <Footer>
          <!-- <template v-slot:url> -->
          <!-- 作用域插槽 -->
          <template #url="data">

            <!-- 解构形式 -->
            <!-- <template #url="{title,user}"> -->

            <!-- data用于接收数据 -->
            {{ data.title }}
            {{ data.user }}
            <a href="www.baidu.com">网址</a>
          </template>
    </Footer>
</template>

<style scoped>

</style>


/*footer.vue文件*/
<script setup>
    
</script>

<template>
    <h3>footer.vue子组件</h3> 
    <!-- 具名插槽 -->
    <slot name="url" title="摆渡" user="1000"/>
</template>

<style scoped>

</style>

8、生命周期函数

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

1、挂载阶段:

  •  onBeforeMount:在组件实例即将被挂载到DOM之前调用,此时模板还未编译或渲染到DOM,通常用于执行初始化操作,如:获取异步数据、设置初始属性值等。
  • onMounted:在组件成功挂载到DOM并完成首次渲染后调用,此时可以访问和操作DOM元素,并执行与页面交互相关的逻辑。

2、更新阶段:

  • onBeforeUpdate (由于响应式数据变化):在组件更新之前在重新渲染时之前调用,可以根据新的参数判断是否需要进行特殊处理,甚至可以选择阻止此次更新过程。
  • onUpdated:在组件完成更新并重新渲染后调用,可以基于新的渲染结果处理更新后的数据。

3、卸载阶段:

  • onBeforeUnmount:在组件从DOM中销毁之前调用,用于释放资源,如:清理计时器、解绑事件监听器等。
  • onUnmounted:在组件已经从DOM中移除并销毁后调用,确保组件所占用的所有资源都被正确释放。

4、错误处理:

  • onErrorCaptured:在捕获到组件中的错误时调用,用于处理错误,如:记录错误日志等。
<script setup>
    import { onMounted,onUpdated,ref} from 'vue';
    // 在组件成功挂载到DOM并完成首次渲染后调用
    onMounted(()=>{
      console.log("onMounted")
    })
    // 组件更新后调用
    onUpdated(()=>{
      console.log("onUpdated")
    })
    const user = ref(0)
    console.log(user.value)
</script>

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

<style scoped>

</style>

9、toRef和toRefs

  • toRefs将一个响应式对象的所有属性转换为ref对象
  • toRef将一个响应式对象的某个属性转换为ref变量
<script setup>
    import {reactive,toRefs,toRef} from 'vue';
    let web=reactive({
      name:"黑神话",
      url:"baidu.com"
    })
    // let{name,url}=toRefs(web);
    let url=toRef(web,"url")
    console.log(url)
</script>

<template>
    {{ url }}
</template>

<style scoped>

</style>

Pinia

1、Pinia简介

  • Pinia是一个轻量级的状态管理库,状态管理库是用于管理应用程序全局状态的工具。
  • Pinia可以处理大型项目中复杂的状态管理需求,而父传子、子传父以及跨组件通信,可以解决一些简单的状态传递问题,更适合小型项目。
  • 对于复杂的状态管理需求,使用Pinia是更好的选择,而对于简单的状态管理需求,使用localStorage是更简单的解决方案。

  • 以登录为例:使用Pinia创建一个userStore来集中管理用户的登录状态和过期时间。
    • 当用户登录成功时:设置userStore中用户的登录状态为已登录,并设置过期时间。
    • 当用户退出登录时:修改userStore中用户的登录状态为未登录,并删除过期时间。

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

  • 在终端中输入命令安装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 { defineStore } from "pinia";
import { reactive,ref } from "vue";
//定义一个基于Pinia的Store
 export const useWebStore = defineStore('web',()=>{
    const web=reactive({
        title:"仓库管理",
        url:"baidu.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)
    console.log(webStore.users)
</script>

<template>
    {{ webStore.web.url }}
    {{ webStore.users }}
    <button @click="webStore.userAdd">添加用户</button>
</template>

<style scoped>

</style>

3、Pinia持久化存储插件

1、安装npm i pinia-plugin-persistedstate

2、将插件添加到 pinia 实例上

import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

3、创建 Store 时,将 persist 选项设置为 true

//组合式语法
import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useStore = defineStore(
  'main',
  () => {
    const someState = ref('你好 pinia')
    return { someState }
  },
  {
    persist: true,
  },
)

  • 33
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3是一种流行的JavaScript框架,用于构建用户界面。Vue Router是Vue.js的官方路由器,用于实现单页面应用程序的导航功能。Vite是一个快速的Web开发构建工具,具有即时重载和快速的开发体验。Pinia是一个简单、快速、类型安全的状态管理库。 使用Vue3、Vue Router、Vite和Pinia进行组件化开发实战入门非常简单。 首先,我们需要安装Vue3和相关的库。可以使用npm或yarn来安装它们。在项目的根目录中运行以下命令: ``` npm install vue@next vue-router@next @pinia/vue@next vite --save ``` 安装完成后,我们可以开始创建一个Vue应用程序。在项目的根目录中创建一个`src`文件夹,并在其中创建一个`main.js`文件。在`main.js`文件中,我们需要导入VueVue Router和Pinia,并创建一个Vue实例。代码示例如下: ```javascript // main.js import { createApp } from 'vue'; import { createRouter, createWebHistory } from 'vue-router'; import { createPinia } from 'pinia'; // 导入组件 import App from './App.vue'; // 创建路由 const router = createRouter({ history: createWebHistory(), routes: [ // 定义路由 { path: '/', component: Home } ] }); // 创建 Pinia 实例 const pinia = createPinia(); // 创建 Vue 实例 const app = createApp(App); // 使用路由和 Pinia app.use(router); app.use(pinia); // 挂载应用 app.mount('#app'); ``` 现在,我们可以创建一个简单的Vue组件。在`src`文件夹中创建一个名为`App.vue`的文件,并在其中定义一个组件。在组件中,我们可以使用Pinia来管理组件的状态,使用Vue Router来处理导航。 ```html <!-- App.vue --> <template> <div> <router-view></router-view> <button @click="increment">增加计数器</button> <p>{{ count }}</p> </div> </template> <script> import { defineComponent } from 'vue'; import { useCounter } from '../store'; export default defineComponent({ setup() { const counter = useCounter(); const increment = () => { counter.increment(); }; return { count: counter.count, increment }; } }); </script> ``` 在上述示例中,我们创建了一个Counter组件,其中包含一个用于增加计数器的按钮和一个显示计数器值的段落。我们使用Pinia的`useCounter`钩子来访问和修改计数器的状态。 最后,在项目的根目录中运行以下命令启动应用程序: ``` npm run dev ``` 以上就是使用Vue3、Vue Router、Vite和Pinia进行组件化开发实战入门的一个简单示例。通过深入学习这些工具和框架,您将能够构建更复杂、功能丰富的应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值