# 归档

文章目录

# 前端渲染?

把数据填充HTML标签中

  • js字符串拼接
    (维护难)
  • 前端模板引擎
    (方便维护、但没有专门事件机制)
  • vue
  1. 解耦视图和数据
  2. 可复用的组件
  3. 前端路由技术
  4. 状态管理
  5. 虚拟DOM

# 渐进式?

  • 核心库
  • 插件
    • 路由
    • ...

# 与其他JS框架的关联?

借鉴前辈的技术:

  • angular

    • 模板
    • 数据绑定
  • react

    • 组件化
    • DOM

vue 整合了以上技术

# 特点

  1. 遵循 MVVM 模式
  2. 简洁、小、效率高、支持移动、pc端
  3. 只关注ui、可轻松引入 vue 插件(依赖vue的) 或其他第三方库(不依赖vue的)

# vue包含一系列的扩展插件(库):

  • vue-cli: vue脚手架
  • vue-resource(axios): ajax请求
  • vue-router: 路由
  • vuex: 状态管理
  • vue-lazyload: 图片懒加载
  • vue-scroller: 页面滑动相关
  • mint-ui: 基于vue的组件库(移动端)
  • element-ui: 基于vue的组件库(PC端)

Core + vue-router + Vuex

# Vue 初体验

## Vue.js 安装

  • 方法一:

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

  • 方法三:NPM
    后续通过webpack和CLI的使用,我们使用该方式。

## 声明式编程

声明式编程优势:数据(data、model)和界面(view)分离

(看下面例子慢慢理解)

<body>

  <div id="app">{{message}}</div>

  <script src="../dist/vue.js"></script>
  <script> // 编程范式:声明式编程  let mv = new Vue({ el: '#app', // 用于挂载要管理的元素 data: { // 定义数据 message: '你好啊' } }) // 元素js的做法(编程范式:命令式编程) // 1.创建div元素,设置id属性 // 2.定义一个变量叫message // 3.将message变量放在前面的div袁术中显示 </script>
</body>

## 插值: {{msg.toUpperCase()}}、v-bind、:、v-on、@

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <div id='app'>
    <!--视图:view-->
    <h2>v-model 双向数据绑定</h1>
      <input type="text" v-model='username'>
      <p>Hello {{username}}</p>

      <h2>大括号表达式</h2>
      <p>{{msg}}</p>
      <p>{{msg.toUpperCase()}}</p>
      <!--textContent-->
      <p v-text="msg"></p>
      <!--innerContent-->
      <p v-html="msg"></p>

      <h2>强制数据绑定</h2>
      <img src="url" alt="">
      <img v-bind:src="url" alt="">
      <!--简写-->
      <img :src="url" alt="">

      <h2>绑定事件监听</h2>
      <button v-on:click="test">test1</button>
      <!--简写:可直接识别data参数-->
      <button @click="test2(msg)">test2</button>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
  <script> // 创建 vue 实例 const vm = new Vue({ // 配置对象 el: '#app', // element: 选择器 data: { // model: 数据 username: 'lawssscat', msg: `<a href="https://cn.vuejs.org/images/logo.png">logo</a>`, url: 'https://cn.vuejs.org/images/logo.png' }, methods: { test() { alert('test1'); }, test2(content) { alert(content); } }, }) </script>
</body>

</html>

## 遍历 v-for

<body>

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

  </div>

  <script src="../dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊', movies: ['海贼王', '白色相簿', '火影忍者'] } }) </script>
</body>

## 案例:计数器 - method、v-on、@

<body>

  <div id='app'>
    <h2>当前计数: {{counter}}</h2>
    <!-- <button v-on:click="counter++">+</button> -->
    <!-- <button v-on:click="counter--">-</button> -->
    <button v-on:click="increment">+</button>
    <button v-on:click="decrement">-</button>
  </div>

  <script src="../dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { counter: 0 }, methods: { increment() { this.counter++; }, decrement() { this.counter--; } }, }) // 命令式编程: // 1. 拿button元素 // 2. 添加监听事件 </script>
</body>

# MVVM?

维基:https://zh.wikipedia.org/wiki/MVVM

View层:

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

Model层:

  • 数据层
  • 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
  • 在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。

VueModel层:

  • 视图模型层
  • 视图模型层是View和Model沟通的桥梁。
  • 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
  • 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。

# (前面用到的)基本 options

文章目录

# Vue 的生命周期

官网 - 生命周期 api: https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90


文章目录

# 模板语法

官方文档 - https://cn.vuejs.org/v2/guide/syntax.html

模板语法概览


指令本质:自定义属性
指令格式:以v-开始(如:v-cloak)

## Mus`tache (胡子) - 插值表达式

  • 如何将 data 中的文本数据,插入到 HTML 中呢?
    • 已经学习过了,可以通过Mustache语法(也就是双大括号)。
    • Mustache: 胡子/胡须.
  • 我们可以像下面这样来使用,并且数据是响应式的

<body>

  <div id='app'>
    <h2>{{message}}</h2>
    <!-- mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式 -->
    <h2>{{message}}, 主人</h2>
    <h2>{{message}}, {{firstName + ' ' + lastName}}</h2>
    <h2>{{counter * 2}}</h2>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊', firstName: 'alan', lastName: '~~~', counter: 100 } }) </script>
</body>

## v-once 取消响应

插值表达式渲染一次后,不随变量改变

<body>

  <div id='app'>
    <h2>{{message}}</h2>
    <h2 v-once>{{message}}</h2>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊' } }) app.message = '哈哈哈' // 改了 message 值 </script>
</body>

## v-html

文本解析为html(有标签,能识别)

<body>

  <div id='app'>
    <h2>{{message}}</h2>
    <h2 v-html="message"></h2>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) </script>
</body>

## v-text

和 v-html 相反,文本只能识别为文本(而且会覆盖原有文本)


<body>

  <div id='app'>
    <h2>{{message}}</h2>
    <!--不翻译标签-->
    <h2 v-text="message"></h2>
    <!--覆盖文本-->
    <h2 v-text="message">你好骚啊</h2>
    <!--覆盖文本-->
    <h2 v-text="message">{{message}},你好骚啊</h2>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) </script>
</body>

## v-pre 显示原生内容

<body>

  <div id='app'>
    <h2>{{message}}</h2>
    <h2 v-pre="message">{{message}}</h2>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) </script>
</body>

## v-cloak

cloak 披风、伪装

v-clock 披风,在Vue渲染前显示的样式,渲染后消失。可以用来避免未渲染文本出现

<mark>但是后面也不会用到,因为后面会用虚拟 DOM 技术</mark>

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> [v-clock] { display: none; } </style>
</head>

<body>

  <!-- v-clock 披风,在Vue渲染前显示的样式,渲染后消失。可以用来避免未渲染文本出现 -->
  <div id='app' v-clock>
    <h2>{{message}}</h2>
  </div>
  <script src="./dist/vue.js"></script>
  <script> setTimeout(() => { const app = new Vue({ el: '#app', data: { message: `<a href='http://www.baidu.com'>百度一下</a>` } }) }, 3000) </script>
</body>

</html>

文章目录

## v-bind

  • 某些属性我们也希望动态来绑定。
    • 比如动态绑定 a 元素的 href 属性
    • 比如动态绑定 imgimg 元素的 src 属性
  • 这个时候,我们可以使用 v-bind 指令:
    • 作用:动态绑定属性
    • 缩写::
    • 预期:any (with argument) | Object (without argument)
    • 参数:attrOrProp (optional)

<mark>这个用的超多</mark>

如:绑定图片 src

<body>

  <div id='app'>
    <img v-bind:src="url"></img>
    <img :src="url"></img><!--语法糖:由于经常用到,所以有了简写-->
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { url: 'https://cn.vuejs.org/images/logo.png' } }) </script>
</body>

又如:【对象语法】 通过对象修改 class

注意:这里的 :class 不会覆盖原有的 class

 <h2 class='title' :class='{active: isActive,error:!isActive }'>{{message}}</h2>

如这里的 title class 仍然会保留

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> .active { color: green; } .error { color: red; } </style>
</head>

<body>

  <div id='app'>
    <h2 :class='{active: isActive,error:!isActive }'>{{message}}</h2>
    <button @click='change'>点击换颜色</button>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true }, methods: { change() { this.isActive = !this.isActive; } }, }) </script>
</body>

</html>



同一个例子:只是用了访问器

<body>

  <div id='app'>
    <h2 :class='myClass'>{{message}}</h2>
    <button @click='change'>点击换颜色</button>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true, get myClass() { return { active: this.isActive, error: !this.isActive } } }, methods: { change() { this.isActive = !this.isActive; } }, }) </script>
</body>

又如:【数组语法】

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> .a { font-size: small; } .b { font-size: large; } .active { color: green; } .error { color: red; } </style>
</head>

<body>

  <div id='app'>
    <h2 :class='myClass'>{{message}}</h2>
    <button @click='change'>点击换颜色</button>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true, get myClass() { if (this.isActive) { return ['active', 'a']; } else { return ['error', 'b'] } } }, methods: { change() { this.isActive = !this.isActive; } }, }) </script>
</body>

</html>


文章目录

## 计算属性 computed

怎么用?

<body>

  <div id='app'>
    <!--data-->
    <h2>{{fullName}}</h2>
    <!--methods-->
    <!-- <h2>{{fullName()}}</h2> -->
    <!--计算属性 computed-->
    <h2>{{fullName}}</h2>
  </div>

  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { firstName: 'alan', lastName: 'Wan', // get fullName() { // return `${this.firstName} ${this.lastName}`; // } }, computed: { fullName() { return `${this.firstName} ${this.lastName}`; } }, methods: { // fullName() { // return `${this.firstName} ${this.lastName}`; // } } }) </script>
</body>

必要使用


<body>

  <div id='app'>
    <ul>
      <li v-for='book in books'>{{book.name}}:{{book.price}}</li>
    </ul>
    <h2>总价格:{{totalPrice}}</h2>
  </div>

  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { books: [{ id: 11, name: 'Unix编程艺术', price: 19 }, { id: 12, name: 'Vue.js', price: 99 }, { id: 13, name: '深入理解计算机原理', price: 33 }, { id: 14, name: '现代操作系统', price: 9 }, ] }, computed: { totalPrice() { return this.books.reduce((total, book) => { return total += book.price; }, 0) } }, }) </script>
</body>

计算属性的 settergetter (访问器)

计算属性一般没有set方法,只读属性

但用了,可以实现三联

<body>

  <div id='app'>
    <h2>firstName: {{firstName}}</h2>
    <h2>lastName: {{lastName}}</h2>
    <h2>fullName: {{fullName}}</h2>
  </div>

  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { firstName: 'AA', lastName: 'bb' }, computed: { fullName: { set(value) { const names = value.split(' '); this.firstName = names[0] || names[1] || ''; this.lastName = (names[1] && names[0]) || names[2] || ''; }, get() { return `${this.firstName} ${this.lastName}`; } } }, }) </script>
</body>

计算属性有【缓存】!!!(速度快!)

<body>

  <div id='app'>
    <h2>调用 computed 方法4次</h2>
    <p>{{cache}}</p>
    <p>{{cache}}</p>
    <p>{{cache}}</p>
    <p>{{cache}}</p>
    <h2>调用 methods 方法4次</h2>
    <p>{{nocache()}}</p>
    <p>{{nocache()}}</p>
    <p>{{nocache()}}</p>
    <p>{{nocache()}}</p>
  </div>

  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: {}, computed: { cache() { console.log(`调用 computed `) return 'computed'; } }, methods: { nocache() { console.log(`调用 methods `) return 'methods'; } }, }) </script>
</body>

computed 区别于 method 的核心

在官方文档中,强调了 computed 区别于 method 最重要的两点

  1. <mark>computed是属性调用,而methods是函数调用</mark>

  2. <mark>computed带有缓存功能,而methods不是</mark>

  3. computed定义的方法我们是以属性访问的形式调用的, {{computedTest}}

  4. 但是methods定义的方法,我们必须要加上()来调用,如{{methodTest()}},否则,视图会出现test1的情况,见下图

  5. 我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 text 还没有发生改变,多次访问 getText 计算属性会立即返回之前的计算结果,而不必再次执行函数。而方法只要页面中的属性发生改变就会重新执行

  6. 对于任何复杂逻辑,你都应当使用计算属性

  7. computed依赖于data中的数据,只有在它的相关依赖数据发生改变时才会重新求值

文章目录

## v-on、@、 事件监听

在前端开发中,我们需要经常和用于交互。

  • 这个时候,我们就必须监听用户发生的时间,比如点击、拖拽、键盘事件等等
  • 在Vue中如何监听事件呢?使用v-on指令

v-on 介绍 - 事件绑定

  • 作用:绑定事件***
  • 缩写:@
  • 预期:Function | Inline Statement | Object
  • 参数:event(默认) | 自定义转入+$event

参数 、 event$event

当通过 methods 中定义方法,以供@click调用时,需要注意参数问题:

  • 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。
    但是注意:如果方法本身中有一个参数,那么会<mark>默认将原生事件 event 参数传递进去</mark>
  • 情况二:如果需要同时传入某个参数,同时需要 event 时,可以通过 $event 传入事件。

API 增强

在某些情况下,我们拿到event的目的可能是进行一些事件处理。

Vue提供了修饰符来帮助我们方便的处理一些事件:

  • .stop - 调用 event.stopPropagation()

    《JS阻止冒泡和取消默认事件(默认行为)》 - http://caibaojian.com/javascript-stoppropagation-preventdefault.html

    // js 需要这样做
    
    function stopBubble(e) { 
    //如果提供了事件对象,则这是一个非IE浏览器 
    if ( e && e.stopPropagation ) 
       //因此它支持W3C的stopPropagation()方法 
       e.stopPropagation(); 
    else 
       //否则,我们需要使用IE的方式来取消事件冒泡 
       window.event.cancelBubble = true; 
    }
    
  • .prevent - 调用 event.preventDefault()

    《JS阻止冒泡和取消默认事件(默认行为)》 - http://caibaojian.com/javascript-stoppropagation-preventdefault.html

    // js 需要这样做
    //阻止浏览器的默认行为 
    function stopDefault( e ) { 
        //阻止默认浏览器动作(W3C) 
        if ( e && e.preventDefault ) 
            e.preventDefault(); 
        //IE中阻止函数器默认动作的方式 
        else 
            window.event.returnValue = false; 
        return false; 
    }
    
  • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。

  • .native - 监听组件根元素的原生事件。(组件时候用到)

  • .once - 只触发一次回调。

文章目录

## 条件判断:v-if、v-else-if、v-else、及条件渲染 v-show

v-ifv-else-ifv-else

不建议使用,建议使用计算属性

这三个指令与JavaScript的条件语句if、else、else if类似。

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

简单的案例演示:

v-if 的原理:

v-if 后面的条件为 false 时,对应的元素以及其子元素不会渲染。
也就是根本没有不会有对应的标签出现在 DOM 中。

v-if 切换时候的小问题(引出概念:虚拟DOM)

<body>

  <div id='app'>
    <span v-if="isUser">
      <label for="username">{{userText}}</label>
      <input type="text" :placeholder="userText" id="username">
    </span>
    <span v-else>
      <label for="email">{{emailText}}</label>
      <input type="text" :placeholder='emailText' id="email">
    </span>
    <button @click='isUser=!isUser'>切换类型</button>
  </div>

  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { userText: '用户账号', emailText: '用户邮箱', isUser: true } }) </script>
</body>

小问题:

  • 如果我们在 input 输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容
  • 为什么会这样

问题解答:

  • 这是因为 Vue 在进行 DOM 渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。<mark>虚拟DOM技术(后面讲)</mark>
  • 在上面的案例中, Vue 内部会发现原来的 input 元素不再使用,直接作为 else 中的 input 来使用

解决方案

  • 如果我们不希望 Vue 出现类似复用的问题,可以给对应的 input 添加 Key
    <mark>会把 key 作为一个唯一标识</mark>
  • 当然,要保证 Key 不同

v-show

v-show 的用法和 v-if 非常相似,也用于决定一个元素是否渲染:

v-show 和 v-if 的区别

  • v-if 当条件为 false 时,压根不会有对应的元素在 DOM 中。
  • v-show 当条件为 false 时,<mark>仅仅是将元素的 display 属性设置为 none 而已。</mark>

<body>

  <div id='app'>
    <h2 v-if='isShow'>{{message}}</h2>
    <h2 v-show='isShow'>{{message}}</h2>
  </div>

  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { message: '你好啊', isShow: false } }) </script>
</body>

结论:

  • 当需要在显示与隐藏之间切片很频繁时,使用v-show
  • 当只有一次切换时,通过使用v-if

文章目录

## v-for 遍历

语法

v-for 的语法类似于 JavaScript 中的 forof 循环。

  • 【数组】 不要下标格式: v-for='item in items'v-for='item of items'
  • 【数组】要下标格式:v-for='(item, index) in items'
    其中的index就代表了取出的item在原数组的索引值。
  • 【对象】不要key格式:v-for='value in obj'
  • 【对象】要key格式:v-for='(value,key) in obj'
  • 【对象】要key,要index格式:v-for='(value,key, index) in obj'

原则:

  1. in 或者 of 均可(效果一样)
  2. 接收多个值 要用(....)
  3. 有三个接收值 (value, key, index) 分别为:值、键、下标
  4. 支持解构 (不同的是,用 of 或者 in 均可)
<li v-for='[key,value] of Object.entries(user)'>

<mark>和 JS 的 forin 、 forof 的 对比</mark>

  • forin 只能遍历获取 key
  • forof支持解构,
    解构必须使用 [key, value] ,分别为:键,值
    不用解构 接收的是 value , 值
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style> .active { color: red; } </style>
</head>

<body>
  <div id='app'>
    <h2>老婆们:(今晚翻牌)</h2>
    <ul>
      <li v-for="(m, index) in movies" :class="{active: index==activeIndex}" @click="activeChange(index)">{{m}}</li>
    </ul>
  </div>
  <script src="./dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { movies: ['妲己', '上官婉儿', '不知火舞', '王昭君', '大乔', '小乔', '武则天'], activeIndex: 0 }, methods: { activeChange(index) { this.activeIndex = index; } }, }) </script>
</body>

</html>

【重要】 官方推荐:使用v-for时,添加:key属性

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

为什么需要这个key属性呢(了解)?
这个其实和 Vue 的 <mark>虚拟DOM</mark> 的 <mark>Diff算法</mark> 有关系。
这里我们借用 React’s diff algorithm 中的一张图来简单说明一下:

当<mark>同一层</mark>有很多相同的节点时,也就是列表节点时,<mark>我们希望插入一个新的节点</mark>:
(我们希望可以在B和C之间加一个F)

['a', 'b', 'c', 'd', 'e'].splice(2,0,'f')


Diff算法执行有两种情况:
.

情况一:每个节点均无 Key 唯一标识(下图)

即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
所以我们需要使用key来给每个节点做一个唯一标识

情况二:每个节点均有 Key 唯一标识(下图)

Diff算法就可以正确的识别此节点
找到正确的位置区插入新的节点。

.
<mark>所以一句话,key的作用主要是为了高效的更新虚拟DOM。</mark>

检测数组更新 / Vue.set

<mark>因为Vue是响应式的</mark>,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。

Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。

<mark>哪些组数方法 是响应式的?</mark>

  • push()
  • pop()
  • shift() - 数组最前面<mark>删除一个</mark>元素
  • unshift() - 数组最前面<mark>添加 n 个</mark>元素
  • splice() - 组数在<mark>指定位置</mark>,<mark>删除指定长度</mark>并<mark>插入指定数组</mark>
    JavaScript splice() 方法
  • sort()
  • reverse()

<mark>哪些组数方法 是响应式的?</mark>

  • 直接改数组元素值:lessons[0]='aaa';
    这种情况要改成
    Vue.set(this.lessons, 0, 'aaa')
    // 或者
    lessons.splice(0, 1, 'aaa')
    



文章目录

## 案例:购物车

文章目录

## v-model 表单绑定

## 双向绑定

<body>

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

  <script src="../dist/vue.js"></script>
  <script> const apo = new Vue({ el: '#app', data: { message: '你好啊' } }) </script>
</body>

## v-model双向绑定数组数据时遇到的天坑

前面说了,下面,直接赋值的方法不是响应式的

<mark>哪些组数方法 是响应式的?</mark>

  • 直接改数组元素值:lessons[0]='aaa';
    这种情况要改成
    Vue.set(this.lessons, 0, 'aaa')
    // 或者
    lessons.splice(0, 1, 'aaa')
    

但是 360 支持,这是为什么呢?

用Chrome浏览器

用360浏览器

查看了几个文档后发现是Chrome不兼容Object.observe

也就是说,因为360浏览器太老(没有更新)的原因,没有废弃object.server,所以才能够这样用。现阶段只能使用vue.set

解决方法

使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上。 还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名。

## (js手写)双向绑定 - ***

双向绑定原理 - https://blog.csdn.net/LawssssCat/article/details/104190288#__1279

v-model其实是一个语法糖,它的背后本质上是包含两个操作:

1.v-bind绑定一个value属性

2.v-on指令给当前元素绑定input事件

也就是说下面的代码:等同于下面的代码:

(简化版)大概如下,完整版 看源码


<body>

  <div id='app'>
    <input type="text" v-model='message'>
    <input type="text" v-model='message'>
  </div>

  <script> /** * 自定义 Vue */ class Vue { constructor(config) { this.init(config); } /** * 初始化 */ init(config) { if (!(config && config.el)) throw new Error('传参数啊!') // 找el this.el = document.querySelector(config.el); // 找v-model const models = this.el.querySelectorAll(`[v-model]`); // 找data if (config.data) { // 构建***对象  this.constructorProxy(); // data赋值 for (const [property, value] of Object.entries(config.data)) { this.proxy[property] = value; } } // 添加 model 监听 models.forEach(model => { model.addEventListener('keyup', (e) => { let target = e.target; let property = target.getAttribute('v-model'); this.proxy[property] = target.value; }) }) } /** * ***对象构建 */ constructorProxy() { let handler = { get(obj, property) { return obj[property]; }, set(obj, property, value) { // 对象赋值 obj[property] = value; // v-model赋值 obj.el.querySelectorAll(`[v-model=${property}]`) .forEach(model => { model.value = value; }) // mustache赋值 // 略过... // 还有其他赋值... return true; } } this.proxy = new Proxy(this, handler); } } let mv = new Vue({ el: '#app', data: { message: '你好啊' } }) </script>
</body>

v-model 结合:radio

当存在多个单选框时

<body>

  <div id='app'>
    <label for="male">
     <!--当存在 v-model 时, name可以去掉,也能完成互斥的效果-->
      <input type="radio" id="male" name='sex' value='' v-model='sex'></label>
    <label for="female">
      <input type="radio" id="female" name='sex' value='' v-model='sex'></label>
    <h2>您选择的性别是:{{sex}}</h2>
  </div>

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

v-model 结合:checkbox

复选框分为两种情况:单个选框和多个选框

单选框

<body>

  <div id='app'>
    <label for="license">
      <input type="checkbox" name="" id="license" v-model='isAgree'>同意协议
    </label>
    <h2>您选择的是:{{isAgree}}</h2>
    <button :disabled='!isAgree' onclick="javascript:alert('ok');">下一步</button>
  </div>

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

多选框

<body>
  <div id='app'>
    <label :for="hobby+index" v-for='(hobby, index) in hobbies'>
      <input type="checkbox" :value='hobby' :id='hobby+index' v-model='selectedHobbies'>{{hobby}}
    </label>
    <h2>您选择的是:{{selectedHobbies}}</h2>
  </div>

  <script src="../dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { selectedHobbies: [], hobbies: ['22娘', '33娘', '樱花庄的宠物女孩', '芽衣', '埃尔芒老师'], isAgree: false } }) </script>
</body>

v-model 结合:select

和checkbox一样,select也分单选和多选两种情况。

单选:只能选中一个值。

  • v-model绑定的是一个值。
  • 当我们选中option中的一个时,会将它对应的value赋值到mySelect中

单选择

<body>
  <div id='app'>
    <!--选择一个-->
    <select name="wife" id="" v-model='selectedHobbies'>
      <option :value="hobby" v-for='hobby in hobbies'>{{hobby}}</option>
    </select>

    <h2>您的老婆是:{{selectedHobbies}}</h2>
  </div>

  <script src="../dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { selectedHobbies: '', hobbies: ['22娘', '33娘', '樱花庄的宠物女孩', '芽衣', '埃尔芒老师'], isAgree: false } }) </script>
</body>


多选:可以选中多个值。

  • v-model绑定的是一个数组。
  • 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中

多个


<body>
  <div id='app'>
    <!--选择一个-->
    <select name="wife" id="" v-model='selectedHobbies' multiple>
      <option :value="hobby" v-for='hobby in hobbies'>{{hobby}}</option>
    </select>

    <h2>您的老婆是:{{selectedHobbies}}</h2>
  </div>

  <script src="../dist/vue.js"></script>
  <script> const app = new Vue({ el: '#app', data: { selectedHobbies: [], hobbies: ['22娘', '33娘', '樱花庄的宠物女孩', '芽衣', '埃尔芒老师'], isAgree: false } }) </script>
</body>

<mark>按住 ctrl 选择</mark>

v-model 的 修饰符

官网 api - https://cn.vuejs.org/v2/api/#v-model
lazy修饰符: - 懒更新

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

number修饰符:

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

trim修饰符:

  • 如果输入的内容首尾有很多空格,通常我们希望将其去除
  • trim修饰符可以过滤内容左右两边的空格


官网 api - https://cn.vuejs.org/v2/api/#%E6%8C%87%E4%BB%A4 【指令部分】