个人微信公众号:程序猿的月光宝盒
〇.高阶函数
0.1 filter()
const nums = [10, 20, 111, 222, 444, 40, 50]
// 1.filter函数的使用
// filter中的回调函数有一个要求: 必须返回一个boolean值
// true: 当返回true时, 函数内部会自动将这次回调的n加入到新的数组中
// false: 当返回false时, 函数内部会过滤掉这次的n
// 10, 20, 40, 50
let newNums = nums.filter(function (n) {
return n < 100
});
console.log(newNums);
0.2 map()
const nums = [10, 20, 111, 222, 444, 40, 50]
// 2.map函数的使用
// 原来的newNums*2倍
// 20, 40, 80, 100
//newNums是 0.1步骤的结果
let new2Nums = newNums.map(function (n) {
return n * 2
});
console.log(new2Nums);
0.3 reduce()
const nums = [10, 20, 111, 222, 444, 40, 50]
// 3.reduce函数的使用
// reduce作用对数组中所有的内容进行汇总(相加)
//new2Nums是0.2步骤的结果
let total = new2Nums.reduce(function (preValue, n) {
return preValue + n
}, 0);
console.log(total);
// 流程:
// 第一次: preValue 0, n 20
// 第二次: preValue 0+20=20, n 40
// 第三次: preValue 20+40=60, n 80
// 第四次: preValue 20+40+80=140, n 100
// 最终结果:140+100=240
// 编程范式: 命令式编程/声明式编程
// 编程范式: 面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)
// filter/map/reduce
let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
console.log(total);
// 传统的:
// // 1.需求: 取出所有小于100的数字
let newNums = []
for (let n of nums) {
if (n < 100) {
newNums.push(n)
}
}
// 2.需求:将所有小于100的数字进行转化: 全部*2
let new2Nums = []
for (let n of newNums) {
new2Nums.push(n * 2)
}
console.log(new2Nums);
// 3.需求:将所有new2Nums数字相加,得到最终的结果
let total = 0
for (let n of new2Nums) {
total += n
}
console.log(total);
用了高阶函数
// 取出小于100的
let total = nums.filter(function (n) {
return n < 100
// 把取出来的*2
}).map(function (n) {
return n * 2
// 然后再求和
}).reduce(function (prevValue, n) {
return prevValue + n
}, 0);
console.log(total);
一. 表单绑定v-model
表单控件在实际开发中是非常常见的。特别是对于用户信息的提交,需要大量的表单。
Vue中
使用v-model
指令来实现表单元素和数据的双向绑定
。
1.1. v-model的基本使用
-
v-model 原理=>
v-bind:value
加上v-on:input
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <input type="text" v-model="message"> {{message}} </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊' } }) </script> </body> </html>
解析:
当我们在输入框输入内容时,因为
input
中的v-model
绑定了message
,所以会实时将输入的内容传递给message
,message
发生改变。 当
message
发生改变时,因为上面我们使用Mustache
语法,将message
的值插入到DOM
中,所以DOM
会发生响应的改变。 所以,通过
v-model
实现了双向的绑定。也可以将
v-model
用于textarea
原理:
v-model
其实是一个语法糖
,它的背后本质
上是包含两个操作: 1.
v-bind
绑定一个value
属性 2.
v-on
指令给当前元素绑定input
事件也就是说:
<input type="text" v-model="message">
等同于
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">
1.2. v-model和radio/checkbox/select
1.2.1 v-model
和radio
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<label for="male">
<input type="radio" id="male" value="男" v-model="sex">男
</label>
<label for="female">
<input type="radio" id="female" value="女" v-model="sex">女
</label>
<h2>您选择的性别是: {{sex}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
sex: '女'
}
})
</script>
</body>
</html>
1.2.2 v-model
和checkbox
与值绑定
复选框分为两种情况:单个勾选框和多个勾选框
单个勾选框:
v-model即为布尔值。
此时input的value并不影响v-model的值。
多个复选框:
当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。
当选中某一个时,就会将input的value添加到数组中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--1.checkbox单选框-->
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<h2>您选择的是: {{isAgree}}</h2>
<button :disabled="!isAgree">下一步</button>
<!--2.checkbox多选框-->
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="足球" v-model="hobbies">足球
<input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
<input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
<h2>您的爱好是: {{hobbies}}</h2>
<!-- 从服务器获取的originHobbies,也就是所谓的值绑定 -->
<label v-for="item in originHobbies" :for="item">
<input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
</label>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isAgree: false, // 单选框,默认没选 为false
hobbies: [], // 多选框,
originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球', '高尔夫球']
}
})
</script>
</body>
</html>
1.2.3 v-model
和select
和checkbox一样,select也分单选和多选两种情况。
单选:只能选中一个值。
v-model绑定的是一个值。
当我们选中option中的一个时,会将它对应的value赋值到fruit中
多选:可以选中多个值。
v-model绑定的是一个数组。
当选中多个值时,就会将选中的option对应的value添加到数组fruits中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--1.选择一个-->
<select name="abc" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="榴莲">榴莲</option>
<option value="葡萄">葡萄</option>
</select>
<h2>您选择的水果是: {{fruit}}</h2>
<!--2.选择多个 multiple属性 -->
<select name="abc" v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="榴莲">榴莲</option>
<option value="葡萄">葡萄</option>
</select>
<h2>您选择的水果是: {{fruits}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
// 默认选香蕉
fruit: '香蕉',
fruits: ['香蕉']
}
})
</script>
</body>
</html>
1.3. 修饰符
-
lazy
默认情况下,
v-mode
l默认是在input事件中同步输入框的数据的。也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
lazy修饰符可以让数据在失去焦点或者回车时才会更新:
-
number 只能是number类型的数据,但是input默认是空的字符串
默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
number修饰符可以让在输入框中输入的内容自动转成数字类型
-
trim
如果输入的内容首尾有很多空格,通常我们希望将其去除
trim修饰符可以过滤内容左右两边的空格
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!--1.修饰符: lazy 就是失去焦点或者按了回车后,改变--> <input type="text" v-model.lazy="message"> <h2>{{message}}</h2> <!--2.修饰符: number--> <input type="number" v-model.number="age"> <h2>{{age}}-{{typeof age}}</h2> <!--3.修饰符: trim--> <input type="text" v-model.trim="name"> <h2>您输入的名字:{{name}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊', age: 0, name: '' } }) </script> </body> </html>
二. 组件化开发
2.1. 认识组件化
人面对复杂问题的处理方式:
任何一个人处理信息的逻辑能力都是有限的
所以,当面对一个非常复杂的问题时,我们不太可能一次性搞定一大堆的内容。
但是,我们人有一种天生的能力,就是将问题进行拆解。
如果将一个复杂的问题,拆分成很多个可以处理的小问题,再将其放在整体当中,你会发现大的问题也会迎刃而解。
组件化也是类似的思想:
如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。
但如果,我们讲一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。
Vue组件化思想
组件化是Vue.js中的重要思想
它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
任何的应用都会被抽象成一颗组件树。
组件化思想的应用:
有了组件化的思想,我们在之后的开发中就要充分的利用它。
尽可能的将页面拆分成一个个小的、可复用的组件。
这样让我们的代码更加方便组织和管理,并且扩展性也更强。
所以,组件是Vue开发中,非常重要的一个篇章。
2.2. 组件的基本步骤
注册组件的基本步骤
组件的使用分成三个步骤:
1.创建组件构造器
2.注册组件
3.使用组件。
我们来看看通过代码如何注册组件
查看运行结果:
和直接使用一个div看起来并没有什么区别。
但是我们可以设想,如果很多地方都要显示这样的信息,我们是不是就可以直接使用<my-cpn></my-cpn>
来完成呢?
步骤解析
1.Vue.extend():
调用Vue.extend()创建的是一个组件构造器。
通常在创建组件构造器时,传入template代表我们自定义组件的模板。
该模板就是在使用到组件的地方,要显示的HTML代码。
事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础。
2.Vue.component():
调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称。
所以需要传递两个参数:
1、注册组件的标签名
2、组件构造器
3.组件必须挂载在某个Vue实例下,否则它不会生效。
我们来看下面我使用了三次<my-cpn></my-cpn>
而第三次其实并没有生效:
2.3. 全局组件和局部组件
当我们通过调用Vue.component()****注册组件时,组件的注册是全局的
这意味着该组件可以在任意Vue示例下使用。
如果我们注册的组件是挂载在某个实例中, 那么就是一个局部组件
2.4. 父组件和子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn2></cpn2>
<!--<cpn1></cpn1>-->
</div>
<script src="../js/vue.js"></script>
<script>
// 1.创建第一个组件构造器(子组件)
const cpnC1 = Vue.extend({
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
})
// 2.创建第二个组件构造器(父组件),并在其中注册子组件
const cpnC2 = Vue.extend({
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵呵</p>
<cpn1></cpn1>
</div>
`,
// 在父组件中注册子组件
components: {
cpn1: cpnC1
}
})
// root组件
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
//注册父组件(局部组件)
components: {
cpn2: cpnC2
}
})
</script>
</body>
</html>
2.5. 注册的语法糖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>
// 1.全局组件注册的语法糖
// 1.创建组件构造器
// const cpn1 = Vue.extend({
// template: `
// <div>
// <h2>我是标题1</h2>
// <p>我是内容, 哈哈哈哈</p>
// </div>
// `
// })
// 2.注册全局组件
Vue.component('cpn1', {
template: `
<div>
<h2>我是标题1</h2>
<p>我是内容, 哈哈哈哈</p>
</div>
`
});
// 2.注册局部组件的语法糖
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
'cpn2': {
template: `
<div>
<h2>我是标题2</h2>
<p>我是内容, 呵呵呵</p>
</div>
`
}
}
})
</script>
</body>
</html>
2.6. 模板的分类写法
刚才,我们通过语法糖简化了Vue组件的注册过程,另外还有一个地方的写法比较麻烦,就是template模块写法。
如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰。
Vue提供了两种方案来定义HTML模块内容:
-
script
-
template
2.7. 数据的存放
- 子组件不能直接访问父组件
- 子组件中有自己的data属性, 而且必须是一个函数.也可以有methods等属性
- 为什么必须是一个函数.
- 首先,如果不是一个函数,Vue直接就会报错。
- 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响。
2.8. 父子组件的通信
-
父传子: props
-
子传父: $emit
2.8.1 props基本用法(父传子)
props的值有两种方式:
方式一:字符串数组,数组中的字符串就是传递时的名称。
方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。
2.8.1.2 props数据验证(对象写法)
验证都支持哪些数据类型呢?
1.String
2.Number
3.Boolean
4.Array
5.Object
6.Date
7.Function
8.Symbol
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--<cpn v-bind:cmovies="movies"></cpn>-->
<!--<cpn cmovies="movies" cmessage="message"></cpn>-->
<cpn :cmessage="message" :cmovies="movies"></cpn>
</div>
<template id="cpn">
<div>
<ul>
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 父传子: props
const cpn = {
template: '#cpn',
// props: ['cmovies', 'cmessage'],
props: {
// 1.类型限制
// cmovies: Array,
// cmessage: String,
// 2.提供一些默认值, 以及必传值
cmessage: {
type: String,
default: 'aaaaaaaa',
required: true
},
// 类型是对象或者数组时, 默认值必须是一个函数
cmovies: {
type: Array,
//是个函数
default() {
return []
}
}
},
data() {
return {}
},
methods: {
}
}
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
movies: ['海王', '海贼王', '海尔兄弟']
},
components: {
cpn
}
})
</script>
</body>
</html>
当有自定义构造函数时,验证也支持自定义的类型
2.8.2 自定义事件的基本用法(子传父)
什么时候需要自定义事件呢?
当子组件需要向父组件传递数据时,就要用到自定义事件了。
我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。
自定义事件的流程:
1.在子组件中,通过$emit()来触发事件。
2.在父组件中,通过v-on来监听子组件事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--父组件模板-->
<div id="app">
<!--v-on监听子组件的自定义事件-->
<cpn @item-click="cpnClick"></cpn>
</div>
<!--子组件模板-->
<template id="cpn">
<div>
<button v-for="item in categories"
@click="btnClick(item)">
{{item.name}}
</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
// 1.子组件
const cpn = {
template: '#cpn',
data() {
return {
categories: [
{id: 'aaa', name: '热门推荐'},
{id: 'bbb', name: '手机数码'},
{id: 'ccc', name: '家用家电'},
{id: 'ddd', name: '电脑办公'},
]
}
},
methods: {
btnClick(item) {
// 发射事件: 自定义事件
this.$emit('item-click', item)
}
}
}
// 2.父组件
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn
},
methods: {
cpnClick(item) {
console.log('cpnClick', item);
}
}
})
</script>
</body>
</html>