目 录CONTENT

文章目录

vue基础

Administrator
2021-11-18 / 0 评论 / 10 点赞 / 6238 阅读 / 39623 字 / 正在检测是否收录...

vue基础

一、vue概念

Vue.js是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue采用自底向上增量开发的设计。Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合。另一方面,Vue 完全有能力驱动采用单文件组件和Vue生态系统支持的库开发的复杂单页应用(单页面开发SPA)。

渐进式框架:可以理解为上手简单,入门简单,但是可以渐近提高框架等级

视图层:之前我们的express它是一个MVC的框架

SPA:称之为单页面开发,是目前开发的主流,当前阶段能够很好的实现SPA开发的框架主要有三个,分别是vue/react/angular

还有一个涉及到的新概念叫MVVM,它是相对于MVC来进行的

MVC的模型

image.png

M:Module数据模型,可以理解为从数据库查出来的数据

V:View视图,可以理解为页面

C:Controller控制器,一般可以理解为路由

在nodejs里面典型的MVC框架就是express,koa,egg等,但是我们在学习的时候只是使用了express里面的M和C


MVVM:Model View and ViewModel,直接将数据与视图结合,去掉中间的整合过程,这样更快速,更高效,最典型的应用点就是数据驱动页面

二、vue安装与使用及版本介绍

目前最新版本是3.2.0-beta.8,但是稳定版仍然持续在2.6.14,授课仍然以2为主,后面带入到3

$ yarn add vue

下载包以后,直接找到vue.jsvue.min.js即可

三、vue接管页面数据

vue的核心

  1. 数据驱动页面【抛弃DOM操作】
  2. 虚拟DOM操作(virtual-dom)

现在在基础阶段我们只关注第一个点数据驱动页面,在开发过程当中vue会接管整个页面的数据以及事件等


<body>
    <div id="app">

    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app"
    });
</script>

vue在接管页面的时候,它不能接管body更不能接管html

当vue一旦接管某一个区域以后,这个区域里面所有的东西都可以通过vue来操作,如数据,事件,样式等

<body>
    <div id="app">
        <input type="text" v-model="userName" style="width: 500px;height: 40px;">
        <h2>{{userName}}</h2>
        <p v-show="userName.length<=0" style="color: red;font-weight: bold;">当前姓名不能为空</p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            userName: "标哥哥"
        }
    })
</script>

在上面的代码里面,我们可以看到,页面上面有一个变量userName,它使用的就是我们data里面定义的属性,vue接管页面以后,页面所有的数据都可以在data或后期学习的计算属性里面找到

四、vue数据绑定及渲染

1. 基本数据绑定渲染

<body>
    <div id="app">
        <h2>{{1+1}}</h2>
        <hr>
        <h2>{{age+2}}</h2>
        <hr>
        <h2>{{age>=18?"成年":"未成年"}}</h2>
        <hr>
        <h2>当前时间:{{new Date().toLocaleString()}}</h2>
        <hr>
        <h2>{{new Array(10).fill("杨").join("-")}}</h2>
        <hr>
        <!-- 下面的写法是错的 -->
        <a href="{{u1}}">标哥的网页</a>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            age: 18,
            u1: "http://www.softeem.xin:8090"
        }
    });
</script>

</html>
  1. v-text数据绑定
  2. v-html数据绑定
  3. {{}}数据绑定,这一种相当于innerText的数据绑定
  4. v-model表单元素的绑定,执行双向数据绑定
  5. v-once单次绑定,只会在第一次的时候绑定这个值 ,这个值如果后期改变了,我也不改变

<body>
    <div id="app">
        姓名:<input type="text" v-model="userName">
        <hr>
        年龄:<input type="text" v-model="age">
        <hr>
        性别:<select v-model="sex">
            <option value="男">这是儿子伢</option>
            <option value="女">这是姑娘伢</option>
        </select>
        <hr>
        角色:<input type="radio" name="aaa" value="学生"
            v-model="role">我是学生
        <input type="radio" name="aaa" value="老师"
            v-model="role">我是老师
        <hr>
        爱好:<input type="checkbox" name="bbb" value="看书"
            v-model="hobby">看书
        <input type="checkbox" name="bbb" value="睡觉"
            v-model="hobby">睡觉
        <input type="checkbox" name="bbb" value="玩游戏"
            v-model="hobby">玩游戏
        <input type="checkbox" name="bbb" value="打牌"
            v-model="hobby">打牌

        <hr>
        <h2>{{sex}}</h2>
        <h2>{{role}}</h2>
        <h2>{{hobby}}</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            userName: "小珊子",
            age: 18,
            sex: "女",
            role: "学生",
            hobby: ["玩游戏"]
        }
    });
</script>

2. 列表渲染

<body>
    <div id="app">
        <p v-for="(item,index) in stuList" :key="index">
            {{index}}----{{item}}
        </p>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            stuList: ["季强", "欢欢", "松明大哥", "喻金大哥"]
        }
    });
</script>

</html>
  1. 在使用v-for的时候最好是在每一个生成项上面添加一个:key,相当于数据库的主键,不重复,不可或缺
  2. 后期SPA脚手架里面,严禁使用index做key,如果非要使用index做key,一定要注意后果

3. 条件渲染

这个就是根据某一个条件才去执行渲染,条件成立就渲染出来 ,条件不成立就不渲染出来

  • v-if
  • v-else
  • v-else-if
<body>
    <div id="app">
        <h2 v-if="flag">标哥哥真帅</h2>
        <hr>
        <input type="range" v-model="age">{{age}}
        <!-- 如果年龄大于等于18就渲染第一个成年,否则就渲染第二个 未成年 -->
        <h2 v-if="age>=18">你是成年人了</h2>
        <h2 v-else>我勒个去,你还是个小孩子</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            flag: true,
            age:19
        }
    });
</script>
<body>
    <div id="app">
        <!-- 
            100~90优秀
            89~89良好
            79~70中等
            69~60及格
            60以及不及格
         -->
        <h2 v-if="score>=90">优秀</h2>
        <h2 v-else-if="score>=80">良好</h2>
        <h2 v-else-if="score>=70">中等</h2>
        <h2 v-else-if="score>=60">及格</h2>
        <h2 v-else>小坏蛋,竟然不及格</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            score: 90
        }
    });
</script>

条件渲染与列表渲染还可以结合起为一起使用

<body>
    <div id="app">
        <!-- 只渲染stuList里面性别为男的数据 -->
        <ul>
            <li v-for="(item,index) in stuList"
                :key="index"
                v-if="item.sex=='男'">
                {{item.stuName}}-----{{item.sex}}
            </li>
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            stuList: [{
                stuName: "季强",
                sex: "男"
            }, {
                stuName: "陈欢欢",
                sex: "女"
            }, {
                stuName: "松明大哥",
                sex: "男"
            }, {
                stuName: "喻金大哥",
                sex: "男"
            }]
        }
    });
</script>

本质:v-if渲染与不渲染本质就是在页面里面把你注释掉了,条件成立就不注释,条件不成立就把这个元素注释掉

4. v-show条件显示

这个东西与上面的东西v-if非常像,但是本质是不一样的

<h2 v-show="flag2">这还是标哥哥</h2>

本质v-show如果条件成立就正常显示 ,如果条件不成立,则会通过display:none来进行隐藏

5. 属性绑定

回顾上面的数据绑定,我们发现无论是通过{{}}还是v-textv-htmlv-model它们都只是对innerText/innerHTML/value属性进行绑定。如果我们要绑定其它属性呢,这个时候我们要使用vue专门的指令叫v-bind:属性名来进行

<body>
    <div id="app">
        <a v-bind:href="u1">百度一下</a>
        <hr>
        <a :href="u2">标哥哥的博客</a>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            u1: "https://www.baidu.com",
            u2: "http://www.softeem.xin:8090"
        }
    });
</script>

重点注意:属性绑定本应该使用v-bind:属性名来完成,但是vue考虑到这个操作在后期的开发当中经常使用,所以直接简写成:属性名就可以了

所以后期如果看到一个属性的前面有:则代表动态属性绑定

在属性绑定里面有两个属性比较特殊,我们要到后面讲,这两个属性是styleclass

五、vue 指令及自定义指令

在上面的执行数据渲染和绑定的过程当中,我们看到了很多以v-xxx的东西,这些东西在vue里面叫指令

  1. v-text
  2. v-html
  3. v-model
  4. v-if
  5. v-else
  6. v-else-if
  7. v-for
  8. v-show
  9. v-bind

上面都是vue自带的指令,我们还可以根据自己的需求来写一些自己的指定,它通过Vue.directive来定义,这里先不做讲解,在项目式授课里面具体讲解

vue是通过一系列的指令来完成页面的操作的,指令应该算是一个重要的环节

六、vue事件与事件对象,参数

vue在接管页面的时候,上面的过程是接管数据的过程,它还可以接管事件及方法,它的事件绑定通过v-on:事件名来进行

<body>
    <div id="app">
        <button type="button"
            v-on:click="sayHello">
            按钮1
        </button>
        <h2 v-on:click="aaa(1231123)">你好</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        // 负责接管页面的数据
        data: {

        },
        //负责接管页面的方法
        methods: {
            sayHello() {
                alert("大家好,我是vue的第一个方法")
            },
            aaa(number){
                alert(number);
            }
        }
    });
</script>

在上面的事件方法里面,我们可以看到methods负责接管整个页面的事件方法,同时在事件调用方法的时候,如果这个方法不需要传递参数,则方法后面的小括号可以省略

同时vue也考虑到事件绑定会经常操作,它也有一种简写方法@事件名来进行

<button type="button" @click="sayHello">简写</button>

如果需要得到事件对象,则需要在调用事件方法的时候传递$event来进行

<button type="button" @click="sayHello($event)">简写</button>

在vue的事件内部,如果想拿到data里面的数据,应该使用this.$data,但是可以简写,去掉$data也可以,如下

<body>
    <div id="app">
        <input type="text" v-model="userName">
        <h2>{{userName}}</h2>
        <button type="button" @click="aaa">按钮1</button>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        // 负责接管页面的数据
        data: {
            userName: "张三"
        },
        //负责接管页面的方法
        methods: {
            aaa() {
                //正常情况下,确实应该使用this.$data去找data
                // console.log(this.$data.userName);
                console.log(this.userName);
                this.bbb();
            },
            bbb() {
                alert("hello world");
            }
        }
    });
</script>

同时如果要在方法的内部调用其它方法,也是直接通过this来调用

七、vue计算属性

之前给同学们提到过,如果托管区域要使用数据 必须 从data里面得到,其实从computed计算属性里面也可以得到

<body>
    <div id="app">
        <h2>{{aaa}}</h2>
        <hr>
        <h2>{{bbb}}</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
          
        },
        //计算属性,计算属性是一个方法,空上方法的返回值会当成渲染的值
        computed:{
            aaa(){
                return "标哥"
            },
            bbb(){
                return parseInt(Math.random()*100)
            }
        }
    });
</script>

计算属性本质上面是一个方法,它可以通过我们的computed里面定义方法,然后在方法里面返回值去实现功能

<body>
    <div id="app">
        <h2>男生:{{boyCount}}</h2>
        <h2>女生:{{girlCount}}</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        // 负责接管页面的数据
        data: {
            stuList: [{
                stuName: "季强",
                sex: "男"
            }, {
                stuName: "陈欢欢",
                sex: "女"
            }, {
                stuName: "松明大哥",
                sex: "男"
            }, {
                stuName: "喻金大哥",
                sex: "男"
            }]
        },
        computed: {
            boyCount() {
                return this.stuList.filter(item => item.sex == "男").length;
            },
            girlCount() {
                return this.stuList.filter(item=>item.sex=="女").length;
            }
        }

    });
</script>

下面是一个经典的案例

<body>
    <div id="app">
        <table class="table-box">
            <tr>
                <th>编号</th>
                <th>名称</th>
                <th>单价</th>
                <th>数量</th>
                <th>总价</th>
            </tr>
            <tr v-for="(item,index) in shopCartList" :key="index">
                <td>{{item.gid}}</td>
                <td>{{item.gname}}</td>
                <td>{{item.price}}</td>
                <td style="text-align: center;">
                    <button type="button" @click="item.count--" v-show="item.count>0">-</button>
                    {{item.count}}
                    <button type="button" @click="item.count++">+</button>
                </td>
                <td>{{item.price * item.count}}</td>
            </tr>
            <tr>
                <td>合计:</td>
                <td colspan="4">{{totalMoney}}元</td>
            </tr>
        </table>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el:"#app",
        data:{
            shopCartList:[
                {gid:"g01",gname:"华为mate 50手机",price:1999,count:1},
                {gid:"g02",gname:"充电宝",price:200,count:2},
                {gid:"g03",gname:"耳机",price:35,count:3},
                {gid:"g04",gname:"数据线",price:18,count:5},
                {gid:"g05",gname:"电脑",price:6189,count:1},
            ]
        },
        computed:{
            totalMoney(){
                return this.shopCartList.reduce((prev,current,index,_arr)=>{
                    return prev + current.price * current.count;
                },0);
            }
        }
    })
</script>

image.png

八、vue侦听器

vue里面的侦听器也叫属性监听,它可以监控某一个属性值的变化,然后根据这个变化做出后续的处理

这个东西与我们之前所学过的Object.defineProperty当中的get/set很像

1. 普通侦听


<body>
    <div id="app">
        <input type="text" v-model="age">
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            age: 18,
        },
        watch: {
            //我在监控age这个属性,当这个属性值发生变化以后,触发这个方法
            age(newValue, oldValue) {
                console.log("新的值为" + newValue);
                console.log("旧的值为" + oldValue);
            }
        }

    })
</script>

上面的代码就是一个最简单的监听属性(侦听器),它监听了age的变化

在侦听器方法里面可以接收两个参数,第一个参数是新的值,第二个参数是原来的值

普通侦听器只是侦听到了栈里面的变化

上面的这种侦听器只是一种普通的侦听,它只能够进行基本数据类型的侦听,如果是对象则侦听不到。原因是因为普通侦听器只监控栈,如果要监控到堆的变化则必须使用深度监听

2. 深度侦听

深度侦听器是一个对象

<body>
    <div id="app">
        <input type="text" v-model="userInfo.age">
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            userInfo: {
                age: 18
            }
        },
        watch: {
            userInfo: {
                handler(newValue) {
                    console.log("新的值",newValue);
                },
                deep: true
            }
        }

    })
</script>

深度侦听必须是一个对象,这个对象的内部的handler的方法是用于处理变化以后的操作,deep:true代表当前执行深度侦听

九、vue修饰符

修饰符也叫事件修饰符,我们在第5个章节讲到了vue里面的事件,但那只是基础,如果要深入的使用事件,修饰符是必不可少的

<body>
    <div id="app">
        <div class="box" @click="a">
            <button type="button" @click.stop="b">按钮</button>
        </div>

        <button type="button" @mousedown.left="a">又一个按钮</button>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            userInfo: {
                age: 18
            }
        },
        methods: {
            a() {
                console.log("我是a方法");
            },
            b() {
                console.log("我是b方法");
            }
        }


    })
</script>

事件修饰符可以极大的提高我们的操作

针对于键盘的修饰符

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

针对于系统的

  • .ctrl
  • .alt
  • .shift
  • .meta

针对于鼠标的

  • .left
  • .right
  • .middle

功能性的修饰符

  • .stop阻止事件冒泡
  • .prevent阻止事件的默认行为

系统修饰符可以和普通修饰符联合起来使用,如@click.ctrl=""@keydown.ctrl.enter

针对同一个事件的不同修饰符,可以绑定不同的方式

<input type="text" @keydown.up="a" @keydown.down="b">

十、vue样式class绑定

这个点应该与第七点做对比,因为class其实也是一个样式,但是class是一个非常特殊的属性,所以要单独的去讲解

vue里面的class绑定一般叫动态样式绑定,仍然执行v-bind:class,简写成:class,关键问题就在于这个属性值有两种绑定方式

1. 数组语法

 <ul>
     <li v-for="(item,index) in stuList" :key="index"
         class="list-item"
         :class="[index==2?'active':null]">
         姓名:{{item}}-----{{index}}
     </li>
</ul>

在上面的代码里面,我们可以看到,原始的class可以和动态的:class绑定在一起

<ul>
    <li v-for="(item,index) in stuList" :key="index"
        :class="[index==2?'active':null,index%2==0?'list-item':null]">
        姓名:{{item}}-----{{index}}
    </li>
</ul>

下面是一个经典的vue当中的动态绑定样式的例子

<body>
    <div id="app">
        <ul>
            <li v-for="(item,index) in stuList" :key="index"
                :class="[index==selectedIndex?'active':null]"
                @click="selectedIndex=index">
                {{item}}
            </li>
        </ul>
        <h2>{{stuList[selectedIndex]}}</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            stuList: ["杨佳琪", "陈欢欢", "刘紫微", "李光昊"],
            selectedIndex:0
        }
    })
</script>

image.png

下面是一个动态样式绑定的一个案例

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>class样式绑定</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            list-style-type: none;
        }

        #app {
            width: 100vw;
            height: 100vh;
            display: flex;
            flex-direction: column;
        }

        .top-nav {
            height: 45px;
            border-bottom: 1px solid lightgray;
            display: flex;
            justify-content: space-evenly;
        }

        .top-nav>li {
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            box-sizing: border-box;
        }

        .top-nav>li.active {
            color: tomato;
            font-weight: bold;
            border-bottom: 2px solid tomato;
        }

        .content-box {
            flex: 1;
            overflow: auto;
            position: relative;
        }

        .tab {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <div id="app">
        <ul class="top-nav">
            <li v-for="(item,index) in navTypeList" :key="index"
                :class="[index==selectedIndex?'active':null]"
                @click="selectedIndex=index">
                {{item}}
            </li>
        </ul>
        <div class="content-box">
            <div v-show="selectedIndex==0" class="tab" style="background-color: bisque;">这是关注的页面</div>
            <div v-show="selectedIndex==1" class="tab" style="background-color: lightblue;">这是推荐的页面</div>
            <div v-show="selectedIndex==2" class="tab" style="background-color: pink;">这是热榜的页面</div>
            <div v-show="selectedIndex==3" class="tab" style="background-color: orange;">这是武汉的页面</div>
            <div v-show="selectedIndex==4" class="tab" style="background-color: gray;">这是抗疫的页面</div>
        </div>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            navTypeList: ["关注", "推荐", "热榜", "武汉", "抗疫"],
            selectedIndex: 1
        }
    })
</script>

</html>
<!-- 
    数据驱动页面,你要改变页面,必然是改变了数据
 -->

image.png

2. 对象语法

对象语法与数组语法功能上面是一模一样的,只是写法上面不一样而已

语法

<标签 :class="{class名称:布尔值}"></标签>

这个属性值如果是true则启用这个样式,如果是false则不启动用这个样式

<style>
    ul>li {
        height: 40px;
        line-height: 40px;
        border: 1px solid lightgray;
        border-radius: 4px;
    }


    ul>li.active-1 {
        background-color: deeppink;
    }
    .list-item{
        font-weight: bold;
    }
</style>
<body>
    <div id="app">
        <ul>
            <li v-for="(item,index) in stuList" :key="index"
                :class="{'active-1':index==selectedIndex,'list-item':index%2==0}"
                @click="selectedIndex=index">
                {{item}}
            </li>
        </ul>
        <h2>{{stuList[selectedIndex]}}</h2>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            stuList: ["杨佳琪", "陈欢欢", "刘紫微", "李光昊"],
            selectedIndex: 0
        }
    })
</script>

十一、vue样式style绑定

它的绑定方式其实与上面的class绑定是一样的,它也有对象语法跟数组语法,但是它的对象语法与数组语法没啥本质区域

1. 对象语法

 <style>
     .box{
         width: 100px;
         height: 100px;
         border: 4px solid black;
     }

</style>
<body>
    <div id="app">
        <div class="box" :style="{backgroundColor:c}"></div>
        <hr>
        <ul>
            <li @click="c='red'">红色</li>
            <li @click="c='blue'">蓝色</li>
            <li @click="c='green'">绿色</li>
            <li @click="c='pink'">粉色</li>
        </ul>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el:"#app",
        data:{
            c:"yellow"
        }
    })
</script>

在上面的案例当中,我们可以看到,style后面属性值量 个变量,在发生变化,所以我们要使用动态的:style来绑定

<style>
    .progress-bar{
        width: 500px;
        height: 30px;
        border: 1px solid lightgray;
        border-radius: 15px;
        background-image: linear-gradient(to right,red,red);
        background-repeat: no-repeat;

    }
</style>
<body>
    <div id="app">
        <div class="progress-bar" :style="{backgroundSize:`${percent} 100%`}"></div>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el:"#app",
        data:{
            percent:"50%"
        }
    })
</script>

image.png

2.数组语法

数组语法本质上面与对象语法很像,就是把多个对象放在了一个数组里面

<style>
    .box {
        width: 200px;
        height: 200px;
        border: 5px solid black;
    }
</style>
<body>
    <div id="app">
        <div class="box" :style="[obj1,{backgroundColor:c}]">
            我是盒子
        </div>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            percent: "50%",
            obj1:{
                color:'red'
            },
            c:"blue"
        }
    })
</script>

这里要注意,有个易错点,有个本质点

重点

<body>
    <div id="app">
        <div class="box" :style="[obj1,{backgroundColor:c}]">
            我是盒子
        </div>
        <button type="button" @click="aaa">我要改变</button>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            percent: "50%",
            obj1: {
                color: 'red',
                marginLeft:"100px"
            },
            c: "blue"
        },
        methods: {
            aaa() {
                this.obj1.color = "white";
                // 当前的border-radius属性是动态添加的,原来没有
                // this.obj1.borderRadius = "50px";
                this.$set(this.obj1,"borderRadius","50px");

                //如果需要动态删除属性,vue也不推荐直接使用delete
                // delete this.obj1.marginLeft;
                this.$delete(this.obj1,"marginLeft");
            }
        }
    })
</script>

在上面的代码里面,如果vue的data对象里面需要动态的添加属性,那么,不建议直接扩展或删除,而应该使用下面的两个方法

  1. this.$set(target,propertyName,value)添加一个新的属性
  2. this.$delete(target,propertyName)删除一个属性

这两个方法主要的作用和就是用于后面如果新增的属性没有与页面实现双向绑定,就可以使用它们

十二、this.$set及this.$delete

案例

 <style>
     .box {
         width: 200px;
         height: 200px;
         border: 5px solid black;
         background-color: deeppink;
     }
</style>
<body>
    <div id="app">
        <button type="button" @click="aaa">我要改变</button>
        <div class="box" v-show="obj.flag">
            我是盒子
        </div>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            obj: {

            }
        },
        methods: {
            aaa() {
                //this.obj.flag = true;   //这里是没有效果的
                
                //下面的代码是有效果的
                this.$set(this.obj, "flag", true);
                console.log(this.obj)
            }
        }
    })
</script>

在上面的代码里同,我们使用v-show="obj.flag"来让元素显示,但是obj下面并没有flag属性,所以盒子默认被不显示

但是如果我们后期通过this.obj.flag = ture动态扩展一个属性,页面上面的盒子没有显示,这就是bug

为了解决这个问题,vue推荐如果是新加的属性要实现双向数据绑定则必须使用this.$set()来完成

关于原理,在vue的生命周期里面会讲到这一块

十三、vue过滤器

vue当中的过滤器称之为数据格式化工具,也称之为数据渲染的时候处理工具,它可以在数据渲染的时候二次处理数据

过渡器分为两种,一种是全局过滤器,一咱是局部过滤器,无论是哪种其实调用方法都是一样,这个全局和局部指的是后期的组件化开发里面使用的

1. 全局过滤器

全局过滤器使用Vue.filter("过滤器名称",方法名)来定义,调用的时候直接在数据渲染的过程当中使用| 过滤器名称即可


<body>
    <div id="app">
        <table class="table-box">
            <tr>
                <th>姓名</th>
                <th>性别</th>
                <th>生日</th>
            </tr>
            <tr v-for="(item,index) in stuList">
                <td>{{item.stuName}}</td>
                <td>{{item.sex}}</td>
                <td>{{item.birthday | formatDate}}</td>
            </tr>
        </table>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    /**
     * @param {Date} _d 要格式化的日期
     */
    function formatDate(_d) {
        //假设_d是一个日期对象
        let year = _d.getFullYear();
        let month = _d.getMonth() + 1;
        let date = _d.getDate();
        return `${year}年${month}月${date}日`;
    }

    Vue.filter("formatDate",formatDate);

    new Vue({
        el: "#app",
        data: {
            stuList: [{
                    stuName: "季强",
                    sex: "男",
                    birthday: new Date("2020-1-12")
                },
            ]
        }
    })
</script>

在上面的代码当中,我们可以看到,日期已经被格式化了

2. 局部过滤器

  /**
     * @param {Date} _d 要格式化的日期
     */
function formatDate(_d) {
    //假设_d是一个日期对象
    let year = _d.getFullYear();
    let month = _d.getMonth() + 1;
    let date = _d.getDate();
    return `${year}年${month}月${date}日`;
}

new Vue({
    el: "#app",
    data: {
        stuList: [{
            stuName: "季强",
            sex: "男",
            birthday: new Date("2020-1-12")
        },
                  {
                      stuName: "陈欢欢",
                      sex: "女",
                      birthday: new Date("1990-1-12")
                  },
                  {
                      stuName: "喻金",
                      sex: "男",
                      birthday: new Date("1998-3-3")
                  },
                  {
                      stuName: "杨佳琪",
                      sex: "男",
                      birthday: new Date("2001-12-24")
                  },
                  {
                      stuName: "松明大哥",
                      sex: "男",
                      birthday: new Date("2003-6-30")
                  },
                 ]
    },
    filters:{
        formatDate
    }
})

上面的代码就是局部过滤器,它可以在vue的内部通过属性filters来完成

3. 过滤器当中的参数

在上面的过滤器里面,我们可以看过滤器函数里面的第一个参数永远都是要处理的内容

function formatText(str,maxLength = 10) {
    //假设最多只显示10个字符
    if (str) {
        return str.length > 10 ? str.substr(0, maxLength) + "..." : str;
    } else {
        return "";
    }
}

Vue.filter("formatText",formatText);

在上面的过滤器里面,我定义了两个参数,第一个参数永远都是要处理的内容,从第二个参数开始就是调用过滤器的时候参数,如下

<td>{{item.desc | formatText(15)}}</td>

十四、vue的DOM操作

vue的本质是去DOM操作,但是为什么还会有dom操作的点呢?

因为vue不推荐设置DOM,但是某些特殊情况下,我们要获取dom元素的属性,如clientWidth/clientHeight,或offsetWidth/offsetHeight,及scrollWidth/scrollHeight

在原生的JS里面,如果我们要操作DOM,前提是获取DOM,原生JS里面使用document.querySelector/document.querySelectorAll等方法

1. 通过ref来获取DOM

<body>
    <div id="app">
        <h2 ref="pageTitle">这是一个标题</h2>
        <button type="button" @click="aaa">按钮</button>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            
        },
        methods: {
            aaa(){
                console.log(this.$refs["pageTitle"])
            }
        }
    })
</script>

所以标记了ref属性的DOM元素都可以后期在this.$refs里面找到

注意事项

v-for遍历批量生成的时候,ref有一点小小的区别


<body>
    <div id="app">
        <h2 v-for="(item,index) in txtList" ref="pageTitle">
            {{item}}
        </h2>
        <button type="button" @click="aaa">按钮</button>
    </div>
</body>
<script src="./js/vue.js"></script>
<script>
    new Vue({
        el: "#app",
        data: {
            txtList: ["张珊", "李四", "王五"]
        },
        methods: {
            aaa() {
                console.log(this.$refs["pageTitle"])
            }
        }
    })
</script>

只要是通过v-for来生成的元素,它通过this.$refs[xxx]得到的就是一个数组

2. 通过事件对象

通过触发事件,我们可以得到事件对象$event,而事件对象上面又可以获取事件的绑定者和触发者

<button type="button" @click="aaa($event)">按钮</button>
<script>
    new Vue({
        el: "#app",
        data: {
            txtList: ["张珊", "李四", "王五"]
        },
        methods: {
            aaa(event) {
                console.log(this.$refs["pageTitle"]);
                //通过事件对象,找到了事件的绑定者
                console.log(event.currentTarget);
            }
        }
    })
</script>
10
vue

评论区