Vue的基本使用

297 阅读14分钟

1. Vue是渐进式框架,什么是渐进式呢?

打一个不恰当的比喻,买房时可以选择精装房,或者只买一个空房,里面没有任何装饰。后面可以自己一步一步装修,需要什么家具就买什么家具。使用Vue框架就如同买空房,以后遇到需要的某项功能时,只需要按照特定的插件就可以了,而不是刚使用时就必须安装全套插件。

2. Vue.js安装

方式一:直接CDN引入

(你可以选择引入开发环境版本还是生产环境版本)

<!-- 开发环境版本,包含了有帮助的命令行警告 --> 
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

方式二:下载和引入

下载地址:

开发环境 vuejs.org/js/vue.js

生产环境 vuejs.org/js/vue.min.…

方式三:NPM安装

通过webpack和CLI的使用进行安装

3. Vue的初体验

展示单一数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
  <!-- 执行到这里时,显然出对应的HTML -->
    <h2>{{message}}</h2> 
    <h1>{{name}}</h1>
</div>

<div>{{message}}</div>
<!-- 引入vue.js -->
<script src="../js/vue.js"></script>
<script>
    // let(变量)/const(常量)
    // 编程范式: 声明式编程,比命令式编程更简单
   //执行到这里,创建Vue实例,并且对原HTML进行解析和修改
    const app = new Vue({
        el: '#app', // 用于挂载要管理的元素
        data: { // 定义数据
            message: '你好啊,CodingKid!',
            name: 'CodingKid'
        }
    })

    // 元素js的做法(编程范式: 命令式编程)
    // 1.创建div元素,设置id属性

    // 2.定义一个变量叫message

    // 3.将message变量放在前面的div元素中显示

    // 4.修改message的数据: 今天天气不错!

    // 5.将修改后的数据再次替换到div元素
</script>

</body>
</html>

展示列表(v-for)

  • 利用v-for进行迭代
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

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

<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊',
            movies: ['星际穿越', '大话西游', '少年派', '盗梦空间']
        }
    })
</script>

</body>
</html>
  • 取数组的索引值:v-for=(item, index) in array

  • 取对象的索引值和keyvaluev-for=(value, key, index) in obj

  • 官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性

    • n为什么需要这个key属性呢(了解)?

      • 这个其实和Vue的虚拟DOM的Diff算法有关系

      • 这里我们借用React's diff algorithm中的一张图来简单说明一下(上层结点为虚拟dom中的结点,下层结点为实际dom中的结点)

      • 当没有key时,虚拟dom结点按顺序与实际dom进行比对,看是否一致,不一致则对实际dom进行调整,由此当往中间插入(或改变)一个结点时,其后的结点都会改变

      • 当有key时,虚拟dom结点按key值与实际dom进行配对,故插入新结点时,其他结点不需要改变,不过key值需要**唯一****

        img

响应式

以上两种展示方式都是响应式的,当Vue实例中的data变化时,对应的dom中的内容也会随之改变

初探method(与v-on结合)

下面实现了一个简易计数器,v-on是为了监听,监听什么事件呢?毫无疑问click事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <h2>当前计数: {{counter}}</h2>
  <!-- 下面的实现没有错误,但是监听事件后需要很多操作时,这样写就不方便了 -->
    <!--<button v-on:click="counter++">+</button>-->
    <!--<button v-on:click="counter--;">-</button>-->
    <button v-on:click="add">+</button>
    <button v-on:click="sub">-</button>
    <!--下面是语法糖写法-->
    <!--<button @click="sub">-</button>-->
</div>

<script src="../js/vue.js"></script>
<script>
    // 语法糖: 简写
    // proxy
    const obj = {
        counter: 0,
        message: 'abc'
    }

    new Vue()

    const app = new Vue({
        el: '#app',
        data: obj,
        methods: {
            add: function () {
                console.log('add被执行');
                this.counter++
            },
            sub: function () {
                console.log('sub被执行');
                this.counter--
            }
        }
    })
</script>

</body>
</html>

4.Vue中的MVVM(Model-View-ViewModel)

什么是MVVM呢?

维基百科传送门MVVM

Vue的MVVM

image-20200727172947118

View层(视图层)

  • 在我们前端开发中,通常就是DOM层。
  • 主要的作用是给用户展示各种信息。

Model层(数据层)

  • 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。

  • 在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。

  • VueModel层(视图模型层)

  • 视图模型层

  • 视图模型层是View和Model沟通的桥梁。

  • 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中

  • 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。

5.Vue实例中的Option

  • 官方文档中的介绍,点这里

  • 目前需要掌握的:

    • el:

      • 类型:string | HTMLElement
      • 作用:决定之后Vue实例会管理哪一个DOM
    • data:

      • 类型:Object | Function (组件当中data必须是一个函数)
      • 作用:Vue实例对应的数据对象。
    • methods:

      • 类型:{ [key: string]: Function }
      • 作用:定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用。

6.Vue的生命周期

示意图

示意图

7.基础语法

插值操作

  • Mustache语法

  • v-once

    • p该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
    • 该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变
  • v-html

    • 某些情况下,我们从服务器请求到的数据本身就是一个HTML代码,p如果我们直接通过{{}}来输出,会将HTML代码也一起输出。但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。
    • 可以使用v-html指令
    • 该指令后面往往会跟上一个string类型
    • 会将string的html解析出来并且进行渲染 image-20200727194227961.png
  • v-text

    • nv-text作用和Mustache一致
    • nv-text通常情况下,接受一个string类型,可以是vue实例data中的变量,最后会在浏览器中渲染出来
  • v-pre

    • v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本
  • v-cloak

    • 这个指令保持在元素上直到关联实例结束编译。
    • 和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
    • 防止HTML 绑定 Vue实例,在页面加载时闪烁(闪烁原因:在形成Vue实例时,Vue重新解析页面,导致之前加载的值发生变化,渲染的内容也改变了,所以会有闪烁的情况)

绑定属性

  • v-bind
    • v-bind用于绑定属性值,如图片的链接src、网站的链接href、动态绑定一些类、样式等等,也可以绑定value,也称为值绑定
    • 向另一个组件传递props值(这个复习到组件时再介绍)

绑定class的两种方式

  • 对象语法

    • 用法一:直接通过{}绑定一个类

      <h2 :class="{'active': isActive}">Hello World</h2>
      
    • 用法二:也可以通过判断,传入多个值

      <h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2>
      
    • 用法三:和普通的类同时存在,并不冲突

      <!--如果isActive和isLine都为true,那么会有title/active/line三个类-->
      <h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>
      
  • 数组语法

    • 用法一:直接通过[]绑定一个类

      <h2 :class="['active']">Hello World</h2>
      
    • 用法二:也可以传入多个值

      <h2 :class="['active', 'line']">Hello World</h2>
      
    • 用法三:和普通的类同时存在,并不冲突

      <!--注:会有title/active/line三个类-->
      <h2 class="title" :class="['active', 'line']">Hello World</h2>
      
  • 放在一个methods或者computed中(多学一种)

    <!--classes是一个计算属性-->
    <h2 class="title" :class="classes">Hello World</h2>
    

    在写CSS属性名的时候,比如font-size

    我们可以使用驼峰式 (camelCase) fontSize

    p或短横线分隔 (kebab-case,记得用单引号括起来) ‘font-size’

绑定style的两种方式

  • 对象语法

    • style后面跟的是一个对象类型
  • 对象的key是CSS属性名称

    • 对象的value是具体赋的值,值可以来自于data中的属性
    <div v-bind:style="{color: currentColor, fontSize: fontSize + 'px'}"></div>
    
  • 数组语法

    • style后面跟的是一个数组类型,数组元素为对象类型

      <div id="app">
        <h2 :style="[baseStyle, baseStyle1]">{{message}}</h2>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            message: '你好啊',
            baseStyle: {backgroundColor: 'red'},
            baseStyle1: {fontSize: '100px'},
          }
        })
      </script>
      

计算属性(computed)

  • 每个计算属性都包含一个getter和一个setter

  • 使用计算属性时,其后之所以不用加()是因为会自动调用get()方法,返回相应的值

  • 当给计算属性赋值时,会调用set(value)方法,并把赋予的值传递给value

  • 由于计算属性常用来计算,所以set()方法不常用,故可使用简略写法,从而显得和methods中的方法很相似,但仍然是一个属性,不是方法,是一个只读属性

示例:

data: {
      firstName: 'Kobe',
      lastName: 'Bryant'
    },
computed: {
  		// 常规写法  fullName只读
      // fullName: function () {
      //   return this.firstName + ' ' + this.lastName
      // }
			
  		// 完整写法 fullName可读,可写
      fullName: {
        set: function(newValue) { //当执行 fullName = 'Value' 时,会把Value传给newValue
          console.log(newValue);
        },
        get: function () {
          return this.firstName + ' ' + this.lastName
        }
      }
    }
  • 计算属性会进行缓存,如果多次使用时,计算属性只会调用一次,而多次使用methods中的方法时,会重复调用,当然当其中涉及到的数据发生改变时,计算属性也是响应式的,也就是get()函数可以监听函数体中变量的变化

事件监听

  • v-on基础:在前面的小节中:初探method(与v-on结合)

  • v-on参数

    • 如果该方法不需要额外参数,那么方法后的()可以不添加

    • 如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去

    • 如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件

      <div id="app">
        <!--1.事件调用的方法没有参数-->
        <button @click="btn1Click()">按钮1</button>
        <button @click="btn1Click">按钮1</button>
      
        <!--2.在事件定义时, 写方法时省略了小括号, 但是方法本身是需要一个参数的, 这个时候, Vue会默认将浏览器生产的event事件对象作为参数传入到方法-->
        <!--<button @click="btn2Click(123)">按钮2</button>-->
        <!--<button @click="btn2Click()">按钮2</button>-->
        <button @click="btn2Click">按钮2</button>
      
        <!--3.方法定义时, 我们需要event对象, 同时又需要其他参数-->
        <!-- 在调用方式, 如何手动的获取到浏览器参数的event对象: $event-->
        <button @click="btn3Click(abc, $event)">按钮3</button>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            message: '你好啊',
            abc: 123
          },
          methods: {
            btn1Click() {
              console.log("btn1Click");
            },
            btn2Click(event) {
              console.log('--------', event);
            },
            btn3Click(abc, event) {
              console.log('++++++++', abc, event);
            }
          }
        })
      
        // 如果函数需要参数,但是没有传入, 那么函数的形参为undefined
        // function abc(name) {
        //   console.log(name);
        // }
        //
        // abc()
        //而在v-on中如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
      </script>
      
  • v-on修饰符

    • .stop -调用event.stopPropagation(), 阻止事件冒泡

    • .prevent - 调用 event.preventDefault(),阻止默认事件

    • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调

    • .native - 监听组件根元素的原生事件

    • .once - 只触发一次回调

      <div id="app">
        <!--1. .stop修饰符的使用,点击button,防止冒泡到div-->
        <div @click="divClick">
          <button @click.stop="btnClick">按钮</button>
        </div>
      
        <!--2. .prevent修饰符的使用,阻止提交按钮的默认事件-->
        <br>
        <form action="baidu">
          <input type="submit" value="提交" @click.prevent="submitClick">
        </form>
      
        <!--3. .KeyAlias修饰符的使用,监听某个键盘的键帽,此时监听回车键-->
        <input type="text" @keyup.enter="keyUp">
      
        <!-- 4. .native-修饰符的使用  假如cpn标签是一个组件,则必须加上.native才能触发事件-->
        <cpn @click.native="btn2Click"></cpn>
      
        <!--5. .once修饰符的使用,只有第一次点击button的时候有用-->
        <button @click.once="btn3Click">按钮2</button>
      </div>
      

条件指令

nv-ifv-else-ifv-else的使用

  • Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件

  • v-if后面的条件为false时,对应的元素以及其子元素不会渲染

  • 也就是根本没有不会有对应的标签出现在DOM中

    <!-- 用法和普通语言的if...else if... else相似,如当成绩为99时,显示优秀 -->
    <div id="app">
      <h2 v-if="score>=90">优秀</h2>
      <h2 v-else-if="score>=80">良好</h2>
      <h2 v-else-if="score>=60">及格</h2>
      <h2 v-else>不及格</h2>
    </div>
    
  • 案例

    <div id="app">
      <!-- v-if -->
      <span v-if="isUser">
        <label for="username">用户账号</label>
        <input type="text" id="username" placeholder="用户账号" key="username">
      </span>
      <!-- v-else -->
      <span v-else>
        <label for="email">用户邮箱</label>
        <input type="text" id="email" placeholder="用户邮箱" key="email">
      </span>
      <button @click="isUser = !isUser">切换类型</button>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          isUser: true
        }
      })
    </script>
    
    • input没加key属性之前,会出现一个小问题
      • 切换了类型,我们会发现文字依然显示之前的输入的内容
      • 但是按道理讲,我们应该切换到另外一个input元素中了
      • 在另一个input元素中,我们并没有输入内容
    • 问题解答
      • 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素,否则dom树会改变,消耗性能
      • 在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了
    • 解决方案
      • p如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key,表示需要创建一个新的标签
      • p并且我们需要保证key的不同
  • v-show的对比

    • v-if当条件为false时,压根不会有对应的元素在DOM中
    • v-show当条件为false时,仅仅是将元素的display属性设置为none而已
    • 当需要在显示与隐藏之间切片很频繁时,使用v-show(出于性能的考虑,否则dom树会频繁改变)
    • 当只有一次切换时,通过使用v-if

表单绑定:v-model的使用

Vue中使用v-model指令来实现表单元素和数据的双向绑定

<div id="app">
  <input type="text" v-model="message">
  <h2>{{message}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: 'CodingKid'
    }
  })
</script>

当表单中输入值时,v-model会实时监听,并将message修改成和表单对应的值,因此h2标签显示的内容和表单中的内容一致,因此当页面的内容改变时会影响模型中的data数据,data数据的改变也会显示在页面,故实现了双向绑定。

  • 原理(通过v-bindv-on来理解)

    <div id="app">
      <input type="text" :value="message" @input="message = $event.target.value">
      <h2>{{message}}</h2>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          message: 'CodingKid'
        }
      })
    </script>
    
  • v-modelradio类型结合

    首先说一下radio的默认特性,当多个radio都有name属性,且一样时,为单选框,也就是只可选中其中一个,当name属性的值一致或者没有name属性时,每个radio都是独立的,也就是可以同时选中

    • 使用v-model会改变radio的特性,只要v-model指定了相同的变量时,radio不管有没有name属性,或者name的值是否一样,每个radio都是想关联的,也会是只能选中其中一个,radio主要的作用也是如此

      <div id="app">
        <!-- 即使没有name属性,这两个radio也是相关联的,只能选中其中一个 -->
        <label for="male">
          <input type="radio" id="male" value="男" v-model="sex"></label>
        <label for="female">
          <input type="radio" id="female" value="女" v-model="sex"></label>
        <h2>您选择的性别是: {{sex}}</h2>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            message: '你好啊',
            sex: '女'
          }
        })
      </script>
      
  • v-modelcheckbox类型结合

    checkbox作用就是多选,名字也叫做复选框,不过当只有一个 复选框时,也能当单选框使用,但不能像radio一样,有多个复选框时,能实现只选中一个并取消其他选中的功能

    • 当多个checkbox的v-model绑定一个变量时,当该变量是数组类型,则选中一个复选框,就会把一个复选框的value加入数组

    • 注意:当v-model类型绑定的不是数组时,v-model会强行将变量类型改成布尔类型,也就是只有true和false,因为全部的checkbox全部都绑定了这个变量,于是当一个checkbox选中时,变量的值为true,所有的checkbox全会变成选中状态,同理,当取消如何一个checkbox的选中状态时,全部的checkbox全会取消选中状态(此时checkbox中的value值不起作用)

    • 由上面两点知,v-model所绑定变量的类型会影响其所实现的功能

      <div id="app">
        <!-- 1.checkbox单选框-->
        <label >
          <input type="checkbox" v-model="isAgree" >同意协议
        </label>
        <h2>您选择的是: {{isAgree}}</h2>
        
        <!-- 2.checkbox多选框 -->
        <input type="checkbox" value="篮球" v-model="hobbies">篮球
        <input type="checkbox" value="足球" v-model="hobbies">足球
        <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
        <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
        <h2>您的爱好是: {{hobbies}}</h2>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            message: '你好啊',
            isAgree: false, // 单选框 只要数据类型不是数组,就会变成boolean类型
            hobbies: [] // 多选框,必须是数组类型,否则会变成boolean类型,导致checkbox中的value不起作用
          }
        })
      </script>
      
  • v-modelselect类型结合

    • select与checkbox比较类似,但v-model所绑定的类型不会影响多选的功能实现,当其不为数组时,会强制转换成数组,因为select中有multiple属性决定了其必须为多选

      <div id="app">
        <!--1.选择一个-->
        <select name="abc" v-model="fruit">
          <option value="苹果">苹果</option>
          <option value="香蕉">香蕉</option>
          <option value="榴莲">榴莲</option>
          <option value="葡萄">葡萄</option>
        </select>
        <h2>您选择的水果是: {{fruit}}</h2>
      
        <!--2.选择多个-->
        <select name="abc" v-model="fruits" multiple>
          <option value="苹果">苹果</option>
          <option value="香蕉">香蕉</option>
          <option value="榴莲">榴莲</option>
          <option value="葡萄">葡萄</option>
        </select>
        <h2>您选择的水果是: {{fruits}}</h2>
      </div>
      
      <script src="../js/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            message: '你好啊',
            fruit: '香蕉',
            fruits: [] //不为数组时,会强行转换成数组
          }
        })
      </script>
      
  • v-model的修饰符

    • lazy修饰符

      • 默认情况下,v-model默认是在input事件中同步输入框的数据的
      • 也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变
      • lazy修饰符可以让数据在失去焦点或者回车时才会更新
    • number修饰符

      • 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理
      • 但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理
      • number修饰符可以让在输入框中输入的内容自动转成数字类型
    • trim修饰符

      • 如果输入的内容首尾有很多空格,通常我们希望将其去除

      • ptrim修饰符可以过滤内容左右两边的空格

    <div id="app">
      <!--1.修饰符: lazy-->
      <input type="text" v-model.lazy="message">
      <h2>{{message}}</h2>
    
      <!--2.修饰符: number-->
      <input type="number" v-model.number="age">
      <h2>{{age}}-{{typeof age}}</h2>
    
      <!--3.修饰符: trim-->
      <input type="text" v-model.trim="name">
      <h2>您输入的名字:{{name}}</h2>
    </div>
    
    <script src="../js/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          message: 'Ki',
          age: 0,
          name: ''
        }
      })
    </script>
    

    写在最后

    • 码字不易,点赞鼓励
    • 此文为本人学习Vue的总结,适合有一定vue基础的人阅读
    • 希望广大读者斧正
    • 之后会继续更新的,有兴趣的来波关注吧!