两万字Vue.js基础学习笔记(一)

Vue.js 学习笔记(一)

Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。

HTML + CSS + JS : 视图 : 给用户看,刷新后台给的数据

网络通信 : axios

页面跳转 : vue-router

状态管理:vuex

Vue-UI : ICE , Element UI

  1. VUE 概述
    Vue (读音 /vju/, 类似于 view)是一套用于构建用户界面的渐进式框架,发布于 2014 年 2 月。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库 (如: vue-router: 跳转,vue-resource: 通信,vuex: 管理) 或既有项目整合
  2. 前端三要素
    HTML (结构) : 超文本标记语言 (Hyper Text Markup Language) ,决定网页的结构和内容
    CSS (表现) : 层叠样式表 (Cascading Style sheets) ,设定网页的表现样式
    JavaScript (行为) : 是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行, 用于控制网页的行为
  3. JavaScript 框架
    jQuery: 大家熟知的 JavaScript 框架,优点是简化了 DOM 操作,缺点是 DOM 操作太频繁, 影响前端性能; 在前端眼里使用它仅仅是为了兼容 IE6、7、8;

Angular: Google 收购的前端框架,由一群 Java 程序员开发,其特点是将后台的 MVC 模式搬到了前端并增加了模块化开发的理念,与微软合作,采用 TypeScript 语法开发; 对后台程序员友好,对前端程序员不太友好; 最大的缺点是版本迭代不合理 (如: 1 代 -> 2 代,除了名字,基本就是两个东西; 截止发表博客时已推出了 Angular6)

React: Facebook 出品,一款高性能的 JS 前端框架; 特点是提出了新概念 [虚拟 DOM] 用于减少真实 DOM 操作,在内存中模拟 DOM 操作,有效的提升了前端渲染效率; 缺点是使用复杂,因为需要额外学习一门[JSX] 语言;

Vue:一款渐进式 JavaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了 Angular (模块化) 和 React (虚拟 DOM) 的优点;

Axios :前端通信框架; 因为 Vue 的边界很明确,就是为了处理 DOM, 所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互; 当然也可以直接选择使用 jQuery 提供的 AJAX 通信功能;

前端三大框架:Angular、React、Vue

ES6 语法

1. 不一样的变量声明:const 和 let

ES6 推荐使用 let 声明局部变量,相比之前的 var(无论声明在何处,都会被视为声明在函数的最顶部)
let 和 var 声明的区别:

copy
var x = '全局变量'; { let x = '局部变量'; console.log(x); // 局部变量 } console.log(x); // 全局变量
copy
<body> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <script> // 变量作用域: 变量在什么位置内是可用的 // ES5 之前因为 if 和 for 都没有块级作用域的概念,所以在很多时候,我们都必须借助于 function 的作月域来解决应用外面变量的问题 // 闭包可以解决这个问题: 函数是一个作用域 // ES6 中加入了 let,let 它是有 if 和 for 块级作用域
<span class="hljs-comment">// ES5语法</span>
<span class="hljs-comment">// var btns = document.getElementsByTagName('button');</span>
<span class="hljs-comment">// for(var i = 0; i&lt;btns.length; i++){</span>
<span class="hljs-comment">//   (function(num){</span>
<span class="hljs-comment">//     bnts[num].addEventListener('click',function(){</span>
<span class="hljs-comment">//       console.log('第'+num+'个按钮被点击');</span>
<span class="hljs-comment">//     })</span>
<span class="hljs-comment">//   })(i)</span>
<span class="hljs-comment">// }</span>

<span class="hljs-comment">// ES6语法</span>
<span class="hljs-keyword">const</span> btns = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementsByTagName</span>(<span class="hljs-string">'button'</span>)
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i &lt; btns.<span class="hljs-property">length</span>; i++) {
  btns[i].<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">'click'</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'第'</span> + i + <span class="hljs-string">'个按钮被点击'</span>);
  })
}

</script>
</body>

let 表示声明变量,而 const 表示声明常量,两者都为块级作用域;

const 声明的变量都会被认为是常量,意思就是它的值被设置完成后就不能再修改了,且 const 定义标识符时,必须赋值:

建议:在 ES6 开发中, 优先使用 const, 只有需要改变某一个标识符的时候才使用 let。

copy
const a = 1 a = 0 // 报错

如果 const 的是一个对象,对象所包含的值(内部属性)是可以被修改的。抽象一点儿说,就是对象所指向的地址没有变就行:

copy
const student = { name: 'cc' }

student.name = 'yy';// 不报错
student = { name: 'yy' };// 报错

有几个点需要注意:

  • let 关键词声明的变量不具备变量提升(hoisting)特性
  • let 和 const 声明只在最靠近的一个块中(花括号内)有效
  • 当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
  • const 在声明时必须被赋值

2. 模板字符串

在 ES6 之前,我们往往这么处理模板字符串:
通过“\”和“+”来构建模板

copy
$("body").html("This demonstrates the output of HTML \ content to the page, including student's\" + name + "," + seatNumber + "," + sex + "and so on.");

而对 ES6 来说

  1. 基本的字符串格式化。将表达式嵌入字符串中进行拼接。用 ${} 来界定;
  2. ES6 反引号 (``) 直接搞定;
copy
$("body").html(`This demonstrates the output of HTML content to the page, including student's ${name}, ${seatNumber}, ${sex} and so on.`);

3. 箭头函数(Arrow Functions)

ES6 中,箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体;

箭头函数最直观的三个特点。

  • 不需要 function 关键字来创建函数
  • 省略 return 关键字
  • 继承当前上下文的 this 关键字
copy
// ES5 var add = function (a, b) { return a + b; }; // 使用箭头函数 var add = (a, b) => a + b;

// ES5
[1,2,3].map((function(x){
return x + 1;
}).bind(this));

// 使用箭头函数
[1,2,3].map(x => x + 1);

细节:当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略 {} 和 return;

4. 函数的参数默认值

在 ES6 之前,我们往往这样定义参数的默认值:

copy
// ES6 之前,当未传入参数时,text = 'default'; function printText(text) { text = text || 'default'; console.log(text); }

// ES6;
function printText(text = 'default') {
console.log(text);
}

printText('hello'); // hello
printText();// default

5.Spread / Rest 操作符

Spread / Rest 操作符指的是 ...,具体是 Spread 还是 Rest 需要看上下文语境。

当被用于迭代器中时,它是一个 Spread 操作符:

copy
function foo(x,y,z) { console.log(x,y,z); }

let arr = [1,2,3];
foo(...arr); // 1 2 3

当被用于函数传参时,是一个 Rest 操作符:当被用于函数传参时,是一个 Rest 操作符:

copy
function foo(...args) { console.log(args); } foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

6. 二进制和八进制字面量

ES6 支持二进制和八进制的字面量,通过在数字前面添加 0o 或者 0O 即可将其转换为八进制值:

copy
let oValue = 0o10; console.log(oValue); // 8

let bValue = 0b10; // 二进制使用 0b 或者 0B
console.log(bValue); // 2

7. 对象和数组解构

copy
// 对象 const student = { name: 'Sam', age: 22, sex: '男' } // 数组 // const student = ['Sam', 22, '男'];

// ES5;
const name = student.name;
const age = student.age;
const sex = student.sex;
console.log(name + '---' + age + '---' + sex);

// ES6
const { name, age, sex } = student;
console.log(name + '---' + age + '---' + sex);

8. 对象超类

ES6 允许在对象中使用 super 方法:

copy
var parent = { foo() { console.log("Hello from the Parent"); } }

var child = {
foo() {
super.foo();
console.log("Hello from the Child");
}
}

Object.setPrototypeOf(child, parent);
child.foo(); // Hello from the Parent
// Hello from the Child

9.for...of 和 for...in

for...of 用于遍历一个迭代器,如数组:

copy
let letters = ['a', 'b', 'c']; letters.size = 3; for (let letter of letters) { console.log(letter); } // 结果: a, b, c

for...in 用来遍历对象中的属性:

copy
let stus = ["Sam", "22", "男"]; for (let stu in stus) { console.log(stus[stu]); } // 结果: Sam, 22, 男

10.ES6 中的类

ES6 中支持 class 语法,不过,ES6 的 class 不是新的对象继承模型,它只是原型链的语法糖表现形式。

函数中使用 static 关键词定义构造函数的的方法和属性:

copy
class Student { constructor() { console.log("I'm a student."); }

study() {
console.log('study!');
}

static read() {
console.log("Reading Now.");
}
}

console.log(typeof Student); // function
let stu = new Student(); // "I'm a student."
stu.study(); // "study!"
stu.read(); // "Reading Now."

类中的继承和超集:

copy
class Phone { constructor() { console.log("I'm a phone."); } }

class MI extends Phone {
constructor() {
super();
console.log("I'm a phone designed by xiaomi");
}
}

let mi8 = new MI();

extends 允许一个子类继承父类,需要注意的是,子类的 constructor 函数中需要执行 super() 函数。
当然,你也可以在子类方法中调用父类的方法,如 super.parentMethodName()。
在 这里 阅读更多关于类的介绍。

有几点值得注意的是:

  • 类的声明不会提升(hoisting),如果你要使用某个 Class,那你必须在使用之前定义它,否则会抛出一个 ReferenceError 的错误
  • 在类中定义函数不需要使用 function 关键词

1、基本认识 vue

  • 轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20 多 kb (Angular 压缩后 56kb+,React 压缩后 44kb+)
  • 移动优先。更适合移动端,比如移动端的 Touch 事件
  • 易上手,学习曲线平稳,文档齐全
  • 吸取了 Angular(模块化)和 React(虚拟 DOM)的长处,并拥有自己独特的功能,如:计算属性
  • Vue 是一个渐进式的框架可以将 Vue 作为你应用的一 部分嵌入其中, 带来更丰富的交互体验。
  • 开源,社区活跃度高
  • Vue 有很多特点和 Web 开发中常见的高级功能
    • 解耦视图和数据.
    • 可复用的组件
    • 前端路由技术
    • 状态管理
    • 虚拟 DOM

下载地址

copy
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
  • NPM 安装

初识 vue.js

copy
<body>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span>{{message}}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> //执行到这里显然出对应的HTML

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"../js/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript">
    <span class="hljs-comment">//执行这里创建Vue实例,并且对原HTML进行解析和修改。</span>
    <span class="hljs-comment">//编程范式:声明式编程</span>
    <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Vue</span>({   <span class="hljs-comment">//创建Vue实例</span>
        <span class="hljs-attr">el</span>:<span class="hljs-string">'#app'</span>,   <span class="hljs-comment">//用于指定要挂载的元素</span>
        <span class="hljs-attr">data</span>:{       <span class="hljs-comment">//定义数据</span>
            <span class="hljs-attr">message</span>:<span class="hljs-string">"洛依尘!"</span>
        }
    })
    <span class="hljs-comment">//元素js的做法(编程范式:命令式编程)</span>
    <span class="hljs-comment">// 1.创建div元素,设置id属性</span>
    <span class="hljs-comment">// 2.定义一个变量叫message</span>
    <span class="hljs-comment">// 3.将message变量放在前面的div元素中显示</span>
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

</body>

MVVM 模式

MVVM 源自于经典的 Model–View–Controller(MVC)模式(期间还演化出了 Model-View-Presenter(MVP)模式,可忽略不计)。MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极大地提高了前端开发效率。MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。

如下图所示:

img

简单画了一张图来说明 MVVM 的各个组成部分:

img

分层设计一直是软件架构的主流设计思想之一,MVVM 也不例外。

View 层

View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建,为了更方便地展现 ViewModel 或者 Model 层的数据,已经产生了各种各样的前后端模板语言,比如 FreeMarker、Marko、Pug、Jinja2 等等,各大 MVVM 框架如 KnockoutJS,Vue,Angular 等也都有自己用来构建用户界面的内置模板语言。

Model 层

Model 是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。后端的处理通常会非常复杂

ViewModel 层

ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示),而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现数据驱动开发。看到了吧,View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。

image-20210508173816636

Vue 实例的 options

  • el:
    类型 : string | HTMLElement
    作用 : 决定之后 Vue 实例会管理哪一个 DOM。
  • data:
    类型 : Object | Function (组件当中 data 必须是一个函数)
    作用 : Vue 实例对应的数据对象。
  • methods:
    类型 : {[key: string]: Function }
    作用 : 定义属于 Vue 的一 些方法,可以在其他地方调用, 也可以在指令中使用。

vue 实例的生命周期

一、解析

1、什么是生命周期:从 Vue 实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!

2、生命周期钩子 = 生命周期函数 = 生命周期事件

3、主要的生命周期函数分类:

- 创建期间的生命周期函数:

+ beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性

+ created:实例已经在内存中创建 OK,此时 data 和 methods 已经创建 OK,此时还没有开始 编译模板

+ beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中

+ mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示

- 运行期间的生命周期函数:

+ beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染 DOM 节点

+ updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!

- 销毁期间的生命周期函数:

+ beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。

+ destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

copy
<body> <div id="app"> <input type="button" value="修改 msg" @click="msg='No'"> <h3 id="h3">{{ msg }}</h3> </div>

<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: 'ok'
},
methods: {
show() {
console.log('执行了 show 方法')
}
},
beforeCreate() { // 这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它
console.log(this.msg)
this.show()
// 注意: 在 beforeCreate 生命周期函数执行的时候,data 和 methods 中的 数据都还没有没初始化
},
created() { // 这是遇到的第二个生命周期函数
console.log(this.msg)
this.show()
// 在 created 中,data 和 methods 都已经被初始化好了!
// 如果要调用 methods 中的方法,或者操作 data 中的数据,最早,只能在 created 中操作
},
beforeMount() { // 这是遇到的第 3 个生命周期函数,表示 模板已经在内存中编辑完成了,但是尚未把 模板渲染到 页面中
console.log(document.getElementById('h3').innerText)
// 在 beforeMount 执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串
},
mounted() { // 这是遇到的第 4 个生命周期函数,表示,内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了
console.log(document.getElementById('h3').innerText)
// 注意: mounted 是 实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,此时,如果没有其它操作的话,这个实例,就静静的 躺在我们的内存中,一动不动
},

  <span class="hljs-comment">// 接下来的是运行中的两个事件</span>
  <span class="hljs-title function_">beforeUpdate</span>(<span class="hljs-params"></span>) { <span class="hljs-comment">// 这时候,表示 我们的界面还没有被更新【数据被更新了吗?  数据肯定被更新了】</span>
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'界面上元素的内容:'</span> + <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'h3'</span>).<span class="hljs-property">innerText</span>)
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'data 中的 msg 数据是:'</span> + <span class="hljs-variable language_">this</span>.<span class="hljs-property">msg</span>) 
    <span class="hljs-comment">// 得出结论: 当执行 beforeUpdate 的时候,页面中的显示的数据,还是旧的,此时 data 数据是最新的,页面尚未和 最新的数据保持同步</span>
  },
  <span class="hljs-title function_">updated</span>(<span class="hljs-params"></span>) {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'界面上元素的内容:'</span> + <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">'h3'</span>).<span class="hljs-property">innerText</span>)
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'data 中的 msg 数据是:'</span> + <span class="hljs-variable language_">this</span>.<span class="hljs-property">msg</span>)
    <span class="hljs-comment">// updated 事件执行的时候,页面和 data 数据已经保持同步了,都是最新的</span>
  }
});

</script>
</body>

img

2、基本语法

1、插值操作

Mustache 语法

copy
<div id="app"> <h2>{{massage}}</h2> <h2>{{massage}},洛依尘</h2> <h2>{{firstName+lastName}}</h2> <h2>{{firstName+' '+lastName}}</h2> <h2>{{counter*2}}</h2> </div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
firstName:"kobe",
lastName:"bryant",
counter:200
}
})
</script>
</body>

v-once 指令

该指令后面不需要跟任何表达式 ( 比如之前的 v-for 后面是由跟表达式的

该指令表示元素和组件 (组件后面才会学习) 只渲染 - 次, 不会随着数据的改变而改变

copy
<h2 v-once>{{massage}}</h2>

v-html

该指令后面往往会跟上一个 string 类型
会将 string 的 html 解析出来并且进行渲染

copy
<h2>{{url}}</h2> <!-- <a href="www.baidu.com"> 百度一下 </a> --> <h2 v-html="url"></h2> <!-- 百度一下 -->

v-text

都是用于将数据显示在界面中,但是通常只接受一个 string 类型

copy
<h2 v-text="massage">,洛依尘</h2> <!-- 你好 -->

v-pre

用于跳过这个元素和它子元素的编译过程, 用于显示原本的 Mustache 语法

copy
<h2 v-pre>{{massage}}</h2> <!-- {{massage}} -->

v-cloak

在某些情况下,f 防止浏览器可能会直接显然出未编译的 Mustache 标签。

copy
<style> [v-cloak] { display: none; } </style> </head>

<div id="app" v-cloak>
<h2>{{massage}}</h2>
<h2 v-once>{{massage}}</h2>
<h2>{{url}}</h2> <!-- <a href="www.baidu.com"> 百度一下 </a> -->
<h2 v-html="url"></h2> <!-- 百度一下 -->
<h2 v-text="massage">, 洛依尘</h2>
<!-- 你好 -->
<h2 v-pre>{{massage}}</h2> <!-- {{massage}} -->
</div>

<body>
<script src="../js/vue.js"></script>
<script>
// 在 vue 解析之前,div 里有一个属性 c-cloak
// 在 vue 解析之后,div 里没有一个属性 c-cloak
const app = new Vue({
el: "#app",
data: {
massage: "你好",
url: '<a href="www.baidu.com"> 百度一下 </a>'
}
})
</script>
</body>

2、绑定属性

v-bind

v-bind 用于绑定一个或多个属性值, 或者向另 - 一个组件传递 props 值

copy
<div id="app">

<!-- <img src="{{imgURL}}" alt=""> -->
<!-- 错误的用法: 这里不可以使用 mustache 语法 -->

<!-- 正确用法:使用 v-band 指令 -->
<a v-bind:href="aHref">百度</a>
<img v-bind:src='imgURL' alt="" >

<!-- 语法糖的写法 -->
<a :href="aHref">百度</a>
<img :src='imgURL' alt="" >

</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
imgURL:'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
aHref:"https://www.baidu.com/"
}
})
</script>
</body>

v-bind 动态绑定 class(对象语法)

  • 可以通过 { } 绑定一个类
  • 也可以通过判断,传入多个值
  • 和普通类同时存在,并不冲突
  • 如果过于复杂,可以放在一个 methods 或者 computed 中
copy
<style> .active{ color: red; } </style> </head>

<div id="app">
<!-- <h2 class="active">{{massage}}</h2>
<h2 :class="active">{{massage}}</h2> -->

<!-- <h2 :class="{类名 1:ture, 类名 2:boolean}">{{massage}}</h2> 对 class 对象进行选择 -->
<h2 v-bind:class="{active: isActive , line: isLine}">{{massage}}</h2>
<!-- 将内容放在一个 methods 里,并调用 -->
<h2 v-bind:class="getClasses()">{{massage}}</h2>
<button v-on:click="bntClick">按钮</button>
<!-- 监听按钮,使用 bntClick 方法 -->
</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
active:'active',
isActive:true, // 设置 boolean 值决定是否启用
isLine:true
},
methods:{
bntClick: function(){
this.isActive=!this.isActive
},
getClasses:function(){
return {active: this.isActive, line: this.isLine}
}
}
})
</script>
</body>

v-bind 动态绑定 class(数组语法)

copy
<div id="app"> <!-- 如果在 [] 数组里的元素加了引号,代表他是一个字符串,而不是引用一个变量 --> <h2 :class="[active,line]">{{massage}}</h2> <h2 :class="['active','line']">{{massage}}</h2> <h2 :class="getClasses()">{{massage}}</h2> </div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
active:"aaa",
line:"bbb"
},
methods:{
getClasses:function(){
return [this.active,this.line]
}
}
})
</script>
</body>

小作业:点击列表中的哪一项, 那么该项的文字变成红色

copy
<style> .active { color: red; } </style> </head>

<div id="app">
<ul>
<li v-for="(item, index) in movies" :class="{active: currentIndex === index}" @click="liClick(index)">
<!-- {active: currentIndex === index} 当 currentIndex === index 为 true 时,改变颜色 -->
{{index}}.{{item}}
</li>
</ul>
</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
movies: ['海王', '火影忍者', '进击的巨人', '死神'],
currentIndex: 0
},
methods: {
liClick(index) {
this.currentIndex = index
}
}
})
</script>
</body>

v-bind 绑定 style

copy
<div id="app"> <!-- <h2 :style="{key( 属性名):value(属性值)}">{{massage}}</h2> -->

<!-- 这里要加 ' ' 要不然 vue 会去解析 50px 这个变量然后报错 -->
<h2 :style="{fontSize:'50px'}">{{massage}}</h2>

<!-- finalSize 当成一个变量在使用 -->
<h2 :style="{fontSize: finalSize}">{{massage}}</h2>

<!-- 也可以拼接 -->
<h2 :style="{fontSize: finalSize +'px',color:finalColor}">{{massage}}</h2>

<!-- 数组语法 -->
<h2 :style="[baseStyle,baseStyle1]">{{massage}}</h2>
</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
finalSize: 100,
finalColor: 'red',
baseStyle:{color:'red'},
baseStyle1:{fontSize:'75px'}
}
})
</script>
</body>

3、计算属性

一、什么是计算属性

  模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。

二、计算属性的用法

  在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。

copy
<div id="app"> <h2>{{firstName+' '+lastName}}</h2> <h2>{{fullName}}</h2> <h2>总价格:{{totalPrice}}</h2> </div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
firstName:"luo",
lastName:"yichen",
books:[
{id:100, name: 'java 核心技术' , price:100},
{id:101, name: 'c 核心技术' , price:100},
{id:102, name: 'php 核心技术' , price:100},
{id:103, name: 'python 核心技术' , price:100}
]
},
// computed: 计算属性 ()
computed:{
fullName:function(){
return this.firstName+' '+this.lastName
},
totalPrice:function(){
let result =0
for (let i=0;i < this.books.length; i++){
result += this.books[i].price
}
return result;
}
}
})
</script>

计算属性的 getter 和 setter

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

  • 在上面的例子中, 我们只是使用 getter 来读取。
  • 在某些情况下, 你也可以提供一个 setter 方法 (不常用)。
  • 在需要写 setter 的时候, 代码如下: .
copy
<div id="app"> <h2>{{fullName}}</h2> </div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
firstName: "luo",
lastName: "yichen",
},
computed: {
// fullName: function () {
// return this.firstName + ' ' + this.lastName
// }
// 计算属性一般没有 set 值,只读属性。
fullName:{
set: function(newValue){
const names = newValue.split(" ");
this.firstName = names[0];
this.lastName = names[1];
},
get: function(){
return this.firstName + ' ' + this.lastName
}
},
// 简洁写法
// fullName:function(){
// return this.firstName+' '+this.lastName
// }
}
})
</script>
</body>

计算属性与 methods 对比

copy
<div id="app"> <!-- 通过拼接:语法过于繁琐 --> <h2>{{firstName}} {{lastName}}</h2> <!-- 通过定义 methods 每次都要调用 --> <h2>{{getFullName()}}</h2> <!-- 通过 computed 如果没有发生改变只需要调用一次 --> <h2>{{fullName}}</h2> </div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
firstName: "luo",
lastName: "yichen"
},
methods: {
getFullName: function () {
return this.firstName + ' ' + this.lastName
}
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
</script>
</body>

4、事件监听

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

获取到浏览器参数的 event 对象: $event

copy
<div id="app"> <h2>{{counter}}</h2> <button v-on:click="increment">+</button> <button v-on:click="decrement">-</button> <!-- 语法糖 当没参数时()可以不用写 --> <button @click="increment">+</button> <button @click="decrement">-</button>

<!-- 事件调用时没有参数 -->
<button @click="bnt1Click()">按钮 1</button>
<button @click="bnt1Click">按钮 1</button>

<!-- 在事件定义前,写函数省略了小括号,但是方法本身需要一个参数, 这个时候
Vue 会将浏览器默认生成的 event 事件对象作为参数传入方法中 -->

<button @click="bnt2Click(123)">按钮 2</button>
<button @click="bnt2Click()">按钮 2</button>
<button @click="bnt2Click">按钮 2</button>

<!-- 定义方法时,我们需要 event 对象,同时又需要其他参数 -->
<!-- 在调用方式时,如何手动的获取到浏览器参数的 event 对象: $event -->
<button @click="bnt3Click('abc',$event)">按钮 3</button>
</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
counter: 0
},
methods:{
increment(){
this.counter++
},
decrement(){
this.counter--
},
bnt1Click(){
console.log("bnt1Click");
},
bnt2Click(abc){
console.log("--------------",abc);
},
bnt3Click(abc,event){
console.log("++++++++++++++", abc,event);
}
}
})

<span class="hljs-comment">// 如果我们函数需要参数,但是没有传入参数,那么函数的形参为undefined</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">abc</span>(<span class="hljs-params">name</span>){
  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name);
}
<span class="hljs-title function_">abc</span>()
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

</body>

v-on 的修饰符

  1. .stop 修饰符的使用

    当多对标签进行重叠的时候, 你点击最上面的一层标签的时候, 会自动的冒泡到他下面的所有标签上面
    .stop就是阻止冒泡使用的

  2. .prevent 修饰符的使用

    form表单提交时候或者在点击a标签的时候, 会阻止提交或跳转

  3. .keyup 监听某个键盘的键帽

    监听某个键盘的键位

  4. .once 修饰符的使用

    绑定后只会触发一次

copy
<div id="app"> <!-- 1. .stop --> <div @click='divClick'> aaaaa <button @click.stop='bntClick'>按钮</button> </div>

<!-- 2. .prevent -->
<form action="baidu">
<input type="submit" value="提交" @click.prevent='submitClick'>
</form>

<!-- 3. 监听某个键盘的键位 -->
<input type="text" @keyup.enter="keyUp">

<!-- 4. once 修饰符的使用 -->
<button @click.once='bnt2Click'>按钮</button>
</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好"
},
methods: {
bntClick() {
console.log('bnt')
},
divClick() {
console.log('div')
},
submitClick() {
console.log("submitClick")
},
keyUp() {
console.log("up")
},
bnt2Click() {
console.log('bnt2');
}
}
})
</script>
</body>

5、条件判断

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

copy
<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>

<h1>{{result}}</h1>

<h2 v-if="isShow">{{massage}}</h2>
<h1 v-else>当 isShow 为 false 时显示我</h1>

</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
isShow: true,
score: 99
},
computed: {
result() {
let showMessage = '';
if (this.score >= 90) {
showMessage = "优秀"
} else if (this.score >= 80) {
showMessage = "良好"
}
// ...
return showMessage
}
}
})
</script>
</body>

用户切换的小案例

copy
<div id="app"> <span v-if="isUser"> <label for="username">用户账号</label> <input type="text" id="username" placeholder="用户账号" key='username'> </span> <span v-else> <label for="emailname">用户邮箱</label> <input type="text" id="emailname" placeholder="用户邮箱" key='emailname'> </span> <button @click="isUser = !isUser">切换类型</button> </div>

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

小问题:

  • 如果我们在有输入内容的情况下, 切换了类型, 我们会发现文字依然显示之前的输入的内容。
  • 但是按道理讲, 我们应该切换到另外一个 input 元素中了。
  • 在另一个 input 元素中, 我们并没有输入内容。
  • 为什么会出现这个问题呢?

问题解答:

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

解决方案:

  • 如果我们不希望 Vue 出现类似重复利用的问题, 可以给对应的 input 添加 key
  • 并且我们需要保证 key 的不同

Virtual DOM 是什么?

img

Virtual DOM 其实就是一棵以 JavaScript 对象 (VNode 节点) 作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。

简单来说,可以把 Virtual DOM 理解为一个简单的 JS 对象,并且最少包含标签名 (tag)、属性(attrs) 和子元素对象 (children) 三个属性。不同的框架对这三个属性的命名会有点差别。

对于虚拟 DOM,咱们来看一个简单的实例,就是下图所示的这个,详细的阐述了模板 → 渲染函数 → 虚拟DOM树 → 真实DOM的一个过程

img

Virtual DOM 作用是什么?

虚拟 DOM 的最终目标是将虚拟节点渲染到视图上。但是如果直接使用虚拟节点覆盖旧节点的话,会有很多不必要的 DOM 操作。例如,一个 ul 标签下很多个 li 标签,其中只有一个 li 有变化,这种情况下如果使用新的 ul 去替代旧的 ul, 因为这些不必要的 DOM 操作而造成了性能上的浪费。

为了避免不必要的 DOM 操作,虚拟 DOM 在虚拟节点映射到视图的过程中,将虚拟节点与上一次渲染视图所使用的旧虚拟节点(oldVnode)做对比,找出真正需要更新的节点来进行 DOM 操作,从而避免操作其他无需改动的 DOM。

其实虚拟 DOM 在 Vue.js 主要做了两件事:

  • 提供与真实 DOM 节点所对应的虚拟节点 vnode
  • 将虚拟节点 vnode 和旧虚拟节点 oldVnode 进行对比,然后更新视图

v-if 和 v-show 的区别

v-show 控制的是节点的 display 属性 v-if 是将节点删除了 如果节点需要频繁显示隐藏 使用 v-show 性能更佳!

copy
<div id="app"> <!-- v-if: 当条件为 false 时,包含 v-if 指令的元素,根本就不会存在 dom 中 --> <h2 v-if='isShow' id="aaa">{{massage}}</h2> <!-- V- show: 当条件为 false 时,v-show 只是给我们的元素添加一个行内样式: display: none --> <h2 v-show='isShow' id="bbb">{{massage}}</h2> </div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好",
isShow: true
}
})
</script>
</body>

6、循环遍历

当我们有一组数据需 要进行渲染时, 我们就可以使用 v-for 来完成。
v-for 的语法类似于 JavaScript 中的 for 循环。
格式如下: item in items 的形式。

copy
<div id="app"> <!-- 1. 在遍历的过程中,没有使用索引值(下标值) --> <ul> <li v-for='item in names'>{{item}}</li> </ul>

<!-- 2. 在遍历过程中, 获取索引值 -->
<ul>
<li v-for='(item,index) in names'>
{{index+1}}.{{item}}
</li>
</ul>

<!-- 1. 在遍历对象的过程中,如果只是获取一个值,那么获取到的是 value -->
<ul>
<li v-for="item in info">{{item}}</li>
</ul>
<!-- 2., 获取 key 和 value 格式 (value,key) -->
<ul>
<li v-for="(value,key) in info">{{value}}-{{key}}</li>
</ul>
<!-- 3. 获取 key 和 value 和 index 格式 (value,key,index)-->
<ul>
<li v-for="(value,key,index) in info">{{value}}-{{key}}-{{index}}</li>
</ul>
</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
names: ['why', 'who', 'what', 'where'] // 遍历数组
},
info: { // 遍历对象
name: 'lyc',
age: 18,
height: 1.88
}
})
</script>
</body>

v-for 加 key 属性

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

    • 这个其实和 Vue 的虚拟 DOM 的 Diff 算法有关系。
    • 这里我们借用 React' S diff algorithm 中的一张图来简单说明一下:
  • 当某一层有很多相同的节点时, 也就是列表节点时, 我们希望插入一一个新
    的节点

    • 我们希望可以在 B 和 C 之间加一一个 F , Diff 算法默认执行起来是这样的。
    • 即把 C 更新成 F , D 更新成 C , E 更新成 D , 最后再插入 E , 是不是很没有
      效率?
  • 所以我们需要使用 key 来给每个节点做一个唯一标识

    • Diff 算法就可以正确的识别此节点

    • 0 找到正确的位置区插入新的节点。

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

image-20210517163534869

image-20210517163043021

哪些数组方法是响应式的

copy
<body> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { letters: ['A', 'C', 'B', 'D', 'E'] }, methods: { btnClick() { // 1.push() 在数组最后添加元素 this.letters.push('aaa','bbb')
      <span class="hljs-comment">// 2.pop()      在数组最后删除一个元素</span>
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>.<span class="hljs-title function_">pop</span>();

      <span class="hljs-comment">// 3.shift()   删除在数组第一个元素</span>
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>.<span class="hljs-title function_">shift</span>();

      <span class="hljs-comment">// 4.unshift() 在数组最前面添加元素</span>
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>.<span class="hljs-title function_">unshift</span>(<span class="hljs-string">'ddd'</span>,<span class="hljs-string">'ddd'</span>);

      <span class="hljs-comment">// 5.splice()   删除/插入/替换元素</span>
      <span class="hljs-comment">// 删除元素: 第一参数传入你从第几个元素开始删除,第二参数传入你要删除的几个元素(如果没有传,就删除后面所有元素)</span>
      <span class="hljs-comment">// 插入元素: 第二个传入0,后面跟上要添加的值</span>
      <span class="hljs-comment">// 替换元素: 第二参数传入你要删除元素,后面追加你要写入的元素完成替换</span>
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>.<span class="hljs-title function_">splice</span>(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>,<span class="hljs-string">'m'</span>,<span class="hljs-string">'n'</span>,<span class="hljs-string">'l'</span>)

      <span class="hljs-comment">// 6.sort()     排序</span>
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>.<span class="hljs-title function_">sort</span>()

      <span class="hljs-comment">// 7.reverse()  反转</span>
      <span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>.<span class="hljs-title function_">reverse</span>()

      <span class="hljs-comment">// 注意:通过索引值直接来修改数组中的元素 不是响应式</span>
      <span class="hljs-comment">// this.letters[0]='bbbbbbbbbbbb'</span>
      <span class="hljs-comment">// set(要修改的对象,索引值,修改后的值)</span>
      <span class="hljs-title class_">Vue</span>.<span class="hljs-title function_">set</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">letters</span>,<span class="hljs-number">0</span>,<span class="hljs-string">'bbbbbb'</span>)
    }
  }
})

<span class="hljs-comment">// 扩展知识:可变参数</span>
<span class="hljs-comment">// function sum(...sum){</span>
<span class="hljs-comment">//   console.log(sum);</span>
<span class="hljs-comment">// }</span>
<span class="hljs-comment">// sum(11,223,44,56,77,889,9,1)</span>

</script>
</body>

6、表单绑定

  • 表单控件在实际开发中是非常常见的。特别是对于用户信息的提交, 需要大量的表单。
  • Vue 中使用 v-model 指令来实现表单元素和数据的双向绑定。
copy
<body>

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

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

  • 当我们在输入框输入内容时
  • 因为 input 中的 v-model 绑定了 message , 所以会实时将输入的内容传递给 message , message 发生改变。
  • 当 message 发生改变时, 因为上面我们使用 Mustache 语法, 将 message 的值插入到 DOM 中, 所以 DOM 会发生响应的改变。
  • 所以, 通过 v-model 实现了双向的绑定。

原理:

copy
<div id="app"> <!-- <input type="text" v-model="massage"> --> <!-- <input type="text" :value="massage" @input="valueChange"> --> <input type="text" :value="massage" @input="massage = $event.target.value"> {{massage}} </div>

<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
massage: "你好"
},
methods: {
valueChange(event) {
this.massage = event.target.value;
}
}
})
</script>

</body>

v-model 结合 radio 类型

copy
<div id="app"> <label for=""> <input type="radio" id="male" value="男" v-model="sex"></label> <label for=""> <input type="radio" id="female" value="女" v-model="sex"></label> <h2>{{sex}}</h2> </div>

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

v-model 结合 checkbox 类型

单个勾选框: .

  • v-modelI 即为布尔值。
  • 此时 input 的 value 并不影响 v-model 的值。

多个复选框:

  • 多个复选框时, 因为可以选中多个, 所以对应的 data 中属性是一个数组。
  • 当选中某一个时 , 就会将 input 的 value 添加到数组中。
copy
<div id="app"> <!-- 单选框 --> <!-- <label for="agree"> <input type="checkbox" id="agree" v-model="isAgree"> 同意协议 </label> <h2>{{isAgree}}</h2> <button :disabled="!isAgree"> 下一步 </button> -->

<!-- 多选框 -->
<!-- <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> -->

<span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"item in originHobbies"</span> <span class="hljs-attr">:for</span>=<span class="hljs-string">"item"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">:value</span>=<span class="hljs-string">"item"</span> <span class="hljs-attr">:id</span>=<span class="hljs-string">"item"</span> <span class="hljs-attr">v-model</span>=<span class="hljs-string">"hobbies"</span>&gt;</span>{{item}}
<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

</div>

<body>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
message: "你好",
isAgree: false,// 单选框
hobbies:[],// 多选框
originHobbies:['篮球','足球','乒乓球','台球','高尔夫球']
// 也可以通过值绑定来从服务器获取值
}
})
</script>
</body>

v-model 结合 select

单选: 只能选中一个值。

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

多选: 可以选中多个值。

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

<div id="app">
<!-- 1、选择一个 -->
<select name="abc" id="" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="榴莲">榴莲</option>
<option value="西瓜">西瓜</option>
</select>
<h2>{{fruit}}</h2>

<span class="hljs-comment">&lt;!-- 2、选择多个 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"abc"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">""</span>  <span class="hljs-attr">v-model</span>=<span class="hljs-string">"fruits"</span> <span class="hljs-attr">multiple</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"苹果"</span>&gt;</span>苹果<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"香蕉"</span>&gt;</span>香蕉<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"榴莲"</span>&gt;</span>榴莲<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"西瓜"</span>&gt;</span>西瓜<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{{fruits}}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

</div>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"../js/vue.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="language-javascript">
  <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Vue</span>({
    <span class="hljs-attr">el</span>: <span class="hljs-string">"#app"</span>, 
    <span class="hljs-attr">data</span>: {
      <span class="hljs-attr">message</span>: <span class="hljs-string">"你好"</span>,
      <span class="hljs-attr">fruit</span>:<span class="hljs-string">"香蕉"</span>,
      <span class="hljs-attr">fruits</span>:[]
    }
  })
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

</body>

v-model 的修饰符

lazy 修饰符:

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

number 修饰符:

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

trim 修饰符:

  • 如果输入的内容首尾有很多空格, 通常我们希望将其去除
  • trim 修饰符可以过滤内容左右两边的空格
copy
<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>{{typeof age}}</h2>

<!-- 3. 修饰符:trim -->
<input type="text" v-model.trim="name">
<h2>{{name}}</h2>
</div>

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

综合 - 书籍购物车案例

  • HTML
copy
<!DOCTYPE html> <html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">

</head>

<body>

<div id="app">
<div v-if="books.length">
<table>
<thead>
<tr>
<th></th>
<th>书籍名称</th>
<th> 出版日期</th>
<th> 价格</th>
<th> 购买数量</th>
<th> 操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price | showPrice}}</td>
<td>
<button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button>
{{item.count}}
<button @click="increment(index)">+</button>
</td>
<td><button @click="removeHandler(index)">移除</button></td>
</tr>
</tbody>
</table>
<h2>
总价格: {{totalPrice | showPrice}}
</h2>
</div>
<div v-else>
<h1>购物车为空</h1>
</div>
</div>
<script src="../js/vue.js"></script>
<script src="./main.js"></script>
</body>

</html>

  • CSS
copy
table{ border: 1px solid #000; border-collapse: collapse; border-spacing: 0; } th,td{ padding: 8px 16px; border: 1px solid #000; text-align: left; }

th{
background-color: #f7f7f7;
color: #5c6b77;
font-weight: 600;
}

  • JS
copy
const app = new Vue({ el: "#app", data: { books: [{ id: 1, name: '《算法导论》', date: "2006-9", price: 85.00, count: 1 }, { id: 2, name: '《算法导论》', date: "2006-9", price: 85.00, count: 1 }, { id: 3, name: '《算法导论》', date: "2006-9", price: 85.00, count: 1 }, { id: 4, name: '《算法导论》', date: "2006-9", price: 85.00, count: 1 } ] }, methods: { // getFinalPrice(price){ // return '¥'+price.toFixed(2) //toFixed(2) 保留两位小数 // } increment(index) { this.books[index].count++ }, decrement(index) { this.books[index].count-- }, removeHandler(index) { this.books.splice(index, 1) } }, filters: { // 过滤器 showPrice(price) { return '¥' + price.toFixed(2) } }, computed: { totalPrice() { let totalPrice = 0; for (let i = 0; i < this.books.length; i++) { totalPrice += this.books[i].price * this.books[i].count; } return totalPrice; } } })

JS 高阶函数

编程范式:命令式编程 / 声明式编程

编程范式:面向对象编程 (第一公民: 对象)/ 函数式编程(第一公民: 函数 )

filter/map/reduce

filter 中的回调函数有一个要求:必须返回一个 boolean 值

true: 当返回 true 时,函数内部会自动将这次回调的 n 加入到新的数组中

false: 当返回 false 时,函数内部会过滤掉这次的 n

  • 基本写法
copy
const nums = [10,20,111,222,444,40,50]

// 1. 需求: 取出小于 100 的数字
let newNums = []
for(let n of nums){
if(n > 100){
newNums.push(n)
}
}

// 2. 需求:将所有小于 160 的数字进行转化:全部2
let new2Nums = []
for(let n of newNums){
new2Nums.push(n
2)
}

// 3. 需求:将所有 new2Nums 数字相加,得到最终的记过
let total = 0
for(let n of new2Nums){
total +=n
}
console.log(total)

  • 高阶写法
copy
const nums = [10,20,111,222,444,40,50] // 1.filter 函数的使用 let newNums = nums.filter(function(n){ return n<100 }) console.log(newNums)

// 2.map 函数的使用
let new2Nums = newNums.map(function(n){
return n*2
})
console.log(new2Nums)

// 3.reduce 函数的使用
// reduce 作用对数组中所有的内容进行汇总
let total = new2Nums.reduce(function(preValue,n){
return preValue + n;
},0)
console.log(total)
// 第一次: revalue 0 n 20
// 第二次: revalue 20 n 40
// 第二次: revalue 60 n 80
// 第二次: revalue 140 n 100
// 240

  • 高阶综合写法
copy
const nums = [10,20,111,222,444,40,50]

// 综合
let total = nums.filter(function(n){
return n<100
}).map(function(n){
return n*2
}).reduce(function(preValue,n){
return preValue + n;
},0) // 初始化
console.log(total)

// 使用箭头函数进一步简化
let total = nums.filter(n => n<100).map(n => n*2).reduce((pre,n) => pre+n)
console.log(total)

点击转跳第二部分内容