Vue - 基础

介绍

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

简单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>简单示例</title>
</head>
<body>
<div id="app">
{{ message }}
<ul>
<li v-for="item in list">
{{ item }}
</li>
</ul>
<button v-on:click="changeListVal()">
改变list的值
</button>
</div>
</body>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: "#app",
data: {
message: "Hello Vue!",
list: ["aaa", "bbb", "ccc"]
},
methods: {
changeListVal() {
this.list = ["ddd", "eee", "fff"];
}
}
})
</script>
</html>

初始化数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>初始化</title>
</head>
<body>
<!-- {{ message }}-->
<div id="root">
{{ message }}
<hr>
{{ msg }}
</div>
</body>
<script src="vue.min.js"></script>
<script>
// 实例化Vue
new Vue({
el: "#root", // 表示在该页面中哪一个区域是需要使用Vue的语法进行解析
data: { // 初始化数据,是一个对象
// 如果需要得到该值,那么可以通过this.message得到,不需要写成this.data.message
// 如果需要改变该值,那么只需要通过this.message = newVal
message: "Hello Vue!",
// 如果在root标签中使用了在data选项中未定义的变量,会报错
msg: "Hello message!"
},
})
</script>
</html>

事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件</title>
</head>
<body>
<div id="root">
{{ message }}
<div>
<button v-on:click="changeValHandler($event, 1)">
改变message的值
</button>
</div>
<div>
<button @click="changeValHandler2()">
改变message的值为vue
</button>
</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script>
/**
* 事件
* 如果是PC端的事件,那么PC端的一切事件均可以使用,反之如果为移动端,也一样
* 二阶段所学的事件,在这里一样适用,只不过得按照vue的语法规则
* v-on: EventName = "eventHandler(params)"
* 如果需要传递事件对象,
* v-on:EventName = "eventHandler($event, params)"
* 以前 onclick = "fn()"
* 现在 v-on:click = "fn()"
* 简写形式
* v-on:click = "fn()" ==> @click = "fn()"
*/
new Vue({
el: "#root",
data: {
message: "hello vue-event"
},
methods: {// 所有自定义的方法必须写在这个选项中
changeValHandler(e, id) {
console.log(e)
console.log(id)
this.message = "hello world"
},
changeValHandler2() {
this.message = "vue"
}
},
})
</script>
</html>

循环数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>循环数据</title>
</head>
<body>
<div id="root">
<h1>Vue中的循环---数组</h1>
<ul>
<li v-for="(carItem, index) in carList" :key="index">
{{ index }}--{{ carItem.brand }}
<ul>
<li v-for="(item, index) in carItem.list" :key="index">
{{ index }}--{{ item }}
</li>
</ul>
</li>
</ul>
<h1>Vue中的循环---对象</h1>
<ul>
<li v-for="(value, key) in list">
{{ key }}--{{ value }}
</li>
</ul>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script>
/**
* v-for
* 循环数据
* "item in carList"
* item.brand
* v-for="itm in item.list"
* itm
* 如果需要拿到循环的索引值,那么需要如下写法,索引值并不一定是index,只要在这个位置,使用任何变量都可以
* v-for="(item, index) in carList"
* key属性:是每一个循环选项的独有ID,具有唯一性,方便程序进行分辩,一般需要和绑定属性结合 v-bind:key="index",此时index就是一个变量
* v-for="(item, index) in carList" v-bind:key="index"
*
* 循环对象
* data: {
* list: {
* a: "aaa",
* b: "bbb"
* }
* }
* v-for="value in list"
* {{ value }} 忽略掉key值显示的值
* v-for="(value, key) in list" // key表示对象的key值,value表示的是对应的值
*/
new Vue({
el: "#root",
data: {
list: {
a: "aaa",
b: "bbb"
},
carList: [
{
brand: "劳斯莱斯",
list: [
"幻影", "古斯特", "魅影"
]
},
{
brand: "宾利",
list: [
"慕尚", "欧陆", "飞驰", "房车"
]
},
{
brand: "保时捷",
list: [
"卡宴", "911", "711"
]
},
]
},
})
</script>
</html>

条件判断

  • v-if

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>条件判断</title>
    </head>
    <body>
    <div id="root">
    <div v-if="flag">如果为真你就能看见我</div>
    ---{{ flag }}
    <button @click="changeFlagHandler()">改变flag的值</button>
    </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script>
    new Vue({
    el: "#root",
    data: {
    flag: true
    },
    methods: {
    changeFlagHandler() {
    this.flag = !this.flag
    }
    },
    })
    </script>
    </html>
  • v-else

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>条件判断</title>
    </head>
    <body>
    <div id="root">
    <div v-if="flag">如果为真你就能看见我</div>
    ---{{ flag }}
    <div v-else>v-else</div>
    <button @click="changeFlagHandler()">改变flag的值</button>
    </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script>
    new Vue({
    el: "#root",
    data: {
    flag: true
    },
    methods: {
    changeFlagHandler() {
    this.flag = !this.flag
    }
    },
    })
    </script>
    </html>
    • 控制显示和隐藏,如果一开始条件为假,那么就不去渲染这一处的 DOM 节点。
    • v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
  • v-show

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>条件判断</title>
    </head>
    <body>
    <div id="root">
    <div v-if="flag">如果为真你就能看见我</div>
    ---{{ flag }}
    <div v-else>v-else</div>
    <button @click="changeFlagHandler()">改变flag的值</button>

    <h1>v-show</h1>
    <div v-show="flag">如果为真你就能看见我</div>
    ---{{ flag }}
    <div v-show="!flag">v-show</div>
    </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script>
    new Vue({
    el: "#root",
    data: {
    flag: true
    },
    methods: {
    changeFlagHandler() {
    this.flag = !this.flag
    }
    },
    })
    </script>
    </html>

    如果一开始条件为假,那么会渲染这个 DOM 节点,只不过 css 执行了隐藏 display: none

  • v-if 和 v-show 的区别

    • v-if 是 “真正” 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
    • v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做 —— 直到条件第一次变为真时,才会开始渲染条件块。
    • 相比之下,v-show 就简单得多 —— 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
    • 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
  • v-if-else

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <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>

    类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

jQuery-data

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>获取数据</title>
    </head>
    <body>
    <div id="root">
    <button v-on:click="getData()">获取数据</button>
    <ul>
    <li v-for="(item, index) of movieList">
    {{ item.title }}
    </li>
    </ul>
    </div>
    </body>
    <script src="jquery.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script>
    new Vue({
    el: "#root",
    data: {
    movieList: []
    },
    methods: {
    getData() { // 获取数据---电影列表
    $.ajax({
    url: "http://localhost:3000/api/list",
    success: this.getDataSuccessHandler,
    })
    },
    getDataSuccessHandler(data) { // 获取数据成功的执行函数
    console.log(data)
    this.movieList = data
    }

    },
    })
    </script>
    </html>
  • ⚠️注意:jQuery 进行请求数据 --- ajax 请求数据

    • vue 1.x.x 版本中 $http 进行请求数据的服务 --- 现在不建议使用
    • vue 2.x.x 版本中不建议使用 $http,改推荐使用 axios

axios-data

  • 简介:基于 Promise 的 HTTP 客户端,用于浏览器和 node.js

  • 特征

    • 从浏览器制作的 XMLHttpRequest
    • HTTP 从 node.js 的请求
    • 支持 Promise API
    • 拦截请求和响应
    • 转换请求和响应数据
    • 取消请求
    • JSON 数据的自动转换
    • 客户端支持以防 XSRF
  • get 请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    const axios = require('axios');

    // Make a request for a user with a given ID
    axios.get('/user?ID=12345')
    .then(function (response) {
    // handle success
    console.log(response);
    })
    .catch(function (error) {
    // handle error
    console.log(error);
    })
    .finally(function () {
    // always executed
    });

    // Optionally the request above could also be done as
    axios.get('/user', {
    params: {
    ID: 12345
    }
    })
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .finally(function () {
    // always executed
    });

    // Want to use async/await? Add the `async` keyword to your outer function/method.
    async function getUser() {
    try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
    } catch (error) {
    console.error(error);
    }
    }
    • 示例 1

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>获取数据</title>
      </head>
      <body>
      <div id="root">
      <button v-on:click="getData()">获取数据</button>
      <ul>
      <li v-for="(item, index) of movieList">
      {{ item.title }}
      </li>
      </ul>
      </div>
      </body>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
      <script src="axios.min.js"></script>
      <script>
      new Vue({
      el: "#root",
      data: {
      movielist: []
      },
      methods: {
      getData() {
      axios.get("http://localhost:3000/api/list", {
      params: {}
      })
      .then(this.getDataSuccessHandler)
      .catch(this.getDataFailHandler)
      },
      getDataSuccessHandler(result) {
      console.log(result.data);
      this.movielist = result.data;
      },
      getDataFailHandler(err) {
      console.log(err);
      },
      },
      })
      </script>
      </html>
    • 示例 2

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>获取数据</title>
      </head>
      <body>
      <div id="root">
      <button v-on:click="getData()">获取数据</button>
      <ul>
      <li v-for="(item, index) of movieList">
      {{ item.title }}
      </li>
      </ul>
      </div>
      </body>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
      <script src="axios.min.js"></script>
      <script>
      var myajax = {
      axiosGet(option, cb) {
      axios.get(option.url, option.params)
      .then(function (result) {
      cb(result.data)
      })
      .catch(function (err) {
      console.log(err)
      })
      }
      }
      new Vue({
      el: "#root",
      data: {
      movielist: []
      },
      methods: {
      getData() {
      var option = {
      url: "http://localhost:3000/api/list",
      params: {
      params: {}
      }
      }
      myajax.axiosGet(option, (data) => {
      console.log(data)
      this.movielist = data;
      })
      },

      }
      })
      </script>
      </html>
  • post 请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
    })
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    });
  • 执行多个并发请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function getUserAccount() {
    return axios.get('/user/12345');
    }

    function getUserPermissions() {
    return axios.get('/user/12345/permissions');
    }

    axios.all([getUserAccount(), getUserPermissions()])
    .then(axios.spread(function (acct, perms) {
    // Both requests are now complete
    }));

    示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>获取数据</title>
    </head>
    <body>
    <div id="root">
    <button @click="getData()">获取数据</button>
    <ul>
    <li v-for="(item, index) of movielist">
    {{ item.title }}
    </li>
    </ul>
    <ul>
    <li v-for="(item, index) of nav">
    {{ item.navName }}
    </li>
    </ul>
    </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script>
    new Vue({
    el: "#root",
    data: {
    movielist: [],
    nav: []
    },
    methods: { //所有自定的方法必须写在这个选项中
    getlistdata() {
    return axios.get('http://localhost:3000/api/list');
    },
    getnavdata() {
    return axios.get('http://localhost:3000/api/nav');
    },
    getmovielistdata() {
    return axios.get('http://localhost:3000/api/list');
    },
    getData() {
    //一次性请求多条数据
    axios.all([this.getlistdata(), this.getnavdata(), this.getmovielistdata()])
    .then(axios.spread((acct, perms, moviedata) => {
    // Both requests are now complete
    console.log(acct) //获取的是list的值
    console.log(perms) //获取的是nav的值
    console.log(moviedata) //获取的是nav的值
    this.movielist = acct.data
    this.nav = perms.data
    }));
    }
    }
    })
    </script>
    </html>

表格输入绑定

  • 你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

  • ⚠️注意:v-model 会忽略所有表单元素的 valuecheckedselected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

  • v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

    • text 和 textarea 元素使用 value property 和 input 事件;
    • checkbox 和 radio 使用 checked property 和 change 事件;
    • select 字段将 value 作为 prop 并将 change 作为事件。
  • ⚠️注意:对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>表格输入绑定</title>
    </head>
    <body>
    <div id="root">
    <input type="text" v-model="username">
    {{ username }}
    <button v-on:click="changeUsernameHandler()">改变username的值</button>
    </div>
    </body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script>
    /**
    * 表单输入绑定
    * v-model 来源于angularJs
    * v-model = "变量"
    * 面试题:数据的双向绑定
    * 1、观察者模式
    * 2、数据劫持
    */
    new Vue({
    el: "#root",
    data: {
    username: "吴大勋"
    },
    methods: {
    changeUsernameHandler() {
    this.username = "王春阳"
    }
    },
    })
    </script>
    </html>

数据的双向绑定

由来

v-model

双向绑定的类型

  1. 发布者 - 订阅者模式(backbone.js)

    • 一般通过 sub, pub 的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value),这里有篇文章讲的比较详细,有兴趣可点这里
    • 这种方式现在毕竟太 low 了,我们更希望通过 vm.property = value 这种方式更新数据,同时自动更新视图,于是有了下面两种方式
  2. 脏值检查(angular.js)

    angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然 Google 不会这么 low,angular 只有在指定的事件触发时进入脏值检测,大致如下:

    • DOM 事件,譬如用户输入文本,点击按钮等。(ng-click)
    • XHR 响应事件 ($http)
    • 浏览器 Location 变更事件 ($location)
    • Timer 事件 ($timeout , $interval)
    • 执行 $digest () 或 $apply ()
  3. 数据劫持(vue.js)

    vue.js 则是采用数据劫持结合发布者 - 订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调。

极简版双向绑定(MVVM)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>双向绑定</title>
</head>
<body>
<h1>双向绑定类型</h1>
<button onclick="changeData()">改变数据</button>
<div id="box"></div>
</body>
<script>
var obj = {};

Object.defineProperty(obj, "newprop", {
set(newVal) {
// console.log(newVal)
document.querySelector("#box").innerHTML = newVal
},
get() {
console.log("this", this)
}
})
obj.newprop = "hello" // 初始化数据局,model->view

function changeData() { // 改变数据,view->model
obj.newprop = "hello model"
}

console.log(obj.newprop) //调用的get
</script>
</html>

如果想更深层次理解,请移步至:https://www.cnblogs.com/kidney/p/6052935.html