Vue3 基础语法

176 阅读9分钟

文本差值:{{ }}

  • 最基本的数据绑定形式是文本插值{{ }},它使用的是“Mustache”语法 (即双大括号)
  • 在标签内部显示内容
  • 【注】双大括号内只能写表达式
// 头部<head>引入
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

<body>
    <div id="box">
        {{mytext}}   
    </div>
    <script>
        const obj = {
            data(){
                return {
                    mytext:"hello"
                }
            }
        }
        const app = Vue.createApp(obj).mount('#box')
    </script>
</body>

属性绑定: v-bind

  • 只要是想要动态绑定的属性,就可以使用 v-bind:属性
  • 可简写为 :属性
// 头部<head>引入
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

<body>
    <div id="box">
        <img :src="url" alt="" :width="width">
        ----分割线----
        <img v-bind="obj">
    </div>
    <script>
        const obj = {
            data() {
                return {
                    url: "https://static.maizuo.com/pc/v5/usr/movie/abd301585b7661f088a0caaa0fb0c3b2.jpg?x-oss-process=image/quality,Q_70",
                    width: 200,
                    obj: {
                        src: "https://static.maizuo.com/pc/v5/usr/movie/abd301585b7661f088a0caaa0fb0c3b2.jpg?x-oss-process=image/quality,Q_70",
                        width: 200
                    },
                }
            }
        }
        const app = Vue.createApp(obj).mount('#box')
    </script>
</body>

双向绑定:v-model (表单绑定)

  • 可以绑定表单元素的值
  • 会根据表单元素的值自动更新 data 属性中的值

输入框

  • v-model绑定的是value值
// 结构
<div id="box">
    <input type="text" v-model="mytext">
    <textarea v-model="mytext"></textarea>
    <p>{{mytext}}</p>
</div>

// vue
<script>
    const obj = {
        data() {
            return {
                mytext: ""
            }
        }
    }
    const app = Vue.createApp(obj).mount('#box')
</script>

多选框 - checkbox

  • 在只有一个多选框的情况下:
    • v-model绑定的是checked值(true和false)
  • 有多个:
    • v-model绑定的是数组,数组中是选中的checkbox的value值
    • 【注】value值必须写,不然就没有意义了
<div id="box">
    <!--  单个多选框  -->
    <p>
        用户名:<input type="text" v-model="username">
    </p>
    <p>
        记住用户名<input type="checkbox" v-model="isRem">
    </p>
    <p>用户名:{{username}}</p>
    <p>是否记住密码:{{isRem}}</p>
    <!--  多个  -->
    <p>
        vue<input type="checkbox" value="vue" v-model="checkList">
        react<input type="checkbox" value="react" v-model="checkList">
        小程序<input type="checkbox" value="小程序" v-model="checkList">
    </p>
    <p>选中的多选框:{{checkList}}</p>
</div>
// vue
<script>
    const obj = {
        data() {
            return {
               username: "", // 用户名
               isRem: false,  // 默认不选中记住用户名
               checkList: ["react"]  // 默认选中value值为value的多选框
            }
        }
    }
    const app = Vue.createApp(obj).mount('#box')
</script>

单选按钮

  • v-model绑定同一个变量,就代表这几个单选按钮是一个组
    • (有点像name值的绑定)
<div id="box">
    <h2>radio -- 性别</h2>
    <p><input type="radio" value="男" v-model="sex"><input type="radio" value="女" v-model="sex">
    </p>
    <p>性别:{{sex}}</p>  
</div>
// vue
<script>
    const obj = {
        data() {
            return { 
               sex: "女"  // 默认性别为女
            }
        }
    }
    const app = Vue.createApp(obj).mount('#box')
</script>

下拉列表

  • v-model绑定在select标签上,绑定的值就是selected(被选中的值),
    • 值就是option的value值
<div id="box">
    <h2>下拉列表</h2>
    <select v-model="select">
        <option :value="1">已发货</option>
        <option :value="2">已取消</option>
        <option :value="3">已完成</option>
        <option :value="4">已付款</option>
    </select>
    <p>
        选中的状态的值:{{select}}
    </p>
</div>
// vue
<script>
    const obj = {
        data() {
            return { 
               select:2  // 默认选中value值为2的option,也就是已取消
            }
        }
    }
    const app = Vue.createApp(obj).mount('#box')
</script>

表单修饰符

  • 加在v-model后面
  1. .lazy 将input事件改为change事件,
    • change事件在失去焦点并且内容发生改变时触发
  2. .number 将输入的字符串转为数字
    • number修饰符在输入框中 type = number 时,会自动启用
  3. .trim 去除首尾空格
<!-- lazy -->
<input type="text" v-model.lazy="mytext">
{{mytext}}

<!-- trim -->
<input type="text" v-model.trim="mytext2">
{{mytext2}}

事件

事件处理器

  • v-on:
  • 简写:@
  • 写法:
    1. v-on:事件名="方法名",简写为 @事件名="方法名"
      • 没加小括号,也会执行方法,而且会自动传递一个事件对象 $event
    2. v-on:事件名="方法名(参数,$event)" 可简写
      • $event是vue中内置的参数,表示事件对象
    3. 方法中只有一句代码,可以直接写在标签中,不用再去methods中定义方法 , 可简写
<div id="box">
    <!-- 写法 1 -->
    <button @click="fn1">方法名不括号</button>
    <!-- 写法 2  -->
    <button @click="fn2($event,'cxm')">方法名加括号</button>
    <!-- 写法 3 -->
    <p>
        <button @click="count--"></button>
        <span>{{count}}</span>
        <button @click="count++"></button>
    </p>
</div>
<script>
    const obj = {
        data() {
            return {
                count: 0
            }
        },
        methods: {
            fn1(e) {
                console.log("没加小括号,也会执行方法,而且会自动传递一个事件对象 $event", e);
            },
            fn2(e, name) {
                console.log(name, e);
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

事件修饰符

  • 可以链式调用
  1. .stop:阻止事件冒泡
  2. .prevent:阻止默认事件
  3. .capture:使用事件捕获
  4. .self:只有事件发生在当前元素上才会触发
  5. .once:事件只触发一次
  6. .passive:事件只触发一次,并且事件会立即执行
<div id="box">
    <h2>事件修饰符:</h2>
    <!-- .self 点击当前元素才能触发 -->
    <ul @click.self="clickUl">
        <!-- .stop 阻止冒泡 -->
        <li @click.stop="clickLi">1111</li>
        <li>2222</li>
    </ul>
    <!-- .prevent阻止默认行为 -->
    <form action="/login" @submit.prevent="submit">
        <button type="submit">提交</button>
    </form> <br>
    <!-- .once 事件只触发一次 -->
    <button @click=" isOnce && clickOnce()">抽奖(函数表达式)</button>
    <button @click.once="clickOnce()">抽奖(事件修饰符)</button>
</div>
<script>
    const obj = {
        data() {
            return {
                isOnce: true,
            }
        },
        methods: {
            clickUl(e) {
                console.log("ul --- click");
            },
            clickLi(e) {
                console.log("li --- click");
                // e.stopPropagation(); 阻止冒泡
            },
            submit(e) {
                console.log("submit提交校验");
                // e.preventDefault(); 阻止默认行为
            },
            clickOnce() {
                console.log("抽奖只能触发一次哦~");
                this.isOnce = false;
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

按键修饰符

  • 可以链式调用
  1. .enter:回车键触发事件
  2. .delete:删除键触发事件,包括backspace和delete
  3. .tab:tab键触发事件
  4. .esc:esc键触发事件
  5. .space:空格键触发事件
  6. .up:上键触发事件
  7. .down:下键触发事件
  8. .left:左键触发事件
  9. .right:右键触发事件
  10. .ctrl:ctrl键触发事件
  11. .alt:alt键触发事件
  12. .shift:shift键触发事件
<div id="box">
    <!-- .enter 回车键触发事件 -->
    <input type="text" v-model="mytext" @keyup.enter="mytext.trim() && add()" placeholder="按回车键提交数据">
    <ul class="list">
        <li v-for="(item,index) in list" :key="item">
            <span>{{item}}</span>
            <button @click=del(index)>删除</button>
        </li>
    </ul>
    <!-- 链式调用 -->
    <!-- 同时按下shift、ctrl、enter才可以触发 -->
    <input type="text" @keyup.shift.enter.ctrl="myshow.trim() && addtArr()" v-model="myshow"
        placeholder="按shift+ctrl+enter添加数组元素">
    <p>{{arr}}</p>
</div>
<script>
    const obj = {
        data() {
            return {
                mytext: "",
                list: ["aaaa", "bbbb"],
                myshow: "",
                arr: [11, 22]
            }
        },
        methods: {
            add() {
                this.list.push(this.mytext)
                this.mytext = ""
            },
            del(index) {
                this.list.splice(index, 1)
            },
            addtArr() {
                this.arr.push(this.myshow)
                this.myshow = ""
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

小案例 - 模态框

// 结构
<div id="box">
    <button @click.self="isShow=true">模态框</button>
    <!-- 方式一: -->
   <!--  <div id="overlay" v-show="isShow" @click.self="hide"> 
        <div id="center">
            <input v-model="mytext" /><br>
            <button @click.stop="hide">login</button>
        </div>
    </div> -->
    <!-- 方式二: -->
    <div id="overlay" v-show="isShow" @click="hide">
        <div id="center" @click.stop>  <!-- 阻止事件冒泡 -->
            <input v-model="mytext" />
            <button @click.stop="hide">login</button>
        </div>
    </div>
</div>
// 行为
<script>
    var obj = {
        data() {
            return {
                isShow: false,
                mytext: ""
            }
        },
        methods: {
            hide(e) {
                this.isShow = false
                this.mytext = ""
            }
        }
    }
    Vue.createApp(obj).mount("#box")
</script>
// 样式
<style>
    #overlay {
        background: rgba(0, 0, 0, 0.6);
        width: 100%;
        margin: auto;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
    }
    #center {
        background: #ffff;
        border-radius: 5px;
        /* 边框圆角 */
        padding-top: 15px;
        padding-left: 30px;
        padding-bottom: 15px;
        width: 290px;
        height: 160px;
        position: fixed;
        margin: auto;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
    }
</style>

列表渲染:v-for

  • 语法:v-for="(每一项,下标) in或of关键字 数组 "
  • 【注】 v-if 和 v-for 不能在同一个标签中使用
    • 可以在在外层中嵌套一个template标签,在template中写v-for,在里层标签中写v-if
    • template标签不会生成节点在页面中,不会改变页面的结构
<body>
    <div id="box">
        <!-- 数组 -->
        <ul>
            <li v-for="(item,index) in arr">
                {{item}} -- {{index}}
            </li>
        </ul>
        <!-- 数组对象,解构 -->
        <hr>
        <ul>
            <li v-for="({id,name},index) in arr1">
                {{id}} ~ {{name}}
            </li>
        </ul>
        <!-- 
            of === in 
            在遍历对象的时候,内部会进行处理,把数组转为对象:Object.entries(obj) 
        -->
        <hr>
        <ul>
            <li v-for="({id,name},index) of arr1">
                {{id}} ~ {{name}}
            </li>
        </ul>
    </div>

    <script>
        const obj = {
            data() {
                return {
                    arr: ["aaa", "bbb", "ccc", "ddd", "eee"],
                    arr1: [
                        { id: 1003, name: "张三" },
                        { id: 1004, name: "李四" },
                        { id: 1005, name: "王五" },
                    ]
                }
            }
        }
        const app = Vue.createApp(obj).mount("#box")
    </script>
</body>

:key值的设置

  • 好处:可以提高性能
    • key值设置后,vue内部会对key值进行一个缓存,如果key值没有变化,则不会更新dom节点
  • 使用场景
    • 一般与v-for搭配使用
    • key值一般设置为不重复的id值,后端返回的数据中一般会有id值
  • 虚拟dom:
    • 虚拟dom是一个js对象,描述了真实dom结构
    • 真实dom和虚拟dom的区别:
      • 真实dom:浏览器渲染出来的页面
      • 虚拟dom:js对象
<div id="box">
    <ul>
        <li v-for="({id,title,state},index) in datalist" :key="id">
            {{title}}
        </li>
    </ul>
</div>
<script>
    const obj = {
        data() {
            return {
                datalist: [
                    { id: 1001, title: "手机", state: 0 },
                    { id: 1002, title: "衣服", state: 1 },
                    { id: 1003, title: "裤子", state: 2 },
                ],
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

显示隐藏:v-show

  • v-show="表达式"
  • 为true时,显示元素;为false时,隐藏元素
  • 操作的是元素的display属性
<div id="box">
    <p v-show="show">我被显示了</p>
    <p v-show="hide">我被隐藏了</p>
    <p v-show="a===a">aaaaaa被显示了</p>
</div>

<script>
    const obj = {
        data() {
            return {
                show: true,
                hide: false
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

条件渲染:v-if、v-else-if、v-else

  • v-if
  • v-else-if
  • v-else
  • v-if 和 v-show 的区别:
    • v-show是操作元素的display属性,v-if是直接创建和删除元素
    • 在频繁切换的时候,v-show会更好一些
<body>
    <div id="box">
        <!-- 用法1: -->
        <ul>
            <li v-for="({title,state},index) in datalist">
                {{title}} --
                <span v-if="state===0">未付款</span>
                <span v-else-if="state===1">运输中</span>
                <span v-else-if="state===2">已签收</span>
            </li>
        </ul>
        <!-- 
            用法2:
            v-if 也可以判斷元素的显示和隐藏
            v-if=" 表达式 "
            v-if 判断为真,则创建,如果为假,则不创建
         -->
        <div v-if="show">我被显示了</div>
        <div v-if="hide">我被隐藏了</div>
    </div>
    <script>
        const obj = {
            data() {
                return {
                    datalist: [
                        { title: "手机", state: 0 },
                        { title: "衣服", state: 1 },
                        { title: "裤子", state: 2 },
                    ],
                    show: true,
                    hide: false
                }
            }
        }
        const app = Vue.createApp(obj).mount("#box")
    </script>
</body>

image.png

动态绑定class的方法

  • 对象
    • key: class名
    • value: true/false
      • true: 添加该class
      • false: 不添加该class
  • 数组
    • 写入要添加的class名
// 样式
    <style>
        .color {color: orange;}
        .bg {background: linen;}
        .fs {font-size: 30px;line-height: 50px;}
    </style>
// 标签
   <div id="box">
        <p :class="objClass">动态class的绑定方法 -- 对象</p>
        <p :class="arr">动态class的绑定方法 -- 数组</p>
    </div>
// vue
<script>
        const obj = {
            data() {
                return {
                    // 对象
                    objClass: {
                        color: true,
                        bg: true,
                        fs: false
                    },
                    // 数组
                    arr: ["color", "fs"]
                    /* 
                        在数组中添加新属性
                        vue2 不支持 后来添加新属性
                        vue3 支持 
                    */
                }
            }
        }
        const app = Vue.createApp(obj).mount("#box")
    </script>

动态绑定style的方法

  • 对象
    • key为样式名,value为样式的值
  • 数组
    • 数组中的每一项都会添加到标签上去
// 标签
     <div id="box">
        <p :style="styleObj">动态的添加style属性 -- 对象</p>
        <p :style="styleArr">动态的添加style属性 -- 数组</p>
        <button @click="add()">添加属性</button>
    </div>
// vue
    <script>
        const obj = {
            data() {
                return {
                    // 对象
                    styleObj: {
                        color: "white",
                        backgroundColor: "red"
                    },
                    // 数组
                    styleArr: [
                        { color: "white" },
                        { backgroundColor: "orange", fontSize: "30px" }
                    ]
                }
            },
            methods: {
                // 添加属性
                add() {
                    this.styleObj.fontSize = "50px"
                    this.styleArr.push("text-align:center")
                }
            }
        }
        const app = Vue.createApp(obj).mount("#box")
    </script>

计算属性:Computed

  • 调用方式:不用加括号,直接调用
  • 好处:
    • 计算属性可以用来简化模板{{ }}中的表达式
    • 计算属性可以用来缓存数据,减少不必要的DOM操作
  • 缓存的特性:是存储到内存中,当下次再次访问时,直接从内存中读取
  • 【注】
    • 计算属性是基于依赖的缓存,依赖改变,才会重新计算
    • 计算属性中不能写异步操作
    • 计算属性是可以被赋值的,通过get,set方法

简化表达式

<p>首字母大写:{{myName.toUpperCase().substring(0,1)+myNamesubstring(1).toLowerCase()}}</p>
<p>首字母大写:{{ComputedName}}</p>

data(){
    return {
        myNmae:"caoxinmei"
    }
},
 computed: {
    // 首字母大写
    ComputedName() {
        console.log("计算属性被执行了!");
        return this.myName.toUpperCase().substring(0, 1) + this.myName.substring(1).toLowerCase()
    },
}

缓存的特性

<div id="box">
    <!-- 缓存的特性 ---与方法对比 -->
    <p>
        {{ComputedName}}
        {{ComputedName}}
        {{ComputedName}}
    </p>
    <p>
        {{methodName()}}
        {{methodName()}}
        {{methodName()}}
    </p>
</div>
<script>
    const obj = {
        data() {
            return {
                myName: "caoxinmei",
            }
        },
        // 计算属性
        computed: {
            // 首字母大写
            ComputedName() {
                console.log("计算属性被执行了!");
                return this.myName.toUpperCase().substring(0, 1) + this.myName.substring(1).toLowerCase()
            },
        },
        // 方法
        methods: {
            methodName() {
                console.log("方法被执行了!");
                return this.myName.toUpperCase().substring(0, 1) + this.myName.substring(1).toLowerCase()
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

计算属性的赋值

<div id="box">
    <!-- 计算属性的赋值 -->
    <p>
        {{ComputedDate}}
    </p>
    <!-- 在控制台输入 app.ComputedDate="2000-1-1"  可看到变化-->
</div>
<script>
    const obj = {
        data() {
            return {
                // 年月日
                year: new Date().getFullYear(),
                month: new Date().getMonth() + 1,
                day: new Date().getDate(),
            }
        },
        // 计算属性
        computed: {
           // 计算属性是可以被赋值的,get、set方法
            ComputedDate: {
                // 原理就是在设置的时候调用了set方法,改变了year、month、day的值
                // get方法又依赖了year、month、day,所以当year、month、day改变时,就会触发get方法
                get() {
                    return this.year + "年" + this.month + "月" + this.day + "日"
                },
                set(value) {
                    // 假设后端返回的数据格式为:2019-10-10
                    [this.year, this.month, this.day] = value.split("-")
                }
            }
        },
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

侦听器:watch

  • 要监听那个数据,就在watch里面写一个相同名称的函数
  • watch中可以写异步代码
  • watch与conputed的区别:
    1. watch不会立即执行(除非加上 immediate:true),计算属性会立即执行
    2. watch监听一个状态,计算属性监听多个状态
    3. watch支持同步和异步,计算属性只支持同步

监听字符串

<div id="box">
    <!-- 监听字符串,并通过异步实现 -->
    <input type="text" v-model="mytext">
    <ul>
        <li v-for="item in list" :key="item">
            {{item}}
        </li>
    </ul>
</div>
<script>
    const obj = {
        data() {
            return {
                // 模糊查询
                mytext: "",
                list: ["aaa", "bbb", "ccc", "abc", "aac", "aca", "bacc", "bbaa", "acac"],
                copyList: ["aaa", "bbb", "ccc", "abc", "aac", "aca", "bacc", "bbaa", "acac"]
            }
        },
        watch: {
            // 监听mytext
            mytext(value) {
                // 模拟异步代码
                setTimeout(() => {
                    this.list = this.copyList.filter(item => item.includes(value))
                }, 1000)
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

监听对象

<div id="box">
    <!-- 监听对象 -->
    <!-- 场景:模拟查看对应日期的数据 -->
    <select v-model="obj.year">
        <option :value="2021">2021</option>
        <option :value="2022">2022</option>
        <option :value="2023">2023</option>
        <option :value="2024">2024</option>
    </select>
    <select v-model="obj.month">
        <option :value="10">10</option>
        <option :value="11">11</option>
        <option :value="12">12</option>
    </select>
    <select v-model="obj.day">
        <option :value="31">31</option>
        <option :value="1">1</option>
        <option :value="2">2</option>
    </select>
    <p>{{obj}}</p>
</div>
<script>
    const obj = {
        data() {
            return {
                // 模拟对象
                obj: {
                    year: 2023,
                    month: 12,
                    day: 31
                }
            }
        },
        watch: {
            // 监听对象
            //      方式一:监听对象中的某些属性,fn为回调函数
            // "obj.year": "fn",
            // "obj.month": "fn",
            // "obj.day": "fn",
            //      方式二:深度监听,监听对象中的所有属性,(不推荐)
            obj: {
                handler(value) {
                    console.log("深度监听" + value);
                },  // 函数handler是固定写法
                deep: true, // 深度监听
                immediate: true // 立即执行
            }
        },
        motheds: {
            fn(value, oldvalue) {
                console.log(value, oldvalue);
            }
        }
    }
    const app = Vue.createApp(obj).mount("#box")
</script>

fetch 和 axios 的使用

  • 与在原生js中的写法一致,这里只演示get请求的用法,详细:fetchaxios 用法

fetch

data() {
    return {
        datalist: []
    }
},
methods: {
    // 获取数据
    get() {
        fetch("./11.json")
            .then(resp => resp.json())
            .then(res => {
                this.datalist = res.data.hot
                console.log(res.data.hot);
            })
    }
}

axios

data() {
    return {
        datalist: []
    }
},
methods: {
    // 获取数据
    get() {
        axios.get("./12.json").then(res => {
            console.log(res.data.data.films)
            this.datalist = res.data.data.films
        })
    },
}