总结下自己在vue2里面的重难点。(基础篇)

235 阅读8分钟

双向绑定

咱们直接,学过vue应该都知道声明式渲染——双向绑定v-model,这个通常同差值表达式{{}}一起使用,说多了也没用,如果我们的input框的type类型是text,那么所绑定的变量值就同里面输入的值一样,与input里面的value值就无关了,而如果type类型为是checkbox,那么就比较复杂了,直接看代码:

<template>
  <div id="app">
    <label><input v-model="message" type="checkbox" value="里面的值是叫花鸡" name="" id="">叫花鸡</label>
    <p>第一个:{{message}}</p>
    <label><input v-model="messages" type="checkbox" name="" id="">叫花鸡</label>
    <p>第二个:{{messages}}</p>
  </div>
</template>

<script>

export default {
  name: 'App',
  data(){
    return{
      //第一个是数组形式。
      message:[],
      //第二个是字符串形式。
      messages:""
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

从结果可以看出如果给变量定义的是字符串,那么无论你给input是否定义value属性,它的值始终都是truefalse,而如果变量定义的是数组,那么它的值是同value属性值相同。直接看下图:

8601346a0ad3825ee5a73c20f45dbb8.png

处理用户事件

其实事件绑定相信大家都很了解,说白了就是v-on:(事件绑定),例如:

<button v-on:click="add">按钮</button>
<!--上面的同下面的一样。--!>
<button @click="add">按钮</button>

这些都没啥,最主要的是你必须知道事件修饰符,看例子吧:

1.阻止冒泡事件

冒泡事件就是从当前节点出发,找到父亲节点并将其触发,并且会一直冒泡而直到html根元素为止。

<div @click.stop="fn2"></div>

2.捕获事件

与冒泡事件相反,它是从html根元素开始依次移动并触发到当前元素为止。

<div class="div2" @click.capture="fn2"></div>

3.阻止默认事件

<a href="https://example.com" @click.prevent="fn2">Click me</a>

上面这个例子非常好理解,大家应该知道超链接的作用就是导航到指定的url,但是我们我们使用了prevent修饰符,它会执行方法fn2,而不会导航到指定的url。

监听数据变化

看到这个题目,相信大家第一个想到的就是侦听器,它的用法也是相当地简单,直接看代码: 上面就是侦听器最简单的使用,即我们要监听的变量发生了变化——就会触发侦听器。但是这里我想说的重点就是侦听器的进阶使用。

侦听器的进阶使用

获取前一次的值

有时候我们想要获取前一次的值,这个也是相当滴简单哒,只需要在我们监听的变量里面添加参数即可,第一个参数是新值,第二个是旧值。

watch:{
  count(value,oldValue){
    let str = `count变量的旧值为${oldValue},新值为${value}`;
    let p = document.createElement('p');
    p.innerHTML = str;
    document.body.appendChild(p);
  }
}

动态绑定v-bind

有时候我们修改一些特性节点时不一定非得在html里面直接修改,这样显得代码非常的臃肿。我们可以使用v-bind动态绑定,可以简写为:,直接代码:

<template>
  <div id="app">
    <img src="#" v-bind:alt="imgText" />
  </div>
</template>

上面的alt属性就是当img没显示时,就会出现一行数据,这行数据就是alt的属性值。

<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            imgText:'周杰伦演唱会图片'
        };
    }
};
</script>

模板中使用表达式

模板中进行计算

<template>
  <div id="app">
    <ul>
      <li>{{ goods[0].index + 1 }}---{{ goods[0].name }}</li>
      <li>{{ goods[1].index + 1 }}---{{ goods[1].name }}</li>
      <li>{{ goods[2].index + 1 }}---{{ goods[2].name }}</li>
    </ul>
  </div>
</template>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            goods:[
                {
                    index:0,
                    name:"扫地机器人"
                },
                {
                    index:1,
                    name:"华为手机"
                },
                {
                    index:2,
                    name:"戴尔笔记本"
                }
            ]
        };
    }
};
</script>

模板中使用三元表达式

在差值表达式里面也可以使用三元表达式,直接看代码:

<template>
  <div id="app">
    <p>{{ flag?'你已经通过了考试':'你还没有通过考试' }}</p>
    <button @click="exchange">转换</button>
  </div>
</template>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            flag:true
        };
    },
    methods:{
        exchange(){
            this.flag = !this.flag;
        }
    }
};
</script>

在模板中写方法

<template>
  <div id="app">
    <p>{{ message.split('').reverse().join('') }}</p>
  </div>
</template>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            message:"优课达--学的比别人好一点~"
        };
    }
};
</script>

另外,在模板中也可以直接写js表达式,但是一般不要这样,因为会使得html代码显得臃肿。

条件渲染语句

里面的v-ifv-else以及v-else-if语句就不说了,直接看个例子理解一下:

<p v-if="questions[0].type === 'PICK'">{{ questions[0].content }}</p>
<p v-else-if="questions[1].type === 'MULT'">{{ questions[1].content }}</p>
<p v-else>题目还没有加载进来...</p>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            questions:[
                {
                    type:"PICK",
                    content:"这是一道选择题"
                },
                {
                    type:"MULT",
                    content:"这是一道多选题"
                },
                {
                    type:"ESSAY",
                    content:"这是一道论述题"
                }
            ]
        };
    }
};
</script>

我想说的重点是v-ifv-show的区别,它俩区别用两点就可以看出:

  • v-if指令是如果不满足条件的话,则此标签在dom中根本不存在。
  • v-show指令则是如果不满足条件,只是将标签的display属性设置为none。

列表渲染语句

vue里面的列表渲染核心就是v-for循环指令,我们直接看个简单的例子:

循环渲染数字

<div id="app">
    <ul>
        <li v-for="item in 5" :key="item">{{ item }}</li>
    </ul>
</div>

里面的:key属性就是Vue工程为了保证每个item都是唯一的,所以需要一个key,这个属性值一般都是从后台取到的数据的id,但是我们可以给它赋值为索引。

循环渲染数组

这里的v-for遍历数组对象和js的遍历数组是一样的,代码:

<ul>
<!--第一个参数item是成员属性值,第二个参数是成员索引-->
    <li v-for="(item,index) in nameList" :key="index">{{ item }}</li>
</ul>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            nameList:["张淮森","周逸依","梁澄静","宁古薄","丘约靖"]
        };
    }
};
</script>

循环渲染对象

渲染对象相较于渲染数组不同的是,成员变量变成了键值对,看代码:

<ul>
<!--
    value:对象的每一项的值,
    key:对象中每一项的键,这个一般不常用。
    index:索引
-->
    <li v-for="(value,key,index) in book" :key="index">值:{{ value }}--键:{{ key }}--索引:{{ index }}</li>
</ul>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            book:{
                bookName:'指环王',
                author:'JK 罗琳'
            }
        };
    }
};
</script>

遍历数组中的对象

遍历数组中的对象就更加简单了,看例子吧,简单理解:

<ul>
    <li v-for="(item,index) in books" :key="index">
        {{ index+1 }}----{{ item.title }}----{{ item.author }}----{{ item.publishedTime }}
    </li>
</ul>
<script>
export default {
    name: "app",
    // 数据
    data() {
        return {
            books: [
                {
                    title: '《魔戒》',
                    author: '约翰·罗纳德·瑞尔·托尔金',
                    publishedTime: '1954'
                },{
                    title:'《哈利·波特》',
                    author:'J·K·罗琳',
                    publishedTime:'1997'
                },{
                    title:'《人性的弱点》',
                    author:'戴尔•卡内基',
                    publishedTime:'2008'
                }
            ]
        };
    }
};
</script>

计算属性

这个学过的都知道,这东西和Methods很像,但是这个相较于后者一般都是用于差值表达式中,例子:

<div id="app">
  <p>原字符串:{{ message }}</p>
  <p>反转后的字符串:{{ reverseMessage() }}</p>
</div>
<script>
  export default {
    name: 'app',
    data: function () {
      return {
        message: '优课达--学的比别人好一点~',
      };
    },
    methods: {
      reverseMessage: function () {
        return this.message.split('').reverse().join('');
      },
    },
  };
</script>

这里我就必须说下计算属性的两个性质了:依赖缓存

  • 依赖:案例中的message就是计算属性的依赖。
  • 缓存:上一次计算得到的值。

这里我结合上面的代码示例解释一下:

计算属性computed

  • message发生变化(即依赖变化),reverseMessage会重新计算并返回计算结果。
  • message没有变化(即依赖没发生变化),reverseMessage会返回缓存的值,而不会去计算。

方法methods

  • 每次访问的时候,都会执行里面的方法逻辑,然后返回结果。

总的来说,计算属性明显性能更优,因为避免了不必要的代码执行。

动态class

动态绑定我在上面说过了,其实就是v-bind:,我接下来要说的是动态样式绑定,语法如下所示:

<!--下面的isActive就是一个在data里面的boolean属性值-->
<div class="base" v-bind:class="{ 'active': isActive }"></div>
.active {
  border: 1px solid green;
}

上面的引号规则可以用外单内双或者外双内单都是可以的。

<!-- 外双内单 -->
<div v-bind:class="{ 'base-active': isActive }"></div>
<!-- 外单内双 -->
<div v-bind:class='{ "base-active": isActive }'></div>

亦或者是多类名,即一个标签里面的class属性有多个值。

<div v-bind:class='{ "base-active": isActive,"base":true}'></div>

方法形式

我们在上面讲的都是变量形式,我现在需要说的是方法形式。说白了就是将里面的变量换为了方法,原本是返回变量的boolean值,而换成方法形式则是返回方法值,例如,下面的方法返回值类型就是boolean

<span :class="{ 'new-appear': isActive(item.type) }">新</span>
data:function(){
    return {
        liListData: [
            {
            imgUrl:'https://m.360buyimg.com/babel/jfs/t1/30057/19/14881/720/5cbf064aE187b8361/eed6f6cbf1de3aaa.png',
            text: '话费',
            type: 'NEW',
            },
        ]
    }
},
methods:{
    isActive: function(type) {
    if (type === 'NEW') {
        return true;
    }
    return false;
}
}

表达式形式

对于上面的代码感觉过于臃肿,我们直接使用表达式岂不是更简单,看代码:

<span :class="{ 'new-appear': item.type === 'NEW' }">新</span>

另外,我们也可以使用计算机属性的形式,我们可以变换一下:

<span :class="{ 'new-appear': hoverObj }">新</span>
computed: {
  hoverObj: function () {
    return {
      hover: this.index === 1,
    };
  },
},

动态样式绑定中的数组写法

我在上面说的都是关于对象的写法,那么数组的写法也是非常简单,直接往里面添加类名即可,如下:

<div v-bind:class="['red-style', 'font-style']"></div>

另外,在数组中还可以使用三元表达式,代码:

<div
  v-bind:class="['red-style', 'font-style',isChoosed ? 'redbg' : 'bluebg']"
></div>

最后,在数组里面仍然也可以使用对象,看代码:

<div v-bind:class="['red-style', 'font-style',{'redbg':isChoosed}]"></div>

动态style

我们上面讲的:class是外部样式,那么我接下来讲的:style则就是行内样式了。还是一样,我们先讲对象语法,再讲数组语法。

对象语法

<div :style="{background:'red',fontWeight:700,fontSize:'20px'}"></div>
/*大家仔细看里面的区别,*/
<div :style="{background:'red','font-weight':700,'font-size':'20px'}"></div>

但是,如果里面的样式过多了,那么就需要将动态样式给提取出来了,这样会使html代码显得很简洁。

<div :style="flexStyle"></div>
data:function(){
    return {
        flexStyle: {
            display: 'flex',
            flexDirection: 'column',
            justifyContent: 'space-between',
            alignItems: 'center',
            flexWrap: 'no-wrap',
            fontWeight: 700 ,
        },
    }
}

那么,如果我想设置一个如下面的例子,代码这样子写可以吗:

data:function(){
    return {
        bg: {
            background: `url(${imgList[currentIndex]}) no-repeat center / contain`,
        },
    }
}

答案明显是不能的,记住了,这个例子只能用下面的这样子写,如果我们写在data变量里面的话,即如果写成上面的那样,会报错,显示你的imgList未定义,这是因为此时的bg和imgList都属于全局变量,这里不能互相引用。

数组语法

数组语法同:class大同小异,但是同:class不同的一点就是它数组里面是变量,不需要加引号,而后者里面的是类名,需要加引号。

<div :style="[fontStyle,boxStyle]">这里是文字</div>
data() {
  return {
    fontStyle: { color: 'red', fontSize: '33px' },
    boxStyle:{width: '200px', height: '200px', border: `1px solid black`}
  };
},

这里面亦可以使用三元表达式,如下:

<div :style="[fontStyle, isActive ? boxStyle : colorBox]">这里是文字</div>

到这里,基本整理完毕。