1. vue简介

1.1 vue是什么

官网:https://cn.vuejs.org/

 

Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

1.2 vue的特点

1) 遵循 MVVM 模式

2) 编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发

3) 它本身只关注 UI, 可以轻松引入 vue 插件或其它第三库开发项目

1.3 与其它前端js框架的关联

1) 借鉴 angular 的模板和数据绑定技术

2) 借鉴 react 的组件化和虚拟 DOM 技术

1.4 vue拓展插件

  • vue-cli: vue 脚手架

  • vue-resource(axios): ajax 请求

  • vue-router: 路由

  • vuex: 状态管理

  • vue-lazyload: 图片懒加载

  • vue-scroller: 页面滑动相关

  • mint-ui: 基于 vue 的 UI 组件库(移动端)

  • element-ui: 基于 vue 的 UI 组件库(PC 端)

2. 基本使用

2.1 hello world

<body>
​
<!--
  1. 引入Vue.js
  2. 创建Vue对象
    el : 指定根element(选择器)
    data : 初始化数据(页面可以访问)
  3. 双向数据绑定 : v-model
  4. 显示数据 : {{xxx}}
-->
​
<!--模板-->
<div id="test">
  <input type="text" v-model="msg"><br><!--指令-->
  <input type="text" v-model="msg"><!--指令-->
  <p>hello {{msg}}</p><!--大括号表达式-->
</div>
​
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
  const vm = new Vue({ // 配置对象 options
    // 配置选项(option)
    el: '#test',  // element: 指定用vue来管理页面中的哪个标签区域
    data: {
      msg: 'world'
    }
  })
</script>
</body>

2.2 调试工具

在Chrome或Firefox浏览器的扩展插件仓库里搜vue devtool,安装Vue.js devtools.

打开vue项目,在控制台选择vue,操作组件查看信息变化。

 

2.3 vue的MVVM

 

MVVM分为三个部分:分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制器) 1、 M:模型层,主要负责业务数据相关; 2、 V:视图层,顾名思义,负责视图相关,细分下来就是html+css层; 3、 VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;

MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦。

3. 模块语法

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。

双大括号表达式

语法: {{exp}}

功能: 向页面输出数据 ,可以调用对象的方法

指令一:强制数据绑定

功能: 指定变化的属性值

完整写法: v-bind:xxx='yyy' //yyy 会作为表达式解析执行

简洁写法: :xxx='yyy'

指令二:绑定事件监听

1) 功能: 绑定指定事件名的回调函数

完整写法整洁写法
v-on:keyup='xxx'@keyup='xxx'
v-on:keyup.enter='xxx'@keyup.enter='xxx'

案例演示

<div id="app">
  <h2>1. 双大括号表达式</h2>
  <p>{{content}}</p>
  <p>{{content.toUpperCase()}}</p>
​
  <h2>2. 指令一: 强制数据绑定</h2>
  <a v-bind:href="url">访问指定站点1</a><br>
  <a :href="url">访问指定站点2</a><br>
​
  <h2>3. 指令二: 绑定事件监听</h2>
  <button v-on:click="test">点我</button>
  <button @click="test2('詹姆斯')">点我</button>
  <!--<button @click="test2(content)">点我</button>-->
</div>
​
​
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
  new Vue({
    el: '#app',
    data: {
      content: 'NBA I Love This Game',
      url: 'http://www.baidu.com'
    },
    methods: {
      test () {
        alert('湖人总冠军!')
      },
      test2 (content) {
        alert('你好,'+content);
      }
    }
  })
</script>

效果如下:

 

点击链接都能跳转,点击按钮都能触发alert事件。

4.计算属性和监听属性

4.1 计算属性computed

在vue应用中,在模板中双向绑定一些数据或者表达式,但是表达式如果过长,或者逻辑更为复杂时,就会变得臃肿甚至难以维护和阅读。所以在遇到复杂的逻辑时应该使用计算属性。

  • computed计算属性是用来声明式的描述一个值依赖了其它的值,当所依赖的值或者变量改变时,计算属性也会跟着改变;

  • computed根据一个现有数据去生成一个新数据,并且这两个数据会永久的建立关系,还会建立缓存,当无关数据改变的时候,不会重新计算而是直接使用缓存中的值;

  • 我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。

<div id="app">
  <p>原始字符串: {{ message }}</p>
  <p>计算后反转字符串: {{ reversedMessage }}</p>
</div>
 
<script>
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Runoob!'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  },
  methods: {
    reversedMessage2: function () {
      return this.message.split('').reverse().join('')
    }
  }
})
</script>

4.2 监听属性watch

1) 通过 vm 对象的$watch()或 watch 配置来监视指定的属性

2) 当属性变化时, 回调函数自动调用, 在函数内部进行计算

<div id="demo">
    姓: <input type="text" placeholder="First Name" v-model="firstName"><br>
    名: <input type="text" placeholder="Last Name" v-model="lastName"><br>
    姓名(单向): <input type="text" placeholder="Full Name" v-model="fullName"><br>
</div>
​
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
    const vm = new Vue({
        el: '#demo',
        data: {
            firstName: 'A',
            lastName: 'B',
            fullName: 'A-B'
        },
​
        watch: {
            // 配置监视firstName
            firstName: function (value) { // 相当于属性的set
                console.log('watch firstName', value);
                // 更新fullName2  this相当于vm对象
                this.fullName = value + '-' + this.lastName
            }
        }
    });
​
    // 监视lastName
    vm.$watch('lastName', function (value) {
        console.log('$watch lastName', value);
        // 更新fullName2
        this.fullName = this.firstName + '-' + value
    })
​
</script>

我们有这样一个功能,我们可以输入姓和名,然后另一个输入框要实时拼接姓和名。我们可以用watch机制来实现。

我们监视姓和名两个变量,每次有改变,则自动触发watch对应的方法,执行逻辑。

 

4.3 computed setter

computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

<div id="demo">
  姓: <input type="text" placeholder="First Name" v-model="firstName"><br>
  名: <input type="text" placeholder="Last Name" v-model="lastName"><br>
  姓名(双向): <input type="text" placeholder="Full Name3" v-model="fullName"><br>
</div>
​
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
    const vm = new Vue({
        el: '#demo',
        data: {
            firstName: 'A',
            lastName: 'B'
        },
​
        // 计算属性配置: 值为对象
        computed: {
            fullName: {
                // 当获取当前属性值时自动调用, 将返回值(根据相关的其它属性数据)作为属性值
                get() {
                    console.log('fullName3 get()')
                    return this.firstName + '-' + this.lastName
                },
                // 当属性值发生了改变时自动调用, 监视当前属性值变化, 同步更新相关的其它属性值
                set(value) {
                    console.log('fullName3 set()', value)
                    // 更新firstName和lastName
                    const names = value.split('-')
                    this.firstName = names[0];
                    this.lastName = names[1];
                }
            }
        }
    })
</script>

效果如下:

 

5.样式绑定

class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性。

Vue.js v-bind 在处理 class 和 style 时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。

5.1 class

class属性绑定有三种情况:

  <p :class="myClass">xxx是字符串</p>
  <p :class="{classA: hasClassA, classB: hasClassB}">xxx是对象</p>
  <p :class="['classA', 'classB']">xxx是数组</p>
​
   <!--点击更新按钮 第二个p标签会实现classA和classB样式的来回切换 -->
  <button @click="update">更新</button>
​
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      myClass: 'classA',
      hasClassA: true,
      hasClassB: false,
      activeColor: 'red',
      fontSize: '20px'
    },
​
    methods: {
      update () {
        this.hasClassA = !this.hasClassA;
        this.hasClassB = !this.hasClassB;
      }
    }
  })
</script>

5.2 内联样式

我们可以在 v-bind:style 直接设置样式:

<div id="app">
    <div :style="{ color: activeColor, fontSize: fontSize + 'px' }">湖人总冠军</div>
</div>
​
<script type="text/javascript">
    new Vue({
      el: '#app',
      data: {
        activeColor: 'green',
        fontSize: 30
      }
    })
<script type="text/javascript">

以上实例div为:

<div style="color: green; font-size: 30px;">湖人总冠军</div>

也可以直接绑定到一个样式对象,让模板更清晰:

<div id="app">
  <div v-bind:style="styleObject">湖人总冠军</div>
</div>
​
<script type="text/javascript">
    new Vue({
      el: '#app',
      data: {
        styleObject: {
          color: 'green',
          fontSize: '30px'
        }
      }
    })
<script type="text/javascript">

v-bind:style 可以使用数组将多个样式对象应用到一个元素上:

<div id="app">
  <div v-bind:style="[baseStyles, overridingStyles]">湖人总冠军</div>
</div>
​
<script type="text/javascript">
    new Vue({
      el: '#app',
      data: {
        baseStyles: {
          color: 'green',
          fontSize: '30px'
        },
        overridingStyles: {
          'font-weight': 'bold'
        }
      }
    })
<script type="text/javascript">

6. v-if和v-show

相同点:v-if与v-show都可以动态控制dom元素显示隐藏

不同点:v-if显示隐藏是将dom元素整个添加或删除,而v-show隐藏则是为该元素添加css--display:none,dom元素还在。

如果需要频繁切换使用 v-show 较好

<div id="demo">
  <p v-if="ok">表白成功</p>
  <p v-else>表白失败</p>
​
  <hr>
  <p v-show="ok">求婚成功</p>
  <p v-show="!ok">求婚失败</p>
​
  <button @click="ok=!ok">切换</button>
</div>
​
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      ok: true,
    }
  })
</script>

页面渲染如下:

 

我们也可以用v-else-if进行链式调用

<div id="app">
    <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
</div>
    
<script>
new Vue({
  el: '#app',
  data: {
    type: 'C'
  }
})
</script>

7. 列表渲染

7.1 列表展示

我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。

<ul id="example-1">
  <li v-for="item in items" :key="item.message">
    {{ item.message }}
  </li>
</ul>
​
<script>
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})
</script>

v-for 块中,我们可以访问所有父作用域的 property。v-for 还支持一个可选的第二个参数,即当前项的索引。

  <ul>
    <li v-for="(p, index) in persons" :key="index">
      {{index}}--{{p.name}}--{{p.age}}
    </li>
  </ul>
​
<script>
  new Vue({
    el: '#demo',
    data: {
      persons: [
        {name: 'Tom', age:18},
        {name: 'Jack', age:17},
        {name: 'Bob', age:19},
        {name: 'Mary', age:16}
      ]
    }
</script>

你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:

<div v-for="item of items"></div>

7.2 列表更新和删除

Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()

  • pop()

  • shift()

  • unshift()

  • splice()

  • sort()

  • reverse()

下面基于上面的代码演示一下:

    <button @click="deleteP(index)">删除</button>
    <button @click="updateP(index, {name:'Cat', age: 16})">更新</button>
​
    methods: {
      deleteP (index) {
        this.persons.splice(index, 1) 
              // 调用的不是原生数组的splice(), 而是一个变异(重写)方法
              // 1. 调用原生的数组的对应方法
              // 2. 更新界面
      },
​
      updateP (index, newP) {
        console.log('updateP', index, newP)
        this.persons.splice(index, 1, newP)
      },
​
      addP (newP) {
        this.persons.push(newP)
      }
    }

7.3 显示过滤/排序后的结果

有时,我们想要显示一个数组经过过滤排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。

我们实现一个案例:展示姓名和年龄的数组列表。同时可以按照姓名筛选和年龄排序。

<div id="demo">
  姓名:<input type="text" v-model="searchName">
  <ul>
    <li v-for="(p, index) in filterPersons" :key="index">
      {{index}}--{{p.name}}--{{p.age}}
    </li>
  </ul>
  <div>
    <button @click="setOrderType(2)">年龄升序</button>
    <button @click="setOrderType(1)">年龄降序</button>
    <button @click="setOrderType(0)">原本顺序</button>
  </div>
</div>
​
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript">
  new Vue({
    el: '#demo',
    data: {
      searchName: '',
      orderType: 0, // 0代表不排序, 1代表降序, 2代表升序
      persons: [
        {name: 'Tom', age:18},
        {name: 'Jack', age:17},
        {name: 'Bob', age:19},
        {name: 'Mary', age:16},
        {name: 'Tim', age:16},
      ]
    },
​
    computed: {
      filterPersons () {
        // 取出相关数据
        const {searchName, persons, orderType} = this;
        let arr = [...persons];
        // 过滤数组
        if(searchName.trim()) {
          arr = persons.filter(p => p.name.indexOf(searchName)!==-1)
        }
        // 排序
        if(orderType) {
          arr.sort(function (p1, p2) {
            if(orderType===1) { // 降序
              return p2.age-p1.age
            } else { // 升序
              return p1.age-p2.age
            }
​
          })
        }
        return arr
      }
    },
​
    methods: {
      setOrderType (orderType) {
        this.orderType = orderType
      }
    }
  })
</script>

效果图如下:

 

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐