mirror of
https://github.com/Estom/notes.git
synced 2026-04-13 14:29:46 +08:00
补充了redis和vue的相关介绍,还没看,等开发的时候,重新学一下
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
## 1 实例
|
||||
|
||||
```
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
@@ -163,11 +163,11 @@ BodyInserter<Object, ReactiveHttpOutputMessage> inserter3
|
||||
```java
|
||||
WebClient.ResponseSpec response1 = uri1
|
||||
.body(inserter3)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
|
||||
.acceptCharset(Charset.forName("UTF-8"))
|
||||
.ifNoneMatch("*")
|
||||
.ifModifiedSince(ZonedDateTime.now())
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
|
||||
.acceptCharset(Charset.forName("UTF-8"))
|
||||
.ifNoneMatch("*")
|
||||
.ifModifiedSince(ZonedDateTime.now())
|
||||
.retrieve();
|
||||
```
|
||||
|
||||
|
||||
379
Vue/01-ES6补充.md
Normal file
379
Vue/01-ES6补充.md
Normal file
@@ -0,0 +1,379 @@
|
||||
# 1. 块级作用域
|
||||
|
||||
ES6之前没有块级作用域,ES5的var没有块级作用域的概念,只有function有作用域的概念,ES6的let、const引入了块级作用域。
|
||||
|
||||
ES5之前if和for都没有作用域,所以很多时候需要使用function的作用域,比如闭包。
|
||||
|
||||
## 1.1. 什么是变量作用域
|
||||
|
||||
变量在什么范围内可用,类似Java的全局变量和局部变量的概念,全局变量,全局都可用,局部变量只在范围内可用。ES5之前的var是没有块级作用域的概念,使用var声明的变量就是全局的。
|
||||
|
||||
```js
|
||||
{
|
||||
var name = 'zzz';
|
||||
console.log(name);
|
||||
}
|
||||
console.log(name);
|
||||
```
|
||||
|
||||
上述代码中{}外的`console.log(name)`可以获取到name值并打印出来,用var声明赋值的变量是全局变量,没有块级作用域。
|
||||
|
||||
## 1.2. 没有块级作用域造成的问题
|
||||
|
||||
### if块级
|
||||
|
||||
```javascript
|
||||
if(true){
|
||||
var name = 'zzz';
|
||||
func = function (){
|
||||
console.log(name);
|
||||
}
|
||||
func();
|
||||
}
|
||||
name = 'ttt';
|
||||
func();
|
||||
console.log(name);
|
||||
```
|
||||
|
||||
代码输出结果为`'zzz','ttt','ttt'`,第一次调用func(),此时name=‘zzz’,在if块外将name置成‘ttt’,此时生效了,if没有块级作用域。
|
||||
|
||||
### for块级
|
||||
|
||||
定义五个按钮,增加事件,点击哪个按钮打印“第哪个按钮被点击了”。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>块级作用域</title>
|
||||
</head>
|
||||
<body>
|
||||
<button>按钮1</button>
|
||||
<button>按钮2</button>
|
||||
<button>按钮3</button>
|
||||
<button>按钮4</button>
|
||||
<button>按钮5</button>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"> </script>
|
||||
<script>
|
||||
// 3.没有块级作用域引起的问题:for块级
|
||||
var btns = document.getElementsByTagName("button");
|
||||
for (var i = 0; i < btns.length; i++) {
|
||||
btns[i].addEventListener('click',function (param) {
|
||||
console.log("第"+i+"个按钮被点击了");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
for块级中使用`var`声明变量i时,是全局变量,点击任意按钮结果都是“第五个按钮被点击了”。说明在执行`btns[i].addEventListener('click',function())`时,for块级循环已经走完,此时`i=5`,所有添加的事件的i都是5。
|
||||
|
||||
改造上述代码,将for循环改造,由于函数有作用域,使用闭包能解决上述问题。
|
||||
|
||||
```javascript
|
||||
// 使用闭包,函数有作用域
|
||||
for (var i = 0; i < btns.length; i++) {
|
||||
(function (i) {
|
||||
btns[i].addEventListener('click',function (param) {
|
||||
console.log("第"+i+"个按钮被点击了");
|
||||
})
|
||||
})(i);
|
||||
}
|
||||
```
|
||||
|
||||
结果如图所示,借用函数的作用域解决块级作用域的问题,因为有块级作用域,每次添加的i都是当前i。
|
||||
|
||||

|
||||
|
||||
在ES6中使用let/const解决块级作用域问题,let和const有块级作用域,const定义常量,在for块级中使用let解决块级作用域问题。
|
||||
|
||||
```javascript
|
||||
// ES6使用let/const
|
||||
const btns = document.getElementsByTagName("button");
|
||||
for (let i = 0; i < btns.length; i++) {
|
||||
btns[i].addEventListener('click',function (param) {
|
||||
console.log("第"+i+"个按钮被点击了");
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
结果和使用闭包解决一致。
|
||||
|
||||
# 2. const的使用
|
||||
|
||||
1.const用来定义常量,赋值之后不能再赋值,再次赋值会报错。
|
||||
|
||||
```javascript
|
||||
<script>
|
||||
//1.定义常量,赋值后不能再赋值,在赋值报错
|
||||
const count = 1
|
||||
// count = 2
|
||||
</script>
|
||||
```
|
||||
|
||||
2.const不能只声明不赋值,会报错。
|
||||
|
||||
```javascript
|
||||
<script>
|
||||
//2.只声明不赋值,必须赋值
|
||||
// const count;
|
||||
</script>
|
||||
```
|
||||
|
||||
3.const常量含义是你不能改变其指向的对象,例如user,都是你可以改变user属性。
|
||||
|
||||
```javascript
|
||||
<script>
|
||||
//3.常量的含义是你不能改变其指向的对象user,但是你可以改变user属性
|
||||
const user = {
|
||||
name:"zzz",
|
||||
age:24,
|
||||
height:175
|
||||
}
|
||||
console.log(user)
|
||||
user.name = "ttt"
|
||||
user.age = 22
|
||||
user.height = 188
|
||||
console.log(user)
|
||||
</script>
|
||||
```
|
||||
|
||||
**const内存地址详解**
|
||||
|
||||

|
||||
|
||||
对象count一开始只是0x10的地址,直接将count(给count重新赋值,指向一个新的对象)指向地址改为0x20会报错,const是常量,无法更改对象地址。
|
||||
|
||||
对象user一开始指向0x10地址,user有`Name`、`Age`、`Height`三个属性,此时修改属性`Name='ttt'`,user对象的地址未改变,不会报错。
|
||||
|
||||
# 3. ES6的增强写法
|
||||
|
||||
## 3.1. ES6的对象属性增强型写法
|
||||
|
||||
ES6以前定义一个对象
|
||||
|
||||
```javascript
|
||||
const name = "zzz";
|
||||
const age = 18;
|
||||
const user = {
|
||||
name:name,
|
||||
age:age
|
||||
}
|
||||
console.log(user);
|
||||
```
|
||||
|
||||
ES6写法
|
||||
|
||||
```javascript
|
||||
const name = "zzz";
|
||||
const age = 18;
|
||||
const user = {
|
||||
name,age
|
||||
}
|
||||
console.log(user);
|
||||
```
|
||||
|
||||
## 3.2 ES6对象的函数增强型写法
|
||||
|
||||
ES6之前对象内定义函数
|
||||
|
||||
```javascript
|
||||
const obj = {
|
||||
run:function(){
|
||||
console.log("奔跑");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
ES6写法
|
||||
|
||||
```javascript
|
||||
const obj = {
|
||||
run(){
|
||||
console.log("奔跑");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 4. 箭头函数
|
||||
|
||||
> 传统定义函数的方式
|
||||
|
||||
```javascript
|
||||
const aaa = function (param) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
> 对象字面量中定义函数
|
||||
|
||||
```javascript
|
||||
const obj = {
|
||||
bbb (param) { },
|
||||
}
|
||||
```
|
||||
|
||||
> ES6中的箭头函数
|
||||
|
||||
```javascript
|
||||
//const ccc = (参数列表) => {}
|
||||
const ccc = () => {}
|
||||
```
|
||||
|
||||
## 4.1 箭头函数的参数和返回值
|
||||
|
||||
### 4.1.1 参数问题
|
||||
|
||||
> 1.放入两个参数
|
||||
|
||||
```javascript
|
||||
const sum = (num1,num2) => {
|
||||
return num1 + num2
|
||||
}
|
||||
```
|
||||
|
||||
> 2.放入一个参数,()可以省略
|
||||
|
||||
```javascript
|
||||
const power = num => {
|
||||
return num * num
|
||||
}
|
||||
```
|
||||
|
||||
### 4.1.2 函数内部
|
||||
|
||||
> 1.函数中代码块中有多行代码
|
||||
|
||||
```javascript
|
||||
const test = () =>{
|
||||
console.log("hello zzz")
|
||||
console.log("hello vue")
|
||||
}
|
||||
```
|
||||
|
||||
> 2.函数代码块中只有一行代码,可以省略return
|
||||
|
||||
```javascript
|
||||
// const mul = (num1,num2) => {
|
||||
// return num1 * num2
|
||||
// }
|
||||
const mul = (num1,num2) => num1* num2
|
||||
// const log = () => {
|
||||
// console.log("log")
|
||||
// }
|
||||
const log = () => console.log("log")
|
||||
```
|
||||
|
||||
## 4.3 箭头函数的this使用
|
||||
|
||||
> 什么时候使用箭头函数
|
||||
|
||||
```javascript
|
||||
setTimeout(function () {
|
||||
console.log(this)
|
||||
} , 1000);
|
||||
setTimeout(() => {
|
||||
console.log(this)//这里this找的是window的this
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
> 结论:箭头函数没有this,这里this引用的是最近作用域(aaa函数里的this)的this。
|
||||
|
||||
```javascript
|
||||
const obj = {
|
||||
aaa(){
|
||||
setTimeout(function () {
|
||||
console.log(this)//window
|
||||
});
|
||||
setTimeout(() => {
|
||||
console.log(this)//obj
|
||||
});
|
||||
}
|
||||
}
|
||||
obj.aaa()
|
||||
```
|
||||
|
||||
> 上述中第一个是window对象的this,第二个箭头函数的this是obj的。
|
||||
|
||||
```javascript
|
||||
const obj = {
|
||||
aaa() {
|
||||
setTimeout(function () {
|
||||
setTimeout(function () {
|
||||
console.log(this) //window
|
||||
})
|
||||
setTimeout(() => {
|
||||
console.log(this) //window
|
||||
})
|
||||
})
|
||||
setTimeout(() => {
|
||||
setTimeout(function () {
|
||||
console.log(this) //window
|
||||
})
|
||||
setTimeout(() => {
|
||||
console.log(this) //obj
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
obj.aaa()
|
||||
```
|
||||
|
||||
# 5. 高阶函数
|
||||
|
||||
## 5.1 filter过滤函数
|
||||
|
||||
```javascript
|
||||
const nums = [2,3,5,1,77,55,100,200]
|
||||
//要求获取nums中大于50的数
|
||||
//回调函数会遍历nums中每一个数,传入回调函数,在回调函数中写判断逻辑,返回true则会被数组接收,false会被拒绝
|
||||
let newNums = nums.filter(function (num) {
|
||||
if(num > 50){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
//可以使用箭头函数简写
|
||||
// let newNums = nums.filter(num => num >50)
|
||||
```
|
||||
|
||||
## 5.2 map高阶函数
|
||||
|
||||
```javascript
|
||||
// 要求将已经过滤的新数组每项乘以2
|
||||
//map函数同样会遍历数组每一项,传入回调函数为参数,num是map遍历的每一项,回调函数function返回值会被添加到新数组中
|
||||
let newNums2 = newNums.map(function (num) {
|
||||
return num * 2
|
||||
})
|
||||
//简写
|
||||
// let newNums2 = newNums.map(num => num * 2)
|
||||
console.log(newNums2);
|
||||
```
|
||||
|
||||
## 5.3 reduce高阶函数
|
||||
|
||||
```javascript
|
||||
// 3.reduce高阶函数
|
||||
//要求将newNums2的数组所有数累加
|
||||
//reduce函数同样会遍历数组每一项,传入回调函数和‘0’为参数,0表示回调函数中preValue初始值为0,回调函数中参数preValue是每一次回调函数function返回的值,currentValue是当前值
|
||||
//例如数组为[154, 110, 200, 400],则回调函数第一次返回值为0+154=154,第二次preValue为154,返回值为154+110=264,以此类推直到遍历完成
|
||||
let newNum = newNums2.reduce(function (preValue,currentValue) {
|
||||
return preValue + currentValue
|
||||
},0)
|
||||
//简写
|
||||
// let newNum = newNums2.reduce((preValue,currentValue) => preValue + currentValue)
|
||||
console.log(newNum);
|
||||
```
|
||||
|
||||
## 5.4综合使用
|
||||
|
||||
```javascript
|
||||
//三个需求综合
|
||||
let n = nums.filter(num => num > 50).map(num => num * 2).reduce((preValue,currentValue) => preValue + currentValue)
|
||||
console.log(n);
|
||||
```
|
||||
|
||||
155
Vue/02-HelloVue.md
Normal file
155
Vue/02-HelloVue.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# 1. HelloVuejs
|
||||
|
||||
如何开始学习Vue,当然是写一个最简单的demo,直接上代码。此处通过cdn`<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>`获取vuejs。
|
||||
|
||||
vue是声明式编程,区别于jquery的命令式编程。
|
||||
|
||||
## 1.1. 命令式编程
|
||||
|
||||
原生js做法(命令式编程)
|
||||
|
||||
1. 创建div元素,设置id属性
|
||||
2. 定义一个变量叫message
|
||||
3. 将message变量放在div元素中显示
|
||||
4. 修改message数据
|
||||
5. 将修改的元素替换到div
|
||||
|
||||
## 1.2 . 声明式编程
|
||||
|
||||
vue写法(声明式)
|
||||
|
||||
1. 创建一个div元素,设置id属性
|
||||
2. 定义一个vue对象,将div挂载在vue对象上
|
||||
3. 在vue对象内定义变量message,并绑定数据
|
||||
4. 将message变量放在div元素上显示
|
||||
5. 修改vue对象中的变量message,div元素数据自动改变
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<title>HelloVuejs</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>{{message}}</h2>
|
||||
<p>{{name}}</p>
|
||||
</div>
|
||||
<script>
|
||||
//let变量/const常量
|
||||
//编程范式:声明式编程
|
||||
const app = new Vue({
|
||||
el:"#app",//用于挂载要管理的元素
|
||||
data:{//定义数据
|
||||
message:"HelloVuejs",
|
||||
name:"zzz"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
在谷歌浏览器中按F12,在开发者模式中console控制台,改变vue对象的message值,页面显示也随之改变。
|
||||
|
||||
`{{message}}`表示将变量message输出到标签h2中,所有的vue语法都必须在vue对象挂载的div元素中,如果在div元素外使用是不生效的。`el:"#app"`表示将id为app的div挂载在vue对象上,data表示变量对象。
|
||||
|
||||
# 2. vue列表的展示(v-for)
|
||||
|
||||
开发中常用的数组有许多数据,需要全部展示或者部分展示,在原生JS中需要使用for循环遍历依次替换div元素,在vue中,使用`v-for`可以简单遍历生成元素节点。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<title>vue列表展示</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>{{message}}</h2>
|
||||
<ul>
|
||||
<li v-for="(item, index) in movies" :key="index">{{item}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",//用于挂载要管理的元素
|
||||
data:{//定义数据
|
||||
message:"你好啊",
|
||||
movies:["星际穿越","海王","大话西游","复仇者联盟"]//定义一个数组
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
显示结果如图所示:
|
||||
|
||||

|
||||
|
||||
`<li v-for="(item, index) in movies" :key="index">{{item}}</li>`item表示当前遍历的元素,index表示元素索引, 为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 `key` 属性。建议尽可能在使用 `v-for` 时提供 `key` attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
|
||||
|
||||
因为它是 Vue 识别节点的一个通用机制,`key` 并不仅与 `v-for` 特别关联。
|
||||
|
||||
> 不要使用对象或数组之类的非基本类型值作为 `v-for` 的 `key`。请用字符串或数值类型的值。
|
||||
|
||||
# 3. vue案例-计数器
|
||||
|
||||
使用vue实现一个小计数器,点击`+`按钮,计数器+1,使用`-`按钮计数器-1。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<title>vue计数器</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>当前计数:{{count}}</h2>
|
||||
<!-- <button v-on:click="count--">-</button>
|
||||
<button v-on:click="count++">+</button> -->
|
||||
<button v-on:click="sub()">-</button>
|
||||
<button @click="add()">+</button>
|
||||
</div>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",//用于挂载要管理的元素
|
||||
data:{//定义数据
|
||||
count:0
|
||||
},
|
||||
methods: {
|
||||
add:function(){
|
||||
console.log("add")
|
||||
this.count++
|
||||
},
|
||||
sub:function(){
|
||||
console.log("sub")
|
||||
this.count--
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 定义vue对象并初始化一个变量count=0
|
||||
|
||||
2. 定义两个方法`add`和`sub`,用于对count++或者count--
|
||||
|
||||
3. 定义两个button对象,给button添加上点击事件
|
||||
|
||||
在vue对象中使用methods表示方法集合,使用`v-on:click`的关键字给元素绑定监听点击事件,给按钮分别绑定上点击事件,并绑定触发事件后回调函数`add`和`sub`。也可以在回调方法中直接使用表达式。例如:`count++`和`count--`。
|
||||
219
Vue/03-插值操作.md
Normal file
219
Vue/03-插值操作.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# 1. Mustache语法
|
||||
|
||||
mustache是胡须的意思,因为`{{}}`像胡须,又叫大括号语法。
|
||||
|
||||
在vue对象挂载的dom元素中,`{{}}`不仅可以直接写变量,还可以写简单表达式。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Mustache的语法</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>{{message}}</h2>
|
||||
<h2>{{message}},啧啧啧</h2>
|
||||
|
||||
<!-- Mustache的语法不仅可以直接写变量,还可以写简单表达式 -->
|
||||
<h2>{{firstName + lastName}}</h2>
|
||||
<h2>{{firstName + " " + lastName}}</h2>
|
||||
<h2>{{firstName}}{{lastName}}</h2>
|
||||
<h2>{{count * 2}}</h2>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊",
|
||||
firstName:"skt t1",
|
||||
lastName:"faker",
|
||||
count:100
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# 2. v-once
|
||||
|
||||
v-once表示该dom元素只渲染一次,之后数据改变,不会再次渲染。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h2>{{message}}</h2>
|
||||
<!-- 只会渲染一次,数据改变不会再次渲染 -->
|
||||
<h2 v-once>{{message}}</h2>
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
上述`{{message}}`的message修改后,第一个h2标签数据会自动改变,第二个h2不会。
|
||||
|
||||
# 3. v-html
|
||||
|
||||
在某些时候我们不希望直接输出`<a href='http://www.baidu.com'>百度一下</a>`这样的字符串,而输出被html自己转化的超链接。此时可以使用v-html。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-html指令的使用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>不使用v-html</h2>
|
||||
<h2>{{url}}</h2>
|
||||
<h2>使用v-html,直接插入html</h2>
|
||||
<h2 v-html="url"></h2>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊",
|
||||
url:"<a href='http://www.baidu.com'>百度一下</a>"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
输出结果如下:
|
||||
|
||||

|
||||
|
||||
# 4. v-text
|
||||
|
||||
v-text会覆盖dom元素中的数据,相当于js的innerHTML方法。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-text指令的使用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>不使用v-text</h2>
|
||||
<h2>{{message}},啧啧啧</h2>
|
||||
<h2>使用v-text,以文本形式显示,会覆盖</h2>
|
||||
<h2 v-text="message">,啧啧啧</h2>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
如图所示,使用`{{message}}`是拼接变量和字符串,而是用v-text是直接覆盖字符串内容。
|
||||
|
||||

|
||||
|
||||
# 5. v-pre
|
||||
|
||||
有时候我们期望直接输出`{{message}}`这样的字符串,而不是被`{{}}`语法转化的message的变量值,此时我们可以使用`v-pre`标签。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-pre指令的使用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>不使用v-pre</h2>
|
||||
<h2>{{message}}</h2>
|
||||
<h2>使用v-pre,不会解析</h2>
|
||||
<h2 v-pre>{{message}}</h2>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
结果如图,使用v-pre修饰的dom会直接输出字符串。
|
||||
|
||||

|
||||
|
||||
# 6. v-cloak
|
||||
|
||||
有时候因为加载延时问题,例如卡掉了,数据没有及时刷新,就造成了页面显示从`{{message}}`到message变量“你好啊”的变化,这样闪动的变化,会造成用户体验不好。此时需要使用到`v-cloak`的这个标签。在vue解析之前,div属性中有`v-cloak`这个标签,在vue解析完成之后,v-cloak标签被移除。简单,类似div开始有一个css属性`display:none;`,加载完成之后,css属性变成`display:block`,元素显示出来。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-cloak指令的使用</title>
|
||||
<style>
|
||||
[v-cloak]{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app" v-cloak>
|
||||
<h2>{{message}}</h2>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
//在vue解析前,div中有一个属性cloak
|
||||
//在vue解析之后,div中没有一个属性v-cloak
|
||||
setTimeout(() => {
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
message: "你好啊"
|
||||
}
|
||||
})
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
这里通过延时1秒模拟加载卡住的状态,结果一开始不显示message的值,div元素中有v-cloak的属性,1秒后显示message变量的值,div中的v-cloak元素被移除。
|
||||
|
||||

|
||||
|
||||
245
Vue/04-动态绑定属性.md
Normal file
245
Vue/04-动态绑定属性.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# 1. v-bind的基本使用
|
||||
|
||||
某些时候我们并不想将变量放在标签内容中,像这样`<h2>{{message}}</h2>`是将变量h2标签括起来,类似js的innerHTML。但是我们期望将变量`imgURL`写在如下位置,想这样`<img src="imgURL" alt="">`导入图片是希望动态获取图片的链接,此时的imgURL并非变量而是字符串imgURL,如果要将其生效为变量,需要使用到一个标签`v-bind:`,像这样`<img v-bind:src="imgURL" alt="">`,而且这里也不能使用Mustache语法,类似`<img v-bind:src="{{imgURL}}" alt="">`,这也是错误的。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-bind的基本使用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 错误的做法这里不能使用Mustache语法 -->
|
||||
<!-- <img v-bind:src="{{imgURL}}" alt=""> -->
|
||||
<!-- 正确的做法使用v-bind指令 -->
|
||||
<img v-bind:src="imgURL" alt="">
|
||||
<a v-bind:href="aHerf"></a>
|
||||
<!-- 语法糖写法 -->
|
||||
<img :src="imgURL" alt="">
|
||||
<a :href="aHerf"></a>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊",
|
||||
imgURL:"https://cn.bing.com/th?id=OIP.NaSKiHPRcquisK2EehUI3gHaE8&pid=Api&rs=1",
|
||||
aHerf:"http://www.baidu.com"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
此时vue对象中定义的`imgURL`变量和`aHerf`变量可以动态的绑定到img标签的src属性和a标签的href属性。`v-bind:`由于用的很多,vue对他有一个语法糖的优化写法也就是`:`,此时修改imgURL变量图片会重新加载。
|
||||
|
||||

|
||||
|
||||
# 2. v-bind动态绑定class
|
||||
|
||||
## 2.1. v-bind动态绑定class(对象语法)
|
||||
|
||||
有时候我们期望对Dom元素的节点的class进行动态绑定,选择此Dom是否有指定class属性。例如,给h2标签加上`class="active"`,当Dom元素有此class时候,变红`<style>.active{color:red;}</style>`,在写一个按钮绑定事件,点击变黑色,再次点击变红色。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-bind动态绑定class(对象语法)</title>
|
||||
<style>
|
||||
.active{
|
||||
color:red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- <h2 class="active">{{message}}</h2>
|
||||
<h2 :class="active">{{message}}</h2> -->
|
||||
|
||||
<!-- 动态绑定class对象用法 -->
|
||||
<!-- <h2 :class="{key1:value1,key2:value2}">{{message}}</h2>
|
||||
<h2 :class="{类名1:true,类名2:boolean}">{{message}}</h2> -->
|
||||
<h2 class="title" :class="{active:isActive}">{{message}}</h2>
|
||||
<h2 class="title" :class="getClasses()">{{message}}</h2>
|
||||
<button @click="change">点击变色</button>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊",
|
||||
active:"active",
|
||||
isActive:true
|
||||
},
|
||||
methods: {
|
||||
change(){
|
||||
this.isActive = !this.isActive
|
||||
},
|
||||
getClasses(){
|
||||
return {active:this.isActive}
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
定义两个变量`active`和`isActive`,在Dom元素中使用`:class={active:isActive}`,此时绑定的`class='active'`,isActive为true,active显示,定义方法change()绑定在按钮上,点击按钮`this.isActive = !this.isActive`,控制Dom元素是否有`class='active'`的属性。
|
||||
|
||||

|
||||
|
||||
## 2.2. v-bind动态绑定class(数组用法)
|
||||
|
||||
class属性中可以放数组,会依次解析成对应的class。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-bind动态绑定class(数组用法)</title>
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 加上单引号当成字符串 -->
|
||||
<h2 class="title" :class="['active','line']">{{message}}</h2>
|
||||
<!-- 不加会被当成变量 -->
|
||||
<h2 class="title" :class="[active,line]">{{message}}</h2>
|
||||
<h2 class="title" :class="getClasses()">{{message}}</h2>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊",
|
||||
active:"aaaa",
|
||||
line:'bbbb'
|
||||
},
|
||||
methods: {
|
||||
|
||||
getClasses(){
|
||||
return [this.active,this.line]
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 加上单引号的表示字符串
|
||||
|
||||
2. 不加的会当成变量
|
||||
|
||||
3. 可以直接使用方法返回数组对象
|
||||
|
||||

|
||||
|
||||
# 3. v-for和v-bind结合
|
||||
|
||||
使用v-for和v-bind实现一个小demo,将电影列表展示,并点击某一个电影列表时候,将此电影列表变成红色。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>作业(v-for和v-bind的结合)</title>
|
||||
<style>
|
||||
.active{
|
||||
color:red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
||||
<ul>
|
||||
<li v-for="(item, index) in movies" :key="index" :class="{active:index===currentIndex}" @click="changeColor(index)" >{{index+"---"+item}}</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
currentIndex:0,
|
||||
movies:["海王","海贼王","火影忍者","复仇者联盟"]
|
||||
},
|
||||
methods: {
|
||||
changeColor(index){
|
||||
this.currentIndex = index
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
v-for时候的index索引,给每行绑定事件点击事件,点击当行是获取此行索引index并赋值给`currentIndex`,使用`v-bind:`绑定class,当`index===currentIndex`Dom元素有active的class,颜色变红。
|
||||
|
||||

|
||||
|
||||
# 4. v-bind动态绑定style
|
||||
|
||||
## 4.1 v-bind动态绑定style(对象语法)
|
||||
|
||||
```html
|
||||
<!-- <h2 :style="{key(属性名):value(属性值)}">{{message}}</h2> -->
|
||||
<!-- 加单引号,当成字符串解析 -->
|
||||
<h2 :style="{fontSize:'50px'}">{{message}}</h2>
|
||||
<!-- 不加单引号,变量解析 -->
|
||||
<h2 :style="{fontSize:fontSize}">{{message}}</h2>
|
||||
<h2 :style="getStyle()">{{message}}</h2>
|
||||
```
|
||||
|
||||
## 4.2 v-bind动态绑定style(数组语法)
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h2 :style="[baseStyle]">{{message}}</h2>
|
||||
<h2 :style="getStyle()">{{message}}</h2>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"你好啊",
|
||||
baseStyle:{backgroundColor:'red'}
|
||||
},
|
||||
methods: {
|
||||
getStyle(){
|
||||
return [this.baseStyle]
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
类似绑定class,绑定style也是一样的。
|
||||
|
||||
375
Vue/05-计算属性与侦听器.md
Normal file
375
Vue/05-计算属性与侦听器.md
Normal file
@@ -0,0 +1,375 @@
|
||||
# 1. 计算属性的基本使用
|
||||
|
||||
现在有变量姓氏和名字,要得到完整的名字。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>计算属性的基本使用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- Mastache语法 -->
|
||||
<h2>{{firstName+ " " + lastName}}</h2>
|
||||
<!-- 方法 -->
|
||||
<h2>{{getFullName()}}</h2>
|
||||
<!-- 计算属性 -->
|
||||
<h2>{{fullName}}</h2>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
firstName:"skt t1",
|
||||
lastName:"faker"
|
||||
},
|
||||
computed: {
|
||||
fullName:function(){
|
||||
return this.firstName + " " + this.lastName
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getFullName(){
|
||||
return this.firstName + " " + this.lastName
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 使用Mastache语法拼接`<h2>{{firstName+ " " + lastName}}</h2>`
|
||||
2. 使用方法methods`<h2>{{getFullName()}}</h2>`
|
||||
3. 使用计算属性computed`<h2>{{fullName}}</h2>`
|
||||
|
||||
|
||||
|
||||
> 例子中计算属性computed看起来和方法似乎一样,只是方法调用需要使用(),而计算属性不用,方法取名字一般是动词见名知义,而计算属性是属性是名词,但这只是基本使用。
|
||||
|
||||
# 2. 计算属性的复杂使用
|
||||
|
||||
现在有一个数组数据books,里面包含许多book对象,数据结构如下:
|
||||
|
||||
```javascript
|
||||
books:[
|
||||
{id:110,name:"JavaScript从入门到入土",price:119},
|
||||
{id:111,name:"Java从入门到放弃",price:80},
|
||||
{id:112,name:"编码艺术",price:99},
|
||||
{id:113,name:"代码大全",price:150},
|
||||
]
|
||||
```
|
||||
|
||||
要求计算出所有book的总价格`totalPrice`。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>计算属性的复杂使用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
||||
|
||||
<h2>总价格:{{totalPrice}}</h2>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
books:[
|
||||
{id:110,name:"JavaScript从入门到入土",price:119},
|
||||
{id:111,name:"Java从入门到放弃",price:80},
|
||||
{id:112,name:"编码艺术",price:99},
|
||||
{id:113,name:"代码大全",price:150},
|
||||
]
|
||||
},
|
||||
computed: {
|
||||
totalPrice(){
|
||||
let result= 0;
|
||||
for (let i = 0; i < this.books.length; i++) {
|
||||
result += this.books[i].price;
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
获取每一个book对象的price累加,当其中一个book的价格发生改变时候,总价会随之变化。
|
||||
|
||||
# 3. 计算属性的setter和getter
|
||||
|
||||
在计算属性中其实是由这样两个方法setter和getter。
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
fullName:{
|
||||
//计算属性一般没有set方法,只读属性
|
||||
set:function(newValue){
|
||||
console.log("-----")
|
||||
const names = newValue.split(" ")
|
||||
this.firstName = names[0]
|
||||
this.lastName = names[1]
|
||||
},
|
||||
get:function(){
|
||||
return this.firstName + " " + this.lastName
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
但是计算属性一般没有set方法,只读属性,只有get方法,但是上述中newValue就是新的值,也可以使用set方法设置值,但是一般不用。
|
||||
|
||||
***computed的getter/setter***
|
||||
|
||||
> 请看如下代码:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Vue计算属性的getter和setter</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>计算属性:computed的getter/setter</h1>
|
||||
<h2>fullName</h2>
|
||||
{{fullName}}
|
||||
<h2>firstName</h2>
|
||||
{{firstName}}
|
||||
<h2>lastName</h2>
|
||||
{{lastName}}
|
||||
</div>
|
||||
<script>
|
||||
var app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
firstName:"zhang",
|
||||
lastName:"san",
|
||||
},
|
||||
computed: {
|
||||
fullName:{
|
||||
get:function(){
|
||||
return this.firstName+" "+this.lastName
|
||||
},
|
||||
set:function(value){
|
||||
var list = value.split(' ');
|
||||
this.firstName=list[0]
|
||||
this.lastName=list[1]
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
> *初始化*
|
||||
|
||||

|
||||
|
||||
> 修改fullName
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
> *结论*
|
||||
|
||||
|
||||
|
||||
\- 通过这种方式,我们可以在改变计算属性值的同时也改变和计算属性相关联的属性值。
|
||||
|
||||
# 4. 计算属性和methods的对比
|
||||
|
||||
直接看代码,分别使用计算属性和方法获得fullName的值。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>计算属性和methods的对比</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- methods,即使firstName和lastName没有改变,也需要再次执行 -->
|
||||
<h2>{{getFullName()}}</h2>
|
||||
<h2>{{getFullName()}}</h2>
|
||||
<h2>{{getFullName()}}</h2>
|
||||
<h2>{{getFullName()}}</h2>
|
||||
<!-- 计算属性有缓存,只有关联属性改变才会再次计算 -->
|
||||
<h2>{{fullName}}</h2>
|
||||
<h2>{{fullName}}</h2>
|
||||
<h2>{{fullName}}</h2>
|
||||
<h2>{{fullName}}</h2>
|
||||
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
firstName:"skt t1",
|
||||
lastName:"faker"
|
||||
},
|
||||
computed: {
|
||||
fullName(){
|
||||
console.log("调用了计算属性fullName");
|
||||
|
||||
return this.firstName + " " + this.lastName
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getFullName(){
|
||||
console.log("调用了getFullName");
|
||||
|
||||
return this.firstName + " " + this.lastName
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
分别使用方法和计算属性获取四次fullName,结果如图。
|
||||
|
||||

|
||||
|
||||
由此可见计算属性有缓存,在`this.firstName + " " + this.lastName`的属性不变的情况下,methods调用了四次,而计算属性才调用了一次,性能上计算属性明显比methods好。而且在改动firstName的情况下,计算属性只调用一次,methods依然要调用4次。
|
||||
|
||||

|
||||
|
||||
# 5. Vue计算属性与侦听器总结
|
||||
|
||||
> **照例看一段代码:**
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Vue计算属性/侦听器/方法比较</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>计算属性:computed</h1>
|
||||
{{fullName}}
|
||||
<h1>方法:methods</h1>
|
||||
{{fullName2()}}
|
||||
<h1>侦听器:watch</h1>
|
||||
{{watchFullName}}
|
||||
<h1>年龄</h1>
|
||||
{{age}}
|
||||
</div>
|
||||
<script>
|
||||
var other = 'This is other';
|
||||
var app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
firstName:"zhang",
|
||||
lastName:"san",
|
||||
watchFullName:"zhangsan",
|
||||
age:18,
|
||||
},
|
||||
watch: {
|
||||
firstName:function(newFirstName, oldFirstName){
|
||||
console.log("firstName触发了watch,newFirstName="+newFirstName+",oldFirstName="+oldFirstName)
|
||||
this.watchFullName = this.firstName+this.lastName+","+other
|
||||
},
|
||||
lastName:function(newLastName, oldLastName){
|
||||
console.log("lastName触发了watch,newLastName="+newLastName+",oldLastName="+oldLastName)
|
||||
this.watchFullName = this.firstName+this.lastName+","+other
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fullName:function(){
|
||||
console.log("调用了fullName,计算了一次属性")
|
||||
return this.firstName+this.lastName+","+other;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fullName2:function(){
|
||||
console.log("调用了fullName,执行了一次方法")
|
||||
fullName2 = this.firstName+this.lastName+","+other;
|
||||
return fullName2;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
> 初始化:
|
||||
|
||||

|
||||
|
||||
> 修改firstName/lastName/两者都修改
|
||||
|
||||

|
||||
|
||||
> 修改computed中没计算的age
|
||||
|
||||

|
||||
|
||||
> 修改Vue实例外的对象
|
||||
|
||||

|
||||
|
||||
> 修改Vue实例外对象后在修改Vue实例内的对象
|
||||
|
||||

|
||||
|
||||
> 测试结论:
|
||||
|
||||
1. 使用computed计算了fullName属性,值为firstName+lastName。计算属性具有`缓存功能`,当firstName和lastName都不改变的时候,fullName不会重新计算,比如我们改变age的值,fullName的值是不需要重新计算的。
|
||||
2. methods并没有缓存特性,比如我们改变age的值,fullName2()方法会被执行一遍。
|
||||
3. 当一个功能可以用上面三个方法来实现的时候,明显使用computed更合适,代码简单也有缓存特性。
|
||||
4. 计算属性范围在vue实例内,修改vue实例外部对象,不会重新计算渲染,但是如果先修改了vue实例外对象,在修改vue计算属性的对象,那么外部对象的值也会重新渲染。
|
||||
|
||||
> *计算属性:computed*
|
||||
|
||||
计算属性范围在Vue实例的fullName内所管理的firstName和lastName,通常监听多个变量
|
||||
|
||||
|
||||
|
||||
> *侦听器:watch*
|
||||
|
||||
监听数据变化,一般只监听一个变量或数组
|
||||
|
||||
|
||||
|
||||
> 使用场景
|
||||
|
||||
watch(`异步场景`),computed(`数据联动`)
|
||||
|
||||
149
Vue/06-事件监听.md
Normal file
149
Vue/06-事件监听.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# 1. v-on的基本使用
|
||||
|
||||
在前面的计数器案例中使用了`v-on:click`监听单击事件。这里在回顾一下:
|
||||
|
||||
```vue
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>{{count}}</h2>
|
||||
<!-- <button v-on:click="count++">加</button>
|
||||
<button v-on:click="count--">减</button> -->
|
||||
<button @click="increment">加</button>
|
||||
<button @click="decrement()">减</button>
|
||||
</div>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
count:0
|
||||
},
|
||||
methods: {
|
||||
increment(){
|
||||
this.count++
|
||||
},
|
||||
decrement(){
|
||||
this.count--
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
使用`v-on:click`给button绑定监听事件以及回调函数,@是`v-on:`的语法糖,也就是简写也可以使用`@click`。方法一般是需要写方法名加上(),在`@click`中可以省掉,如上述的`<button @click="increment">加</button>`。
|
||||
|
||||
# 2. v-on的参数传递
|
||||
|
||||
了解了v-on的基本使用,现在需要了解参数传递。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 事件没传参 -->
|
||||
<button @click="btnClick">按钮1</button>
|
||||
<button @click="btnClick()">按钮2</button>
|
||||
<!-- 事件调用方法传参,写函数时候省略小括号,但是函数本身需要传递一个参数 -->
|
||||
<button @click="btnClick2(123)">按钮3</button>
|
||||
<button @click="btnClick2()">按钮4</button>
|
||||
<button @click="btnClick2">按钮5</button>
|
||||
<!-- 事件调用时候需要传入event还需要传入其他参数 -->
|
||||
<button @click="btnClick3($event,123)">按钮6</button>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
methods:{
|
||||
btnClick(){
|
||||
console.log("点击XXX");
|
||||
},
|
||||
btnClick2(value){
|
||||
console.log(value+"----------");
|
||||
},
|
||||
btnClick3(event,value){
|
||||
console.log(event+"----------"+value);
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 事件没传参,可以省略()
|
||||
2. 事件调用方法传参了,写函数时候省略了小括号,但是函数本身是需要传递一个参数的,这个参数就是原生事件event参数传递进去
|
||||
3. 如果同时需要传入某个参数,同时需要event是,可以通过`$event`传入事件。
|
||||
|
||||
按钮4调用`btnClick2(value){}`,此时`undefined`。按钮5调用时省略了(),会自动传入原生event事件,如果我们需要event对象还需要传入其他参数,可以使用`$event`对象。
|
||||
|
||||
# 3. v-on的修饰词
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-on的修饰符</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!--1. .stop的使用,btn的click事件不会传播,不会冒泡到上层,调用event.stopPropagation() -->
|
||||
<div @click="divClick">
|
||||
<button @click.stop="btnClick">按钮1</button>
|
||||
</div>
|
||||
<!-- 2. .prevent 调用event.preeventDefault阻止默认行为 -->
|
||||
<form action="www.baidu.com">
|
||||
<button type="submit" @click.prevent="submitClick">提交</button>
|
||||
</form>
|
||||
<!--3. 监听键盘的事件 -->
|
||||
<input type="text" @click.enter="keyup">
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
methods:{
|
||||
btnClick(){
|
||||
console.log("点击button");
|
||||
},
|
||||
divClick(){
|
||||
console.log("点击div");
|
||||
},
|
||||
submitClcik(){
|
||||
console.log("提交被阻止了")
|
||||
},
|
||||
keyup(){
|
||||
console.log("keyup点击")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. `.stop`的使用,btn的click事件不会传播,不会冒泡到上层,调用`event.stopPropagation()`。
|
||||
2. `.prevent` 调用`event.preeventDefault`阻止默认行为。
|
||||
3. `.enter`监听键盘事件
|
||||
133
Vue/07-条件判断.md
Normal file
133
Vue/07-条件判断.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 1. v-if、v-else、v-elseif
|
||||
|
||||
v-if用于条件判断,判断Dom元素是否显示。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2 v-if="isFlag">isFlag为true显示这个</h2>
|
||||
<h2 v-show="isShow">isShow为true是显示这个</h2>
|
||||
<div v-if="age<18">小于18岁未成年</div>
|
||||
<div v-else-if="age<60">大于18岁小于60岁正值壮年</div>
|
||||
<div v-else="">大于60岁,暮年</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
isFlag:true,
|
||||
isShow:false,
|
||||
age:66
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 单独使用v-if,变量为布尔值,为true才渲染Dom
|
||||
|
||||
2. v-show的变量也是布尔值,为true才显示内容,类似css的display
|
||||
|
||||
3. v-if、v-else、v-else-if联合使用相当于if、elseif、else,但是在条件比较多的时候建议使用计算属性。
|
||||
|
||||

|
||||
|
||||
# 2. v-if的demo
|
||||
|
||||
在登录网站是经常可以选择使用账户名或者邮箱登录的切换按钮。要求点击按钮切换登录方式。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<span v-if="isUser">
|
||||
<label for="username">用户账号</label>
|
||||
<input type="text" id="username" placeholder="请输入用户名" >
|
||||
</span>
|
||||
<span v-else="isUser">
|
||||
<label for="email">用户邮箱</label>
|
||||
<input type="text" id="email" placeholder="请输入用户邮箱" >
|
||||
</span>
|
||||
<button @click="isUser=!isUser">切换类型</button>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
isUser:true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
使用`v-if`和`v-else`选择渲染指定的Dom,点击按钮对`isUser`变量取反。
|
||||
|
||||
> 这里有个小问题,如果已经输入了账号了,此时想切换到邮箱输入,输入框未自己清空。
|
||||
|
||||

|
||||
|
||||
这里需要了解一下vue底层操作,此时input输入框值被复用了。
|
||||
|
||||
1. vue在进行DOM渲染是,处于性能考虑,会复用已经存在的元素,而不是每次都创建新的DOM元素。
|
||||
|
||||
2. 在上面demo中,Vue内部发现原来的input元素不再使用,所以直接将其映射对应虚拟DOM,用来复用。
|
||||
|
||||
3. 如果不希望出现类似复用问题,可以给对应的dom元素加上`key`值,并保证`key`不同。
|
||||
|
||||
```html
|
||||
<input type="text" id="username" placeholder="请输入用户名" key="username">
|
||||
<input type="text" id="email" placeholder="请输入用户邮箱" key="email">
|
||||
```
|
||||
|
||||
# 3. v-show
|
||||
|
||||
v-if 在首次渲染的时候,如果条件为假,什么也不操作,页面当作没有这些元素。当条件为真的时候,开始局部编译,动态的向DOM元素里面添加元素。当条件从真变为假的时候,开始局部编译,卸载这些元素,也就是删除。
|
||||
|
||||
v-show 不管条件是真还是假,第一次渲染的时候都会编译出来,也就是标签都会添加到DOM中。之后切换的时候,通过display: none;样式来显示隐藏元素。可以说只是改变css的样式,几乎不会影响什么性能。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2 v-show="isFlag">v-show只是操作元素的style属性display</h2>
|
||||
<h2 v-if="isFlag">v-if是新增和删除dom元素</h2>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
isFlag:true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
270
Vue/08-循环遍历.md
Normal file
270
Vue/08-循环遍历.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# 1. v-for遍历数组
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 1.遍历过程没有使用索引(下标值) -->
|
||||
<ul>
|
||||
<li v-for="item in names" >{{item}}</li>
|
||||
</ul>
|
||||
<!-- 2.遍历过程有使用索引(下标值) -->
|
||||
<ul>
|
||||
<li v-for="(item,index) in names" >{{index+":"+item}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
names:["zzz","ttt","yyy"]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
一般需要使用索引值。`<li v-for="(item,index) in names" >{{index+":"+item}}</li>`index表示索引,item表示当前遍历的元素。
|
||||
|
||||
# 2. v-for遍历对象
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 1.遍历过程没有使用index索引-->
|
||||
<!-- 格式为:(value, name) -->
|
||||
<ul>
|
||||
<li v-for="(item,key) in user" >{{key+"-"+item}}</li>
|
||||
</ul>
|
||||
<!-- 格式为:(value, name, index) -->
|
||||
<ul>
|
||||
<li v-for="(item,key,index) in user" >{{key+"-"+item+"-"+index}}</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
user:{
|
||||
name:"zzz",
|
||||
height:188,
|
||||
age:24
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 遍历过程没有使用index索引,`<li v-for="(item,key) in user" >{{key+"-"+item}}</li>`,item表示当前元素是属性值,key表示user对象属性名。
|
||||
2. 遍历过程使用index索引,index表示索引从0开始。
|
||||
3. 
|
||||
|
||||
# 3. v-for使用key
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-for使用key</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 不加key如果要插入f依次改变 -->
|
||||
<ul>
|
||||
<li v-for="item in letters">{{item}}</li>
|
||||
</ul>
|
||||
<button @click="add1">没有key</button>
|
||||
<!-- 加key如果要插入f使用diff算法高效,如果使用index做key一直变,所以item如果唯一可以使用item-->
|
||||
<ul>
|
||||
<li v-for="item in letters" :key="item">{{item}}</li>
|
||||
</ul>
|
||||
<button @click="add2">有key</button>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
letters:['a','b','c','d','e']
|
||||
},
|
||||
methods: {
|
||||
add1(){
|
||||
this.letters.splice(2,0,'f')
|
||||
},
|
||||
add2(){
|
||||
this.letters.splice(2,0,'f')
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 使用key可以提高效率,加key如果要插入f使用diff算法高效,如果使用index做key一直变,所以item如果唯一可以使用item。
|
||||
2. 不加key如果要插入f依次替换。
|
||||
|
||||
|
||||
|
||||
**v-for加key与不加**
|
||||
|
||||

|
||||
|
||||
> 不加key渲染时候会依次替换渲染,加了key会直接将其放在指定位置,加key提升效率。
|
||||
|
||||
# 4. 数组的响应方式
|
||||
|
||||
我们改变DOM绑定的数据时,DOM会动态的改变值。数组也是一样的。但是对于动态变化数据,有要求,不是任何情况改变数据都会变化。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>数组的响应式方法 </title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 数组的响应式方法 -->
|
||||
<ul>
|
||||
<li v-for="item in letters">{{item}}</li>
|
||||
</ul>
|
||||
<button @click="btn1">push</button><br>
|
||||
<button @click="btn2">通过索引值修改数组</button>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
letters:['a','b','c','d','e']
|
||||
},
|
||||
methods: {
|
||||
btn1(){
|
||||
//1.push
|
||||
this.letters.push('f')
|
||||
//2.pop()删除最后一个元素
|
||||
//this.letters.pop()
|
||||
//3.shift()删除第一个
|
||||
//this.letters.shift()
|
||||
//4.unshift()添加在最前面,可以添加多个
|
||||
//this.letters.unshift('aaa','bbb','ccc')
|
||||
//5.splice():删除元素/插入元素/替换元素
|
||||
//splice(1,1)在索引为1的地方删除一个元素,第二个元素不传,直接删除后面所有元素
|
||||
//splice(index,0,'aaa')再索引index后面删除0个元素,加上'aaa',
|
||||
//splice(1,1,'aaa')替换索引为1的后一个元素为'aaa'
|
||||
// this.letters.splice(2,0,'aaa')
|
||||
//6.sort()排序可以传入一个函数
|
||||
//this.letters.sort()
|
||||
//7.reverse()反转
|
||||
// this.letters.reverse()
|
||||
|
||||
},
|
||||
btn2(){
|
||||
this.letters[0]='f'
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. btn2按钮是通过索引值修改数组的值,这种情况,数组letters变化,DOM不会变化。
|
||||
|
||||
2. 而数组的方法,例如`push()`、`pop()`、`shift()`、`unshift()`、`splice()`、`sort()`、`reverse()`等方法修改数组的数据,DOM元素会随之修改。
|
||||
|
||||
3. > push():在最后添加元素
|
||||
>
|
||||
> pop():删除最后一个元素
|
||||
>
|
||||
> shift():删除第一个元素
|
||||
>
|
||||
> unshift():添加在最前面,可以添加多个
|
||||
>
|
||||
> splic():删除元素、插入元素、替换元素
|
||||
>
|
||||
> splice(1,1)再索引为1的地方删除一个元素,第二个元素不传,直接删除后面所有元素
|
||||
>
|
||||
> splice(index,0,'aaa')再索引index后面删除0个元素,加上'aaa'
|
||||
>
|
||||
> splice(1,1,'aaa')替换索引为1的后一个元素为'aaa'
|
||||
|
||||
# 5. 综合练习
|
||||
|
||||
现在要求将数组内的电影展示到页面上,并选中某个电影,电影背景变红,为选中状态。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>综合练习</title>
|
||||
<style>
|
||||
.active {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 数组的响应式方法 -->
|
||||
<ul>
|
||||
<li v-for="(item,index) in movies" @click="liClick(index)" :class="{active:index===curIndex}">{{index+"---"+item}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
movies: ['复仇者联盟', '蝙蝠侠', '海贼王', '星际穿越'],
|
||||
curIndex:0
|
||||
},
|
||||
methods: {
|
||||
liClick(index){
|
||||
this.curIndex = index
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
1. 先使用`v-for`将电影列表展示到页面上,并获取index索引定位当前的`<li>`标签。
|
||||
2. 给每个`<li>`标签加上,单击事件,并将index传入单击事件的回调函数methods的`liClick()`。
|
||||
3. 定义一个变量`curIndex`表示当前索引,初始值为0,用于表示选中状态的电影列。
|
||||
4. 定义个class样式active,在active为激活状态是,` background-color: red;`为红色。使用表达式`index=curIndex`判断当前选中状态的列。
|
||||
5. 
|
||||
182
Vue/09-综合练习.md
Normal file
182
Vue/09-综合练习.md
Normal file
@@ -0,0 +1,182 @@
|
||||
综合前面的知识,需要通过一个小demo来串联起知识。
|
||||
|
||||
如图所示:
|
||||
|
||||

|
||||
|
||||
点击“+”按钮,总价增加,点击“-”按钮总价减少,点击移除,移除当列。
|
||||
|
||||
# 1. 目录结构
|
||||
|
||||

|
||||
|
||||
# 2. index.html
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>综合练习</title>
|
||||
<link rel="stylesheet" href="./css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<table>
|
||||
<thead>
|
||||
<th> </th>
|
||||
<th>书籍名称</th>
|
||||
<th>出版日期</th>
|
||||
<th>价格</th>
|
||||
<th>购买数量</th>
|
||||
<th>操作</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(book,index) in books">
|
||||
<td>{{index}}</td>
|
||||
<td>{{book.name}}</td>
|
||||
<td>{{book.beginDate}}</td>
|
||||
<td>{{book.price | showPrice}}</td>
|
||||
<td>
|
||||
<button @click="decrement(index)" :disabled="book.count<=1">-</button>
|
||||
{{book.count}}
|
||||
<button @click="increment(index)">+</button>
|
||||
</td>
|
||||
<td>
|
||||
<button @click="remove(index)">移除</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>总价:{{totalPrice | showPrice}}</h3>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script src="./js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# 3.main.js
|
||||
|
||||
```javascript
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
books: [
|
||||
{
|
||||
name: "《算法导论》",
|
||||
beginDate: "2006-9",
|
||||
price: 85.00,
|
||||
count: 1
|
||||
},
|
||||
{
|
||||
name: "《UNIX编程艺术》",
|
||||
beginDate: "2006-2",
|
||||
price: 59.00,
|
||||
count: 1
|
||||
},
|
||||
{
|
||||
name: "《编程大全》",
|
||||
beginDate: "2008-10",
|
||||
price: 39.00,
|
||||
count: 1
|
||||
},
|
||||
{
|
||||
name: "《代码大全》",
|
||||
beginDate: "2006-3",
|
||||
price: 128.00,
|
||||
count: 1
|
||||
},
|
||||
]
|
||||
},
|
||||
methods: {
|
||||
increment(index){
|
||||
this.books[index].count++
|
||||
},
|
||||
decrement(index){
|
||||
this.books[index].count--
|
||||
},
|
||||
remove(index){
|
||||
this.books.splice(index,1)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalPrice(){
|
||||
return this.books.map(book => book.price*book.count)
|
||||
.reduce((preValue,currentValue) => preValue+currentValue)
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
showPrice: function(price){
|
||||
console.log(typeof price);
|
||||
let priceStr = price.toFixed(2)
|
||||
console.log(priceStr);
|
||||
return "¥" + priceStr
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# 4. style.css
|
||||
|
||||
```css
|
||||
table{
|
||||
border: 1px;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
th,td{
|
||||
padding: 8px 16px;
|
||||
border: ipx solid #e9e9e9;
|
||||
text-align: left;
|
||||
}
|
||||
th{
|
||||
background-color: #f7f7f7;
|
||||
color: #5c6b77;
|
||||
font-weight: 600;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
# filter、map、reduce
|
||||
|
||||
```javascript
|
||||
// 1.filter过滤函数
|
||||
const nums = [2,3,5,1,77,55,100,200]
|
||||
//要求获取nums中大于50的数
|
||||
//回调函数会遍历nums中每一个数,传入回调函数,在回调函数中写判断逻辑,返回true则会被数组接收,false会被拒绝
|
||||
let newNums = nums.filter(function (num) {
|
||||
if(num > 50){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
//可以使用箭头函数简写
|
||||
// let newNums = nums.filter(num => num >50)
|
||||
console.log(newNums);
|
||||
// 2.map高阶函数
|
||||
// 要求将已经过滤的新数组每项乘以2
|
||||
//map函数同样会遍历数组每一项,传入回调函数为参数,num是map遍历的每一项,回调函数function返回值会被添加到新数组中
|
||||
let newNums2 = newNums.map(function (num) {
|
||||
return num * 2
|
||||
})
|
||||
//简写
|
||||
// let newNums2 = newNums.map(num => num * 2)
|
||||
console.log(newNums2);
|
||||
// 3.reduce高阶函数
|
||||
//要求将newNums2的数组所有数累加
|
||||
//reduce函数同样会遍历数组每一项,传入回调函数和‘0’为参数,0表示回调函数中preValue初始值为0,回调函数中参数preValue是每一次回调函数function返回的值,currentValue是当前值
|
||||
//例如数组为[154, 110, 200, 400],则回调函数第一次返回值为0+154=154,第二次preValue为154,返回值为154+110=264,以此类推直到遍历完成
|
||||
let newNum = newNums2.reduce(function (preValue,currentValue) {
|
||||
return preValue + currentValue
|
||||
},0)
|
||||
//简写
|
||||
// let newNum = newNums2.reduce((preValue,currentValue) => preValue + currentValue)
|
||||
console.log(newNum);
|
||||
|
||||
//三个需求综合
|
||||
let n = nums.filter(num => num > 50).map(num => num * 2).reduce((preValue,currentValue) => preValue + currentValue)
|
||||
console.log(n);
|
||||
```
|
||||
|
||||
230
Vue/10-v-model.md
Normal file
230
Vue/10-v-model.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# 1. v-model的基本使用
|
||||
|
||||
```html
|
||||
<!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: "hello"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
v-model双向绑定,既输入框的value改变,对应的message对象值也会改变,修改message的值,input的value也会随之改变。无论改变那个值,另外一个值都会变化。
|
||||
|
||||
# 2. v-model的原理
|
||||
|
||||
先来一个demo实现不使用v-model实现双向绑定。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- $event获取事件对象,$event.target.value获取input值 -->
|
||||
<!-- <input type="text" :value="message" @input="changeValue($event.target.value)">{{message}}-->
|
||||
<!--事件调用方法传参了,写函数时候省略了小括号,但是函数本身是需要传递一个参数的,这个参数就是原生事件event参数传递进去-->
|
||||
<input type="text" :value="message" @input="changeValue">{{message}}
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
message: "hello world"
|
||||
},
|
||||
methods: {
|
||||
changeValue(event){
|
||||
console.log("值改变了");
|
||||
this.message = event.target.value
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
`v-model = v-bind + v-on`,实现双向绑定需要是用v-bind和v-on,使用v-bind给input的value绑定message对象,此时message对象改变,input的值也会改变。但是改变input的value并不会改变message的值,此时需要一个v-on绑定一个方法,监听事件,当input的值改变的时候,将最新的值赋值给message对象。`$event`获取事件对象,target获取监听的对象dom,value获取最新的值。
|
||||
|
||||
# 3. v-model结合radio类型使用
|
||||
|
||||
radio单选框的`name`属性是互斥的,如果使用v-model,可以不使用`name`就可以互斥。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<!-- name属性radio互斥 使用v-model可以不用name就可以互斥 -->
|
||||
<label for="male">
|
||||
<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>
|
||||
<div>你选择的性别是:{{sex}}</div>
|
||||
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"zzz",
|
||||
sex:"男"
|
||||
},
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
v-model绑定`sex`属性,初始值为“男”,选择女后`sex`属性变成“女”,因为此时是双向绑定。
|
||||
|
||||
# 4. v-model结合checkbox类型使用
|
||||
|
||||
checkbox可以结合v-model做单选框,也可以多选框。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!--单选框-->
|
||||
<h2>单选框</h2>
|
||||
<label for="agree">
|
||||
<input type="checkbox" id="agree" v-model="isAgree">同意协议
|
||||
</label>
|
||||
<!--多选框-->
|
||||
<h2>多选框</h2>
|
||||
<label :for="item" v-for="(item,index) in hobbies" :key="index">
|
||||
<input type="checkbox" name="hobby" :value="item" :id="item" v-model="hobbies">{{item}}
|
||||
</label>
|
||||
<h2>你的爱好是:{{hobbies}}</h2>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
isAgree: false,
|
||||
hobbies: ["篮球","足球","乒乓球","羽毛球"]
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. checkbox结合v-model实现单选框,定义变量`isAgree`初始化为`false`,点击checkbox的值为`true`,`isAgree`也是`true`。
|
||||
2. checkbox结合v-model实现多选框,定义数组对象`hobbies`,用于存放爱好,将`hobbies`与checkbox对象双向绑定,此时选中,一个多选框,就多一个true,`hobbies`就添加一个对象。
|
||||
|
||||
# 5. v-model结合select
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-model结合select类型</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- select单选 -->
|
||||
<select name="fruit" v-model="fruit">
|
||||
<option value="苹果">苹果</option>
|
||||
<option value="香蕉">香蕉</option>
|
||||
<option value="西瓜">西瓜</option>
|
||||
</select>
|
||||
<h2>你选择的水果是:{{fruit}}</h2>
|
||||
|
||||
<!-- select多选 -->
|
||||
<select name="fruits" v-model="fruits" multiple>
|
||||
<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:{
|
||||
fruit:"苹果",
|
||||
fruits:[]
|
||||
},
|
||||
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
v-model结合select可以单选也可以多选。
|
||||
|
||||
# 6. v-model的修饰符的使用
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>v-model修饰符</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h2>v-model修饰符</h2>
|
||||
<h3>lazy,默认情况是实时更新数据,加上lazy,从输入框失去焦点,按下enter都会更新数据</h3>
|
||||
<input type="text" v-model.lazy="message">
|
||||
<div>{{message}}</div>
|
||||
<h3>修饰符number,默认是string类型,使用number赋值为number类型</h3>
|
||||
<input type="number" v-model.number="age">
|
||||
<div>{{age}}--{{typeof age}}</div>
|
||||
<h3>修饰符trim:去空格</h3>
|
||||
<input type="text" v-model.trim="name">
|
||||
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
message:"zzz",
|
||||
age:18,
|
||||
name:"ttt"
|
||||
},
|
||||
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. `lazy`:默认情况下是实时更新数据,加上`lazy`,从输入框失去焦点,按下enter都会更新数据。
|
||||
2. `number`:默认是string类型,使用`number`复制为number类型。
|
||||
3. `trim`:用于自动过滤用户输入的首尾空白字符
|
||||
|
||||

|
||||
977
Vue/11-组件化开发.md
Normal file
977
Vue/11-组件化开发.md
Normal file
@@ -0,0 +1,977 @@
|
||||
# 1. 组件的基本使用
|
||||
|
||||
简单的组件示例
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- 3.使用组件 -->
|
||||
<my-cpn></my-cpn>
|
||||
<my-cpn></my-cpn>
|
||||
<my-cpn></my-cpn>
|
||||
<cpnc></cpnc>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
// 1.创建组件构造器对象
|
||||
const cpnc = Vue.extend({
|
||||
template:`
|
||||
<div>
|
||||
<h2>标题</h2>
|
||||
<p>内容1...<p>
|
||||
<p>内容2...<p>
|
||||
</div>`
|
||||
})
|
||||
// 2.全局注册组件
|
||||
Vue.component('my-cpn', cpnc)
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
},
|
||||
components:{
|
||||
//局部组件创建
|
||||
cpnc:cpnc
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 `my-cpn`。我们可以在一个通过 `new Vue` 创建的 Vue 根实例中,把这个组件作为自定义元素来使用: `<my-cpn></my-cpn>`。
|
||||
|
||||
## 1.1 创建组件构造器对象
|
||||
|
||||
`template`中是组件的DOM元素内容。
|
||||
|
||||
## 1.2 注册组件
|
||||
|
||||
1. 全局注册,通过 `Vue.component `。
|
||||
2. 局部注册,通过 `components:{cpnc:cpnc}`。
|
||||
|
||||
## 1.3 使用组件
|
||||
|
||||
像使用html标签一样使用。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<!-- 3.使用组件 -->
|
||||
<my-cpn></my-cpn>
|
||||
<my-cpn></my-cpn>
|
||||
<my-cpn></my-cpn>
|
||||
<cpnc></cpnc>
|
||||
</div>
|
||||
```
|
||||
|
||||

|
||||
|
||||
# 2. 全局组件和局部组件
|
||||
|
||||
组件的注册方式有两种,一种是全局组件一种是局部组件。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h2>全局组件</h2>
|
||||
<my-cpn></my-cpn>
|
||||
<h2>局部组件</h2>
|
||||
<cpnc></cpnc>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
// 1.创建组件构造器对象
|
||||
const cpnc = Vue.extend({
|
||||
template:`
|
||||
<div>
|
||||
<h2>标题</h2>
|
||||
<p>内容1</p>
|
||||
<p>内容2</p>
|
||||
</div>`
|
||||
})
|
||||
// 2.注册组件(全局组件,可以在多个vue实例中使用)
|
||||
Vue.component('my-cpn', cpnc)
|
||||
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
components:{//局部组件创建
|
||||
cpnc:cpnc
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 2.1 全局组件
|
||||
|
||||
全局组件,可以在多个vue实例中使用,类似于全局变量。
|
||||
|
||||
使用`Vue.component('my-cpn', cpnc)`方式注册,直接使用`<my-cpn></my-cpn>`调用。`my-cpn`是全局组件的名字,`cpnc`是定义的组件对象。
|
||||
|
||||
## 2.2 局部组件
|
||||
|
||||
局部组件,只能在当前vue实例挂载的对象中使用,类似于局部变量,有块级作用域。
|
||||
|
||||
> 注册方式
|
||||
|
||||
```javascript
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
components:{//局部组件创建
|
||||
cpnc:cpnc
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
使用方式与全局变量一样,直接使用`<cpnc></cpnc>`调用。`cpnc:cpnc`第一个cpnc是给组件命名的名字,第二个是定义的组件对象。如果俩个同名也可以直接使用es6语法:
|
||||
|
||||
```javascript
|
||||
components:{//局部组件创建
|
||||
cpnc
|
||||
}
|
||||
```
|
||||
|
||||
# 3. 父组件和子组件的区别
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<cpn2></cpn2>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
// 1.创建组件构造器对象
|
||||
const cpn1 = Vue.extend({
|
||||
template:`
|
||||
<div>
|
||||
<h2>标题1</h2>
|
||||
<p>组件1</p>
|
||||
</div>`
|
||||
})
|
||||
// 组件2中使用组件1
|
||||
const cpn2 = Vue.extend({
|
||||
template:`
|
||||
<div>
|
||||
<h2>标题2</h2>
|
||||
<p>组件2</p>
|
||||
<cpn1></cpn1>
|
||||
</div>`,
|
||||
components:{
|
||||
cpn1:cpn1
|
||||
}
|
||||
})
|
||||
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
components:{//局部组件创建
|
||||
cpn2:cpn2
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
上述代码中定义了两个组件对象`cpn1`和`cpn2`,在组件`cpn2`中使用局部组件注册了`cpn1`,并在`template`中使用了注册的`cpn1`,然后在vue实例中使用注册了局部组件`cpn2`,在vue实例挂载的div中调用了`cpn2`,`cpn2`与`cpn1`形成父子组件关系。
|
||||
|
||||
> 注意:组件就是一个vue实例,vue实例的属性,组件也可以有,例如data、methods、computed等。
|
||||
|
||||
# 4. 注册组件的语法糖
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<cpn1></cpn1>
|
||||
<cpn2></cpn2>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
// 1.注册全局组件语法糖
|
||||
Vue.component('cpn1', {
|
||||
template:`
|
||||
<div>
|
||||
<h2>全局组件语法糖</h2>
|
||||
<p>全局组件语法糖</p>
|
||||
</div>`
|
||||
})
|
||||
|
||||
const app = new Vue({
|
||||
el:"#app",
|
||||
components:{//局部组件创建
|
||||
cpn2:{
|
||||
template:`
|
||||
<div>
|
||||
<h2>局部组件语法糖</h2>
|
||||
<p>局部组件语法糖</p>
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
注册组件时候可以不实例化组件对象,直接在注册的时候实例化。`{}`就是一个组件对象。
|
||||
|
||||
# 5. 组件模板的分离写法
|
||||
|
||||
## 5.1 script标签
|
||||
|
||||
使用`script`标签定义组件的模板,`script`标签注意类型是`text/x-template`。
|
||||
|
||||
```html
|
||||
<!-- 1.script标签注意类型是text/x-template -->
|
||||
<script type="text/x-template" id="cpn1">
|
||||
<div>
|
||||
<h2>组件模板的分离写法</h2>
|
||||
<p>script标签注意类型是text/x-template</p>
|
||||
</div>
|
||||
</script>
|
||||
```
|
||||
|
||||
## 5.2 template标签
|
||||
|
||||
使用`template`标签,将内容写在标签内。
|
||||
|
||||
```html
|
||||
<!-- 2.template标签 -->
|
||||
<template id="cpn2">
|
||||
<div>
|
||||
<h2>组件模板的分离写法</h2>
|
||||
<p>template标签</p>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
> 调用分离的模板,使用`template:'#cpn1'`
|
||||
|
||||
```html
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
components: { //局部组件创建
|
||||
cpn1:{
|
||||
template:'#cpn1'
|
||||
},
|
||||
cpn2: {
|
||||
template: '#cpn2'
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
# 6. 组件的数据
|
||||
|
||||
## 6.1 存放问题
|
||||
|
||||
前面说过vue组件就是一个vue实例,相应的vue组件也有`data`属性来存放数据。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<cpn1></cpn1>
|
||||
</div>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
components: { //局部组件创建
|
||||
cpn1:{
|
||||
template:'<div>{{msg}}</div>',
|
||||
data(){
|
||||
return {
|
||||
msg:"组件的数据存放必须要是一个函数"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
在`template`中使用组件内部的数据`msg`。
|
||||
|
||||

|
||||
|
||||
## 6.2 组件的data为什么必须要是函数
|
||||
|
||||
组件的思想是复用,定义组件当然是把通用的公共的东西抽出来复用。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<h2>data不使用函数</h2>
|
||||
<cpn1></cpn1>
|
||||
<cpn1></cpn1>
|
||||
<hr>
|
||||
<h2>data使用函数</h2>
|
||||
<cpn2></cpn2>
|
||||
<cpn2></cpn2>
|
||||
<hr>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<template id="cpn1">
|
||||
<div>
|
||||
<button @click="count--">-</button>
|
||||
当前计数:{{count}}
|
||||
<button @click="count++">+</button>
|
||||
</div>
|
||||
</template>
|
||||
<template id="cpn2">
|
||||
<div>
|
||||
<button @click="count--">-</button>
|
||||
当前计数:{{count}}
|
||||
<button @click="count++">+</button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
const obj = {
|
||||
count:0
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
components: { //局部组件创建
|
||||
cpn1: {
|
||||
template: '#cpn1',
|
||||
data() {
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
cpn2: {
|
||||
template: '#cpn2',
|
||||
data() {
|
||||
return {
|
||||
count: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
上述代码中定义了两个组件`cpn1`和`cpn2`,都是定义了两个计数器,`con1`的data虽然使用了函数,但是为了模拟`data:{count:0}`,使用了常量`obj`来返回count。
|
||||
|
||||

|
||||
|
||||
图中可以看到,不使用函数`data`的好像共用一个`count`属性,而使用函数的`data`的count是各自用各自的,像局部变量一样有块级作用域,这个块级就是vue组件的作用域。
|
||||
|
||||
> 我们在复用组件的时候肯定希望,各自组件用各自的变量,如果确实需要都用一样的,可以全局组件注册,也可以是用vuex来进行状态管理。
|
||||
|
||||
# 7. 父组件给子组件传递数据
|
||||
|
||||
## 7.1 使用`props`属性,父组件向子组件传递数据
|
||||
|
||||
> 使用组件的`props`属性
|
||||
|
||||
```javascript
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
props: {
|
||||
cmessage: {
|
||||
type: String,
|
||||
default: 'zzzzz',
|
||||
required: true //在使用组件必传值
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 向cmessage对象传值
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<cpn :cMessage="message"></cpn>
|
||||
</div>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
message: "你好",
|
||||
movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 7.2 props属性使用
|
||||
|
||||
> 数组写法
|
||||
|
||||
```javascript
|
||||
props: ['cmovies', 'cmessage']
|
||||
```
|
||||
|
||||
> 对象写法
|
||||
|
||||
```javascript
|
||||
props: {
|
||||
cmessage: {
|
||||
type: String,
|
||||
default: 'zzzzz',
|
||||
required: true //在使用组件必传值
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> props属性的类型限制
|
||||
|
||||
```javascript
|
||||
//1.类型限制(多个类使用数组)
|
||||
cmovies:Array,//限制为数组类型
|
||||
cmessage:String,//限制为Strin类型
|
||||
cmessage:['String','Number']//限制为String或Number类型
|
||||
```
|
||||
|
||||
> props属性的默认值
|
||||
|
||||
```javascript
|
||||
// 2.提供一些默认值,以及必传值
|
||||
cmessage: {
|
||||
type: String,
|
||||
default: 'zzzzz',//默认值
|
||||
}
|
||||
```
|
||||
|
||||
> props属性的必传值
|
||||
|
||||
```javascript
|
||||
cmessage: {
|
||||
type: String,
|
||||
default: 'zzzzz',
|
||||
required: true //在使用组件必传值
|
||||
}
|
||||
```
|
||||
|
||||
> 类型是Object/Array,默认值必须是一个函数
|
||||
|
||||
```javascript
|
||||
//类型是Object/Array,默认值必须是一个函数
|
||||
cmovies: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [1, 2, 3, 4]
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
> 自定义验证函数
|
||||
|
||||
```javascript
|
||||
vaildator: function (value) {
|
||||
//这个传递的值必须匹配下列字符串中的一个
|
||||
return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
|
||||
}
|
||||
```
|
||||
|
||||
> 自定义类型
|
||||
|
||||
```javascript
|
||||
function Person(firstName,lastName) {
|
||||
this.firstName = firstName
|
||||
this.lastName = lastName
|
||||
}
|
||||
cmessage:Person//限定了cmeessage必须是Person类型
|
||||
```
|
||||
|
||||
> 综合使用
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<cpn :cMovies="movies" :cMessage="message"></cpn>
|
||||
</div>
|
||||
<template id="cpn">
|
||||
<div>
|
||||
<ul>
|
||||
<li v-for="(item, index) in cmovies" :key="index">{{item}}</li>
|
||||
</ul>
|
||||
<h2>{{cmessage}}</h2>
|
||||
</div>
|
||||
</template>
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
function Person(firstName,lastName) {
|
||||
this.firstName = firstName
|
||||
this.lastName = lastName
|
||||
}
|
||||
// 父传子:props
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
// props: ['cmovies', 'cmessage'],//数组写法
|
||||
props: { //对象写法
|
||||
// 1.类型限制(多个类使用数组)
|
||||
// cmovies:Array,
|
||||
// cmessage:String,
|
||||
// cmessage:['String','Number'],
|
||||
// 2.提供一些默认值,以及必传值
|
||||
cmessage: {
|
||||
type: String,
|
||||
default: 'zzzzz',
|
||||
required: true //在使用组件必传值
|
||||
},
|
||||
//类型是Object/Array,默认值必须是一个函数
|
||||
cmovies: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [1, 2, 3, 4]
|
||||
}
|
||||
},
|
||||
// 3.自定义验证函数
|
||||
// vaildator: function (value) {
|
||||
// //这个传递的值必须匹配下列字符串中的一个
|
||||
// return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
|
||||
// }
|
||||
// 4.自定义类型
|
||||
// cmessage:Person,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
message: "你好",
|
||||
movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
# 8. 组件通信
|
||||
|
||||
## 8.1 父传子(props的驼峰标识)
|
||||
|
||||
v-bind是 不支持使用驼峰标识的,例如`cUser`要改成`c-User`。
|
||||
|
||||
```html
|
||||
<div id="app">
|
||||
<!-- v-bind不支持驼峰 :cUser改成 :c-User-->
|
||||
<!-- <cpn :cUser="user"></cpn> -->
|
||||
<cpn :c-User="user"></cpn>
|
||||
<cpn :cuser="user" ></cpn>
|
||||
</div>
|
||||
<template id="cpn">
|
||||
<div>
|
||||
<!-- 使用驼峰 -->
|
||||
<h2>{{cUser}}</h2>
|
||||
<!-- 不使用 -->
|
||||
<h2>{{cuser}}</h2>
|
||||
</div>
|
||||
</template>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
// 父传子:props
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
props: { //对象写法
|
||||
//驼峰
|
||||
cUser:Object,
|
||||
//未使用驼峰
|
||||
cuser:Object
|
||||
},
|
||||
data() {return {}},
|
||||
methods: {},
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
user:{
|
||||
name:'zzz',
|
||||
age:18,
|
||||
height:175
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 8.2 子传父`$emit`
|
||||
|
||||
子组件向父组件传值,使用自定义事件`$emit`。
|
||||
|
||||
```html
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
<!-- 不写参数默认传递btnClick的item -->
|
||||
<cpn @itemclick="cpnClcik"></cpn>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
|
||||
<div>
|
||||
<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
categoties: [{
|
||||
id: 'aaa',
|
||||
name: '热门推荐'
|
||||
},
|
||||
{
|
||||
id: 'bbb',
|
||||
name: '手机数码'
|
||||
},
|
||||
{
|
||||
id: 'ccc',
|
||||
name: '家用家电'
|
||||
},
|
||||
{
|
||||
id: 'ddd',
|
||||
name: '电脑办公'
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
btnClick(item) {
|
||||
this.$emit('itemclick', item)
|
||||
}
|
||||
},
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cpnClcik(item) {
|
||||
console.log('cpnClick'+item.name);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
1.在子组件中定义一个方法`btnClick(item)`,使用`$emit`,'itemclick'是事件名,`item`是传过去的值。
|
||||
|
||||
```javascript
|
||||
methods: {
|
||||
btnClick(item) {
|
||||
this.$emit('itemclick', item)
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
2.在子组件中监听点击事件并回调此方法
|
||||
|
||||
```html
|
||||
<div>
|
||||
<button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
3.在父组件中定义一个方法cpnClcik(item)
|
||||
|
||||
```javascript
|
||||
methods: {
|
||||
cpnClcik(item) {
|
||||
console.log('cpnClick'+item.name);
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
4.并在父组件(vue实例)中调用`<cpn @itemclick="cpnClcik"></cpn>`(*不写参数默认传递btnClick的item* ),父组件监听事件名为`itemclick`的子组件传过来的事件。
|
||||
|
||||
```html
|
||||
<cpn @itemclick="cpnClcik"></cpn>
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 8.3 父子组件通信案例
|
||||
|
||||
实现父子组件的值双向绑定。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>组件通信-父子通信案例</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
|
||||
<h2>子组件</h2>
|
||||
<cpn :number1='num1' :number2='num2'
|
||||
@num1change="num1Change"
|
||||
@num2change="num2Change"></cpn>
|
||||
<h2>--------------</h2>
|
||||
|
||||
<h2>父组件{{num1}}</h2>
|
||||
<input type="text" v-model="num1" >
|
||||
<h2>父组件{{num2}}</h2>
|
||||
<input type="text" v-model="num2">
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
|
||||
<div>
|
||||
<h2>number1:{{number1}}</h2>
|
||||
<h2>dnumber1:{{dnumber1}}</h2>
|
||||
<input type="text" :value="dnumber1" @input="num1input">
|
||||
<h2>number2:{{number2}}</h2>
|
||||
<h2>dnumber2:{{dnumber2}}</h2>
|
||||
<input type="text" :value="dnumber2" @input="num2input">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
// 父传子:props
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
dnumber1:this.number1,
|
||||
dnumber2:this.number2
|
||||
}
|
||||
},
|
||||
props:{
|
||||
number1:[Number,String],
|
||||
number2:[Number,String],
|
||||
},
|
||||
methods: {
|
||||
num1input(event){
|
||||
this.dnumber1 = event.target.value
|
||||
this.$emit('num1change',this.dnumber1)
|
||||
},
|
||||
num2input(event){
|
||||
this.dnumber2 = event.target.value
|
||||
this.$emit('num2change',this.dnumber2)
|
||||
}
|
||||
},
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
num1:1,
|
||||
num2:2
|
||||
},
|
||||
methods: {
|
||||
num1Change(value){
|
||||
this.num1=value
|
||||
},
|
||||
num2Change(value){
|
||||
this.num1=value
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
使用watch实现。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>组件通信-父子通信案例(watch实现)</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
|
||||
<cpn :number1='num1' :number2='num2' @num1change="num1Change" @num2change="num2Change"></cpn>
|
||||
|
||||
<h2>父组件{{num1}}</h2>
|
||||
<input type="text" v-model="num1" >
|
||||
<h2>父组件{{num2}}</h2>
|
||||
<input type="text" v-model="num2">
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
|
||||
<div>
|
||||
<h2>{{number1}}</h2>
|
||||
<input type="text" v-model="dnumber1">
|
||||
<h2>{{number2}}</h2>
|
||||
<input type="text" v-model="dnumber2">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
// 父传子:props
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
dnumber1:this.number1,
|
||||
dnumber2:this.number2
|
||||
}
|
||||
},
|
||||
props:{
|
||||
number1:[Number,String],
|
||||
number2:[Number,String],
|
||||
},
|
||||
watch: {
|
||||
dnumber1(newValue){
|
||||
this.dnumber1 = newValue * 100
|
||||
this.$emit('num1change',newValue)
|
||||
},
|
||||
dnumber2(newValue){
|
||||
this.dnumber1 = newValue * 100
|
||||
this.$emit('num2change',newValue)
|
||||
}
|
||||
},
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
num1:1,
|
||||
num2:2,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
num1Change(value){
|
||||
this.num1=value
|
||||
},
|
||||
num2Change(value){
|
||||
this.num1=value
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
# 9. 父访问子(children-ref)
|
||||
|
||||
父组件访问子组件,有时候需要直接操作子组件的方法,或是属性,此时需要用到`$children`和`$ref`。
|
||||
|
||||
```html
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
<cpn></cpn>
|
||||
<cpn></cpn>
|
||||
<cpn ref="aaa"></cpn>
|
||||
<button @click="btnClick" >按钮</button>
|
||||
</div>
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
<div>
|
||||
我是子组件
|
||||
</div>
|
||||
</template>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
// 父传子:props
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
name:"我是子组件的name"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showMessage(){
|
||||
console.log("showMessage");
|
||||
}
|
||||
},
|
||||
};
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
message:"hello"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
btnClick(){
|
||||
// 1.children
|
||||
// console.log(this.$children[0].showMessage)
|
||||
// for (let cpn of this.$children) {
|
||||
// console.log(cpn.showMessage)
|
||||
// }
|
||||
// 2.$ref
|
||||
console.log(this.$refs.aaa.name)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
> `$children`方式
|
||||
|
||||
```javascript
|
||||
// 1.children
|
||||
console.log(this.$children[0].showMessage)
|
||||
for (let cpn of this.$children) {
|
||||
console.log(cpn.showMessage)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
使用`this.$children`直接获取**当前实例的直接子组件,需要注意 `$children` 并不保证顺序,也不是响应式的。**如果你发现自己正在尝试使用 `$children` 来进行数据绑定,考虑使用一个数组配合 `v-for` 来生成子组件,并且使用 Array 作为真正的来源。
|
||||
|
||||
> $refs方式
|
||||
|
||||
**先定义子组件**
|
||||
|
||||
```html
|
||||
<cpn ref="aaa"></cpn>
|
||||
```
|
||||
|
||||
**直接调用**
|
||||
348
Vue/12-组件化高级.md
Normal file
348
Vue/12-组件化高级.md
Normal file
@@ -0,0 +1,348 @@
|
||||
# 1. slot-插槽的基本使用
|
||||
|
||||
我们在使用组件的时候有时候希望,在组件内部定制化内容,例如京东这样。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
这两个都是导航栏,组件的思想是可以复用的,把这个导航栏看做一个组件。
|
||||
|
||||
这个组件都可以分成三个部分,左边中间右边,如果可以分割组件,就可以定制化组件内容了。
|
||||
|
||||
```html
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
|
||||
<cpn></cpn>
|
||||
<cpn>
|
||||
<span style="color:red;">这是插槽内容222</span>
|
||||
</cpn>
|
||||
<cpn>
|
||||
<i style="color:red;">这是插槽内容333</i>
|
||||
</cpn>
|
||||
<cpn></cpn>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 插槽的基本使用使用<slot></slot> -->
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
|
||||
<div>
|
||||
<div>
|
||||
{{message}}
|
||||
</div>
|
||||
<!-- 插槽默认值 -->
|
||||
<slot><button>button</button></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
message: "我是子组件"
|
||||
}
|
||||
},
|
||||
}
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
message: "我是父组件消息"
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
> 简单使用插槽,定义template时候使用`slot`
|
||||
|
||||
```html
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
<div>
|
||||
<div>
|
||||
{{message}}
|
||||
</div>
|
||||
<!-- 插槽默认值 -->
|
||||
<slot><button>button</button></slot>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
> 插槽可以使用默认值,`<button>button</button>`就是插槽的默认值。
|
||||
|
||||
```html
|
||||
<cpn></cpn>
|
||||
<cpn><span style="color:red;">这是插槽内容222</span></cpn>
|
||||
```
|
||||
|
||||
> 使用插槽,`<span style="color:red;">这是插槽内容222</span>`将替换插槽的默认值
|
||||
|
||||
上述代码结果如图所示
|
||||
|
||||

|
||||
|
||||
> 替换了两次插槽,两次未替换显示默认的button。
|
||||
>
|
||||
> 如果想实现组件分成三部分就可以使用三个`<slot></slot>`来填充插槽了。
|
||||
|
||||
# 2. slot-具名插槽的使用
|
||||
|
||||
具名插槽,就是可以让插槽按指定的顺序填充,而没有具名的插槽是按照你填充的顺序排列的,而具名插槽可以自定义排列。
|
||||
|
||||
```html
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
|
||||
<cpn>
|
||||
<span>具名插槽</span>
|
||||
<span slot="left">这是左边具名插槽</span>
|
||||
<!-- 新语法 -->
|
||||
<template v-slot:center>这是中间具名插槽</template>
|
||||
<!-- 新语法缩写 -->
|
||||
<template #right>这是右边具名插槽</template>
|
||||
|
||||
|
||||
</cpn>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 插槽的基本使用使用<slot></slot> -->
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
|
||||
<div>
|
||||
|
||||
<slot name="left">左边</slot>
|
||||
<slot name="center">中间</slot>
|
||||
<slot name="right">右边</slot>
|
||||
<slot>没有具名的插槽</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
message: "我是子组件"
|
||||
}
|
||||
},
|
||||
}
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
message: "我是父组件消息"
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
> 如图所示
|
||||
|
||||

|
||||
|
||||
> 没有具名的插槽排在最后,因为在定义组件的时候,排在了最后,如果有多个按顺序排列。具名插槽按照自定义的顺序排列。
|
||||
|
||||
> 定义具名插槽,使用`name`属性,给插槽定义一个名字。
|
||||
|
||||
```html
|
||||
<!-- 插槽的基本使用使用<slot></slot> -->
|
||||
<!-- 子组件模板 -->
|
||||
<template id="cpn">
|
||||
<div>
|
||||
<slot name="left">左边</slot>
|
||||
<slot name="center">中间</slot>
|
||||
<slot name="right">右边</slot>
|
||||
<slot>没有具名的插槽</slot>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
> 使用具名插槽,在自定义组件标签内使用`slot="left"`,插入指定插槽
|
||||
|
||||
```html
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
<cpn>
|
||||
<span>具名插槽</span>
|
||||
<span slot="left">这是左边具名插槽</span>
|
||||
<!-- 新语法 -->
|
||||
<template v-slot:center>这是中间具名插槽</template>
|
||||
<!-- 新语法缩写 -->
|
||||
<template #right>这是右边具名插槽</template>
|
||||
</cpn>
|
||||
</div>
|
||||
```
|
||||
|
||||
> 注意:此处有是三种写法,获取指定插槽。
|
||||
|
||||
# 3. 编译的作用域
|
||||
|
||||
前面说过组件都有自己的作用域,自己组件的作用在自己组件内。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>编译的作用域</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
<!-- 使用的vue实例作用域的isShow -->
|
||||
<cpn v-show="isShow"></cpn>
|
||||
</div>
|
||||
<!-- 插槽的基本使用使用<slot></slot> -->
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
<div>
|
||||
<h2>我是子组件</h2>
|
||||
<p>哈哈哈</p>
|
||||
<!-- 组件作用域,使用的子组件的作用域 -->
|
||||
<button v-show="isShow"></button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
isShwo:false
|
||||
}
|
||||
},
|
||||
}
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
message: "我是父组件消息",
|
||||
isShow:true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
结果如下
|
||||
|
||||

|
||||
|
||||
> 子组件使用的是子组件的isShow,子组件为false,所以button没显示,被隐藏。
|
||||
|
||||
# 4. 作用域插槽案例
|
||||
|
||||
父组件替换插槽的标签,但是内容是由子组件来提供。
|
||||
|
||||
当组件需要在多个父组件多个界面展示的时候,将内容放在子组件插槽中,父组件只需要告诉子组件使用什么方式展示界面。
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>作用域插槽案例</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<!-- 父组件 -->
|
||||
<div id="app">
|
||||
<cpn></cpn>
|
||||
<!-- 目的是获取子组件数据 -->
|
||||
<cpn>
|
||||
<!-- 2.5以下必须使用template -->
|
||||
<template slot-scope="slot">
|
||||
<!-- <span v-for="(item, index) in slot.data" :key="index">{{item}}-</span> -->
|
||||
<span>{{slot.data.join(' - ')}}</span>
|
||||
</template>
|
||||
</cpn>
|
||||
<cpn>
|
||||
<!-- 2.5以下必须使用template -->
|
||||
<template slot-scope="slot">
|
||||
<!-- <span v-for="(item, index) in slot.data" :key="index">{{item}}*</span> -->
|
||||
<span>{{slot.data.join(' * ')}}</span>
|
||||
</template>
|
||||
</cpn>
|
||||
</div>
|
||||
|
||||
<!-- 插槽的基本使用使用<slot></slot> -->
|
||||
<!-- 子组件 -->
|
||||
<template id="cpn">
|
||||
|
||||
<div>
|
||||
<slot :data="pLanguage">
|
||||
<ul>
|
||||
<li v-for="(item, index) in pLanguage" :key="index">{{item}}</li>
|
||||
</ul>
|
||||
</slot>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="../js/vue.js"></script>
|
||||
|
||||
<script>
|
||||
const cpn = {
|
||||
template: "#cpn",
|
||||
data() {
|
||||
return {
|
||||
isShwo:false,
|
||||
pLanguage:['JavaScript','Java','C++','C']
|
||||
}
|
||||
},
|
||||
}
|
||||
const app = new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
isShow:true
|
||||
}
|
||||
},
|
||||
components: {
|
||||
cpn
|
||||
},
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
> 组件中使用`slot-scope="slot"`**(2.6.0已经废弃)**给插槽属性命名,在通过`slot`调用绑定在插槽上的属性。也可以使用`v-slot="slot"`。
|
||||
|
||||

|
||||
|
||||
312
Vue/13-Vue实例的生命周期.md
Normal file
312
Vue/13-Vue实例的生命周期.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# 1. 生命周期图
|
||||
|
||||
Vue实例的生命周期中有多个状态。
|
||||
|
||||

|
||||
|
||||
> 测试代码
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Vue实例的生命周期</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>测试生命周期</h1>
|
||||
<div>{{msg}}</div>
|
||||
<hr>
|
||||
<h3>测试beforeUpdate和update两个钩子函数</h3>
|
||||
<button @click="handlerUpdate">更新数据</button>
|
||||
</div>
|
||||
<script src="../js/vue.js"></script>
|
||||
<script>
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
msg: "12345"
|
||||
},
|
||||
methods: {
|
||||
handlerUpdate() {
|
||||
this.msg=this.msg.split("").reverse().join("")
|
||||
}
|
||||
},
|
||||
//按照示意图依次调用
|
||||
beforeCreate(){
|
||||
console.log("调用了beforeCreate钩子函数");
|
||||
},
|
||||
created(){
|
||||
console.log("调用了created钩子函数");
|
||||
},
|
||||
beforeMount(){
|
||||
console.log('调用了beforeMount钩子函数');
|
||||
},
|
||||
mounted(){
|
||||
console.log('调用了mounted钩子函数');
|
||||
},
|
||||
beforeUpdate(){
|
||||
console.log("调用了beforeUpdate钩子函数")
|
||||
},
|
||||
updated(){
|
||||
console.log("调用了updated钩子函数");
|
||||
},
|
||||
beforeDestroy(){
|
||||
console.log("调用了beforeDestroy钩子函数");
|
||||
},
|
||||
destroyed(){
|
||||
console.log("调用了destroyed钩子函数");
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
如图所示:
|
||||
|
||||

|
||||
|
||||
初始化页面依次调用了:
|
||||
|
||||
> 1. 调用了beforeCreate钩子函数
|
||||
> 2. 调用了created钩子函数
|
||||
> 3. 调用了beforeMount钩子函数
|
||||
> 4. 调用了mounted钩子函数
|
||||
|
||||
点击更新数据后:
|
||||
|
||||
`12345`变成了`54321`,此时调用了:
|
||||
|
||||
> 1. 调用了beforeUpdate钩子函数
|
||||
> 2. 调用了updated钩子函数
|
||||
|
||||
打开F12控制台
|
||||
直接输入`app.$destroy()`主动销毁Vue实例调用:
|
||||
|
||||
>1. 调用了beforeDestroy钩子函数
|
||||
>2. 调用了destroyed钩子函数
|
||||
|
||||
# 2. 再探究
|
||||
|
||||
## 2.1 beforeCreate之前
|
||||
|
||||
初始化钩子函数和生命周期
|
||||
|
||||
## 2.2 beforeCreate和created钩子函数间的生命周期
|
||||
|
||||
在beforeCreate和created之间,进行数据观测(data observer) ,也就是在这个时候开始监控data中的数据变化了,同时初始化事件。
|
||||
|
||||
## 2.3 created钩子函数和beforeMount间的生命周期
|
||||
|
||||
对于created钩子函数和beforeMount有判断:
|
||||

|
||||
|
||||
### 2.3.1 el选项对生命周期影响
|
||||
|
||||
>1. 有el选项
|
||||
|
||||
```javascript
|
||||
new Vue({
|
||||
el: '#app',
|
||||
beforeCreate: function () {
|
||||
console.log('调用了beforeCreat钩子函数')
|
||||
},
|
||||
created: function () {
|
||||
console.log('调用了created钩子函数')
|
||||
},
|
||||
beforeMount: function () {
|
||||
console.log('调用了beforeMount钩子函数')
|
||||
},
|
||||
mounted: function () {
|
||||
console.log('调用了mounted钩子函数')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
结果:
|
||||

|
||||
|
||||
>2. 无el选项
|
||||
|
||||
```javascript
|
||||
new Vue({
|
||||
beforeCreate: function () {
|
||||
console.log('调用了beforeCreat钩子函数')
|
||||
},
|
||||
created: function () {
|
||||
console.log('调用了created钩子函数')
|
||||
},
|
||||
beforeMount: function () {
|
||||
console.log('调用了beforeMount钩子函数')
|
||||
},
|
||||
mounted: function () {
|
||||
console.log('调用了mounted钩子函数')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
结果:
|
||||

|
||||
|
||||
>证明没有el选项,则停止编译,也意味着暂时停止了生命周期。生命周期到created钩子函数就结束了。而当我们不加el选项,但是手动执行vm.$mount(el)方法的话,也能够使暂停的生命周期进行下去,例如:
|
||||
|
||||
```javascript
|
||||
var app = new Vue({
|
||||
beforeCreate: function () {
|
||||
console.log('调用了beforeCreat钩子函数')
|
||||
},
|
||||
created: function () {
|
||||
console.log('调用了created钩子函数')
|
||||
},
|
||||
beforeMount: function () {
|
||||
console.log('调用了beforeMount钩子函数')
|
||||
},
|
||||
mounted: function () {
|
||||
console.log('调用了mounted钩子函数')
|
||||
}
|
||||
})
|
||||
app.$mount('#app')
|
||||
```
|
||||
|
||||
结果:
|
||||

|
||||
|
||||
### 2.3.2 template
|
||||
|
||||

|
||||
|
||||
>同时使用`template`和`HTML`,查看优先级:
|
||||
|
||||
```html
|
||||
<h1>测试template和HTML的优先级</h1>
|
||||
<div id="app">
|
||||
<p>HTML优先</p>
|
||||
</div>
|
||||
<script>
|
||||
var app = new Vue({
|
||||
el:"#app",
|
||||
data:{
|
||||
msg:"template优先"
|
||||
},
|
||||
template:"<p>{{msg}}</p>",
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
结果:
|
||||

|
||||
|
||||
>结论
|
||||
|
||||
1. 如果Vue实例对象中有template参数选项,则将其作为模板编译成render函数
|
||||
2. 如果没有template参数选项,则将外部的HTML作为模板编译(template),也就是说,template参数选项的优先级要比外部的HTML高
|
||||
3. 如果1,2条件都不具备,则报错
|
||||
|
||||
>注意
|
||||
|
||||
1. Vue需要通过el去找对应的template,Vue实例通过el的参数,首先找自己有没有template,如果没有再去找外部的html,找到后将其编译成render函数。
|
||||
2. 也可以直接调用[render](https://cn.vuejs.org/v2/api/#render)选项,优先级:`render函数选项 > template参数 > 外部HTML`。
|
||||
|
||||
```javascript
|
||||
new Vue({
|
||||
el: '#app',
|
||||
render (createElement) {
|
||||
return (....)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 2.4 beforeMount和mounted钩子函数间的生命周期
|
||||
|
||||

|
||||
|
||||
>beforeMount
|
||||
|
||||
载入前(完成了data和el数据初始化),但是页面中的内容还是vue中的占位符,data中的message信息没有被挂在到Dom节点中,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取。
|
||||
|
||||
>Mount
|
||||
|
||||
载入后html已经渲染(ajax请求可以放在这个函数中),把vue实例中的data里的message挂载到DOM节点中去
|
||||
|
||||
>这里两个钩子函数间是载入数据。
|
||||
|
||||
## 2.5 beforeUpdate钩子函数和updated钩子函数间的生命周期
|
||||
|
||||

|
||||
|
||||
在Vue中,修改数据会导致重新渲染,依次调用beforeUpdate钩子函数和updated钩子函数
|
||||
|
||||
如果待修改的数据没有载入模板中,不会调用这里两个钩子函数
|
||||
|
||||
```javascript
|
||||
var app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
msg: 1
|
||||
},
|
||||
template: '<div id="app"><p></p></div>',
|
||||
beforeUpdate: function () {
|
||||
console.log('调用了beforeUpdate钩子函数')
|
||||
},
|
||||
updated: function () {
|
||||
console.log('调用了updated钩子函数')
|
||||
}
|
||||
})
|
||||
app.msg = 2
|
||||
```
|
||||
|
||||
结果:
|
||||

|
||||
如果绑定了数据,会调用两个钩子函数:
|
||||
|
||||
```javascript
|
||||
<h1>测试有数据绑定修改数据,钩子函数调用情况</h1>
|
||||
<div id="app">
|
||||
</div>
|
||||
<script>
|
||||
var app = new Vue({
|
||||
el:"#app",
|
||||
template:"<p>{{msg}}</p>",
|
||||
data:{
|
||||
msg:"原数据"
|
||||
},
|
||||
beforeUpdate: function () {
|
||||
console.log("调用了beforeUpdate钩子函数")
|
||||
},
|
||||
updated: function () {
|
||||
console.log("调用了updated钩子函数");
|
||||
},
|
||||
});
|
||||
app.msg = "数据被修改了";
|
||||
</script>
|
||||
```
|
||||
|
||||
结果:
|
||||

|
||||
|
||||
>注意只有写入模板的数据才会被追踪
|
||||
|
||||
## 2.6 beforeDestroy和destroyed钩子函数间的生命周期
|
||||
|
||||

|
||||
|
||||
### 2.6.1 beforeDestroy
|
||||
|
||||
销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等…’)
|
||||
|
||||
### 2.6.2 destroyed
|
||||
|
||||
销毁后 (Dom元素存在,只是不再受vue控制),卸载watcher,事件监听,子组件
|
||||
|
||||
|
||||
|
||||
# 总结
|
||||
|
||||
- beforecreate : 可以在这加个loading事件
|
||||
- created :在这结束loading,还做一些初始数据的获取,实现函数自-执行
|
||||
- mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
|
||||
- beforeDestroy: 你确认删除XX吗?
|
||||
- destroyed :当前组件已被删除,清空相关内容
|
||||
|
||||
271
Vue/14-前端模块化.md
Normal file
271
Vue/14-前端模块化.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# 1. 为什么要模块化
|
||||
|
||||
随着前端项目越来越大,团队人数越来越多,多人协调开发一个项目成为常态。例如现在小明和小张共同开发一个项目,小明定义一个aaa.js,小张定义了一个bbb.js。
|
||||
|
||||
> aaa.js
|
||||
|
||||
```javascript
|
||||
//小明开发
|
||||
var name = '小明'
|
||||
var age = 22
|
||||
|
||||
function sum(num1, num2) {
|
||||
return num1 + num2
|
||||
}
|
||||
var flag = true
|
||||
if (flag) {
|
||||
console.log(sum(10, 20));
|
||||
}
|
||||
```
|
||||
|
||||
此时小明的`sum`是没有问题的。
|
||||
|
||||
> bbb.js
|
||||
|
||||
```javascript
|
||||
//小红
|
||||
var name = "小红"
|
||||
var flag = false
|
||||
```
|
||||
|
||||
此时小明和小红各自用各自的`flag`你变量没问题。
|
||||
|
||||
> 但是此时小明又创建了一个mmm.js
|
||||
|
||||
```javascript
|
||||
//小明
|
||||
if(flag){
|
||||
console.log("flag是true")
|
||||
}
|
||||
```
|
||||
|
||||
在index.html页面导入这些js文件
|
||||
|
||||
```php+HTML
|
||||
<script src="aaa.js" ></script>
|
||||
<script src="bbb.js" ></script>
|
||||
<script src="ccc.js" ></script>
|
||||
```
|
||||
|
||||
此时小明知道自己在aaa.js中定义的`flag`是`true`,认为打印没有问题,但是不知道小红的bbb.js中也定义了`flag`为`true`,所以mmm.js文件并没有打印出“flag是true”。
|
||||
|
||||
> 这就是全局变量同名问题。
|
||||
|
||||
# 2. 使用导出全局变量模块解决全局变量同名问题
|
||||
|
||||
> aaa.js
|
||||
|
||||
```javascript
|
||||
//模块对象
|
||||
var moduleA = (function (param) {
|
||||
//导出对象
|
||||
var obj = {}
|
||||
var name = '小明'
|
||||
var age = 22
|
||||
|
||||
function sum(num1, num2) {
|
||||
return num1 + num2
|
||||
}
|
||||
var flag = true
|
||||
if (flag) {
|
||||
console.log(sum(10, 20))
|
||||
}
|
||||
obj.flag=false
|
||||
return obj
|
||||
})()
|
||||
```
|
||||
|
||||
> mmm.js
|
||||
|
||||
```javascript
|
||||
//小明
|
||||
//使用全局变量moduleA
|
||||
if(moduleA.flag){
|
||||
console.log("flag是true")
|
||||
}
|
||||
```
|
||||
|
||||
这样直接使用aaa.js导出的moduleA变量获取小明自己定义的`flag`。
|
||||
|
||||
# 3. CommonJS的模块化实现
|
||||
|
||||
CommonJS需要nodeJS的依支持。
|
||||
|
||||
> aaa.js
|
||||
|
||||
```javascript
|
||||
var name = '小明'
|
||||
var age = 22
|
||||
|
||||
function sum(num1, num2) {
|
||||
return num1 + num2
|
||||
}
|
||||
var flag = true
|
||||
if (flag) {
|
||||
console.log(sum(10, 20))
|
||||
}
|
||||
|
||||
// module.exports = {
|
||||
// flag : flag,
|
||||
// sum : sum
|
||||
// }
|
||||
//导出对象
|
||||
module.exports = {
|
||||
flag,
|
||||
sum
|
||||
}
|
||||
```
|
||||
|
||||
使用`module.exports = {}`导出需要的对象。
|
||||
|
||||
> mmm.js
|
||||
|
||||
```javascript
|
||||
//导入对象,nodejs语法,需要node支持,从aaa.js取出对象
|
||||
var {flag,sum} = require("./aaa")
|
||||
|
||||
console.log(sum(10,20));
|
||||
|
||||
if(flag){
|
||||
console.log("flag is true");
|
||||
}
|
||||
```
|
||||
|
||||
使用 `var {flag,sum} = require("./aaa")`获取已经导出的对象中自己所需要的对象。
|
||||
|
||||
# 4. ES6的模块化实现
|
||||
|
||||
如何实现模块化,在html中需要使用`type='module'`属性。
|
||||
|
||||
```html
|
||||
<script src="aaa.js" type="module"></script>
|
||||
<script src="bbb.js" type="module"></script>
|
||||
<script src="mmm.js" type="module"></script>
|
||||
```
|
||||
|
||||
此时表示aaa.js是一个单独的模块,此模块是有作用域的。如果要使用aaa.js内的变量,需要在aaa.js中先导出变量,再在需要使用的地方导出变量。
|
||||
|
||||
## 4.1 直接导出
|
||||
|
||||
###
|
||||
|
||||
```javascript
|
||||
export let name = '小明'
|
||||
```
|
||||
|
||||
> 使用
|
||||
|
||||
```javascript
|
||||
import {name} from './aaa.js'
|
||||
console.log(name)
|
||||
```
|
||||
|
||||
`./aaa.js`表示aaa.js和mmm.js在同级目录。
|
||||
|
||||
如图打印结果。
|
||||
|
||||

|
||||
|
||||
## 4.2 统一导出
|
||||
|
||||
```javascript
|
||||
var age = 22
|
||||
function sum(num1, num2) {
|
||||
return num1 + num2
|
||||
}
|
||||
var flag = true
|
||||
if (flag) {
|
||||
console.log(sum(10, 20))
|
||||
}
|
||||
//2.最后统一导出
|
||||
export {
|
||||
flag,sum,age
|
||||
}
|
||||
```
|
||||
|
||||
> 使用`import {name,flag,sum} from './aaa.js'`导入多个变量
|
||||
|
||||
```javascript
|
||||
import {name,flag,sum} from './aaa.js'
|
||||
|
||||
console.log(name)
|
||||
|
||||
if(flag){
|
||||
console.log("小明是天才");
|
||||
}
|
||||
|
||||
console.log(sum(20,30));
|
||||
```
|
||||
|
||||
> 使用{}将需要的变量放置进去
|
||||
|
||||

|
||||
|
||||
## 4.3 导出函数/类
|
||||
|
||||
> 在aaa.js中添加
|
||||
|
||||
```javascript
|
||||
//3.导出函数/类
|
||||
export function say(value) {
|
||||
console.log(value);
|
||||
}
|
||||
export class Person{
|
||||
run(){
|
||||
console.log("奔跑");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 在mmm.js中添加
|
||||
|
||||
```javascript
|
||||
import {name,flag,sum,say,Person} from './aaa.js'
|
||||
|
||||
console.log(name)
|
||||
|
||||
if(flag){
|
||||
console.log("小明是天才");
|
||||
}
|
||||
|
||||
console.log(sum(20,30));
|
||||
|
||||
say('hello')
|
||||
const p = new Person();
|
||||
p.run();
|
||||
```
|
||||
|
||||
> 如图
|
||||
|
||||

|
||||
|
||||
## 4.4 默认导入 export default
|
||||
|
||||
> 导出
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
flag,sum,age
|
||||
}
|
||||
```
|
||||
|
||||
> 导入
|
||||
|
||||
```javascript
|
||||
//4.默认导入 export default
|
||||
import aaa from './aaa.js'
|
||||
console.log(aaa.sum(10,110));
|
||||
```
|
||||
|
||||
> 注意:使用默认导出会将所有需要导出的变量打包成一个对象,此时导出一个对象,此时我在`mmm.js`中导入变量时候命名为aaa,如果要调用变量需要使用aaa.变量。
|
||||
|
||||
## 4.5 统一全部导入
|
||||
|
||||
> 使用`import * as aaa from './aaa.js'`统一全部导入
|
||||
|
||||
```javascript
|
||||
// 5.统一全部导入
|
||||
import * as aaa from './aaa.js'
|
||||
console.log(aaa.flag);
|
||||
console.log(aaa.name);
|
||||
```
|
||||
1300
Vue/15-webpack.md
Normal file
1300
Vue/15-webpack.md
Normal file
File diff suppressed because it is too large
Load Diff
432
Vue/16-VueCLI.md
Normal file
432
Vue/16-VueCLI.md
Normal file
@@ -0,0 +1,432 @@
|
||||
# 1. vue-cli起步
|
||||
|
||||
## 1.1 什么是vue-cli
|
||||
|
||||
Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:
|
||||
|
||||
- 通过 `@vue/cli` 搭建交互式的项目脚手架。
|
||||
- 通过 `@vue/cli` + `@vue/cli-service-global` 快速开始零配置原型开发。
|
||||
- 一个运行时依赖 (`@vue/cli-service`),该依赖:
|
||||
- 可升级;
|
||||
- 基于 webpack 构建,并带有合理的默认配置;
|
||||
- 可以通过项目内的配置文件进行配置;
|
||||
- 可以通过插件进行扩展。
|
||||
- 一个丰富的官方插件集合,集成了前端生态中最好的工具。
|
||||
- 一套完全图形化的创建和管理 Vue.js 项目的用户界面。
|
||||
|
||||
Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。
|
||||
|
||||
## 1.2 **CLI是什么意思?**
|
||||
|
||||
- CLI是Command-Line Interface,即命令行界面,也叫脚手架。
|
||||
- vue cli 是vue.js官方发布的一个vue.js项目的脚手架
|
||||
- 使用vue-cli可以快速搭建vue开发环境和对应的webpack配置
|
||||
|
||||
## 1.3 vue cli使用
|
||||
|
||||
**vue cli使用前提node**
|
||||
|
||||
vue cli依赖nodejs环境,vue cli就是使用了webpack的模板。
|
||||
|
||||
安装vue脚手架,现在脚手架版本是vue cli3
|
||||
|
||||
```shell
|
||||
npm install -g @vue/cli
|
||||
```
|
||||
|
||||
如果使用yarn
|
||||
|
||||
```bash
|
||||
yarn global add @vue/cli
|
||||
```
|
||||
|
||||
安装完成后使用命令查看版本是否正确:
|
||||
|
||||
```bash
|
||||
vue --version
|
||||
```
|
||||
|
||||
> 注意安装cli失败
|
||||
|
||||
1. 以管理员使用cmd
|
||||
2. 清空npm-cache缓存
|
||||
|
||||
```bash
|
||||
npm clean cache -force
|
||||
```
|
||||
|
||||
**拉取2.x模板(旧版本)**
|
||||
|
||||
Vue CLI >= 3 和旧版使用了相同的 `vue` 命令,所以 Vue CLI 2 (`vue-cli`) 被覆盖了。如果你仍然需要使用旧版本的 `vue init` 功能,你可以全局安装一个桥接工具:
|
||||
|
||||
```bash
|
||||
npm install -g @vue/cli-init
|
||||
# `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同
|
||||
vue init webpack my-project
|
||||
```
|
||||
|
||||
**1.在根目录新建一个文件夹`16-vue-cli`,cd到此目录,新建一个vue-cli2的工程。**
|
||||
|
||||
```bash
|
||||
cd 16-vue-cli
|
||||
//全局安装桥接工具
|
||||
npm install -g @vue/cli-init
|
||||
//新建一个vue-cli2项目
|
||||
vue init webpack 01-vuecli2test
|
||||
```
|
||||
|
||||
> 注意:如果是创建vue-cli3的项目使用:
|
||||
|
||||
```bash
|
||||
vue create 02-vuecli3test
|
||||
```
|
||||
|
||||
2.创建工程选项含义
|
||||
|
||||

|
||||
|
||||
- project name:项目名字(默认)
|
||||
- project description:项目描述
|
||||
- author:作者(会默认拉去git的配置)
|
||||
- vue build:vue构建时候使用的模式
|
||||
- runtime+compiler:大多数人使用的,可以编译template模板
|
||||
- runtime-only:比compiler模式要少6kb,并且效率更高,直接使用render函数
|
||||
- install vue-router:是否安装vue路由
|
||||
- user eslint to lint your code:是否使用ES规范
|
||||
- set up unit tests:是否使用unit测试
|
||||
- setup e2e tests with nightwatch:是否使用end 2 end,点到点自动化测试
|
||||
- Should we run `npm install` for you after the project has been created? (recommended):使用npm还是yarn管理工具
|
||||
|
||||
等待创建工程成功。
|
||||
|
||||
> 注意:如果创建工程时候选择了使用ESLint规范,又不想使用了,需要在config文件夹下的index.js文件中找到useEslint,并改成false。
|
||||
|
||||
```javascript
|
||||
// Use Eslint Loader?
|
||||
// If true, your code will be linted during bundling and
|
||||
// linting errors and warnings will be shown in the console.
|
||||
useEslint: true,
|
||||
```
|
||||
|
||||
# 2. vue-cli2的目录结构
|
||||
|
||||
创建完成后,目录如图所示:
|
||||
|
||||

|
||||
|
||||
其中build和config都是配置相关的文件。
|
||||
|
||||
## 2.1 build和config
|
||||
|
||||

|
||||
|
||||
如图所示,build中将webpack的配置文件做了分离:
|
||||
|
||||
- `webpack.base.conf.js`(公共配置)
|
||||
- `webpack.dev.conf.js`(开发环境)
|
||||
- `webpack.prod.conf.js`(生产环境)
|
||||
|
||||
我们使用的脚本命令配置在`package.json`中。
|
||||
|
||||

|
||||
|
||||
打包构建:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
如果搭建了本地服务器`webpack-dev-server`,本地开发环境:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
此时`npm run build`打包命令相当于使用node 执行build文件夹下面的build.js文件。
|
||||
|
||||
> build.js
|
||||
|
||||

|
||||
|
||||
1. 检查dist文件夹是否已经存在,存在先删除
|
||||
2. 如果没有err,就使用webpack的配置打包dist文件夹
|
||||
|
||||
在生产环境,即使用build打包时候,使用的是`webpack.prod.conf.js`配置文件。
|
||||
|
||||

|
||||
|
||||
源码中,显然使用了`webpack-merge`插件来合并prod配置文件和公共的配置文件,合并成一个配置文件并打包,而`webpack.dev.conf.js`也是如此操作,在开发环境使用的是dev的配置文件。
|
||||
|
||||
config文件夹中是build的配置文件中所需的一些变量、对象,在`webpack.base.conf.js`中引入了`index.js`。
|
||||
|
||||
```javascript
|
||||
const config = require('../config')
|
||||
```
|
||||
|
||||
## 2.2 src和static
|
||||
|
||||
src源码目录,就是我们需要写业务代码的地方。
|
||||
|
||||
static是放静态资源的地方,static文件夹下的资源会原封不动的打包复制到dist文件夹下。
|
||||
|
||||
## 2.3 其他相关文件
|
||||
|
||||
### 2.3.1 .babelrc文件
|
||||
|
||||
.babelrc是ES代码相关转化配置。
|
||||
|
||||
```json
|
||||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false,
|
||||
"targets": {
|
||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||
}
|
||||
}],
|
||||
"stage-2"
|
||||
],
|
||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
||||
}
|
||||
```
|
||||
|
||||
1. browsers表示需要适配的浏览器,份额大于1%,最后两个版本,不需要适配ie8及以下版本
|
||||
2. babel需要的插件
|
||||
|
||||
### 2.3.2 .editorconfig文件
|
||||
|
||||
.editorconfig是编码配置文件。
|
||||
|
||||
```properties
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
```
|
||||
|
||||
一般是配置编码,代码缩进2空格,是否清除空格等。
|
||||
|
||||
### 2.3.3 .eslintignore文件
|
||||
|
||||
.eslintignore文件忽略一些不规范的代码。
|
||||
|
||||
```
|
||||
/build/
|
||||
/config/
|
||||
/dist/
|
||||
/*.js
|
||||
```
|
||||
|
||||
忽略build、config、dist文件夹和js文件。
|
||||
|
||||
### 2.3.4 .gitignore文件
|
||||
|
||||
.gitignore是git忽略文件,git提交忽略的文件。
|
||||
|
||||
### 2.3.5 .postcssrc.js文件
|
||||
|
||||
css转化是配置的一些。
|
||||
|
||||
### 2.3.6 index.html文件
|
||||
|
||||
index.html文件是使用`html-webpack-plugin`插件打包的index.html模板。
|
||||
|
||||
### 2.3.7 package.json和package-lock.json
|
||||
|
||||
1. package.json(包管理,记录大概安装的版本)
|
||||
2. package-lock.json(记录真实安装版本)
|
||||
|
||||
# 3. runtime-compiler和runtime-only区别
|
||||
|
||||
新建两个vuecli2项目:
|
||||
|
||||
```bash
|
||||
//新建一个以runtime-compiler模式
|
||||
vue init webpack 02-runtime-compiler
|
||||
//新建一个以runtime-only模式
|
||||
vue init webpack 03-runtime-only
|
||||
```
|
||||
|
||||
两个项目的main.js区别
|
||||
|
||||
> runtime-compiler
|
||||
|
||||
```javascript
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
components: { App },
|
||||
template: '<App/>'
|
||||
})
|
||||
```
|
||||
|
||||
> runtime-only
|
||||
|
||||
```javascript
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
render: h => h(App)
|
||||
})
|
||||
```
|
||||
|
||||
`render: h => h(App)`
|
||||
|
||||
```javascript
|
||||
render:function(h){
|
||||
return h(App)
|
||||
}
|
||||
```
|
||||
|
||||
**compiler编译解析template过程**
|
||||
|
||||

|
||||
|
||||
`vm.options.template`解析成`ast(abstract syntax tree)`抽象语法树,抽象语法树编译成`vm.options.render(functions)`render函数。render函数最终将template解析的ast渲染成虚拟DOM(`virtual dom`),最终虚拟dom映射到ui上。
|
||||
|
||||
**runtime-compiler**
|
||||
template会被解析 => ast(抽象语法树) => 然后编译成render函数 => 渲染成虚拟DOM(vdom)=> 真实dom(UI)
|
||||
**runtime-only**
|
||||
render => vdom => UI
|
||||
|
||||
1.性能更高,2.需要代码量更少
|
||||
|
||||
> render函数
|
||||
|
||||
```javascript
|
||||
render:function(createElement){
|
||||
//1.createElement('标签',{标签属性},[''])
|
||||
return createElement('h2',
|
||||
{class:'box'},
|
||||
['Hello World',createElement('button',['按钮'])])
|
||||
//2.传入组件对象
|
||||
//return createElement(cpn)
|
||||
}
|
||||
```
|
||||
|
||||
h就是一个传入的createElement函数,.vue文件的template是由vue-template-compiler解析。
|
||||
|
||||
将02-runtime-compiler的main.js修改
|
||||
|
||||
```javascript
|
||||
new Vue({
|
||||
el: '#app',
|
||||
// components: { App },
|
||||
// template: '<App/>'
|
||||
//1.createElement('标签',{标签属性},[''])
|
||||
render(createElement){
|
||||
return createElement('h2',
|
||||
{class:'box'},
|
||||
['hello vue', createElement('button',['按钮'])])
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
并把config里面的inedx.js的`useEslint: true`改成false,即关掉eslint规范,打包项目`npm run dev`,打开浏览器。
|
||||
|
||||

|
||||
|
||||
在修改main.js
|
||||
|
||||
```javascript
|
||||
new Vue({
|
||||
el: '#app',
|
||||
// components: { App },
|
||||
// template: '<App/>'
|
||||
//1.createElement('标签',{标签属性},[''])
|
||||
render(createElement){
|
||||
// return createElement('h2',
|
||||
// {class:'box'},
|
||||
// ['hello vue', createElement('button',['按钮'])])
|
||||
//2.传入组件
|
||||
return createElement(App)
|
||||
}
|
||||
```
|
||||
|
||||
再次打包,发现App组件被渲染了。
|
||||
|
||||

|
||||
|
||||
# 4. vue-cli3
|
||||
|
||||
## 4.1 vue-cli3起步
|
||||
|
||||
**vue-cli3与2版本区别**
|
||||
|
||||
- vue-cli3基于webpack4打造,vue-cli2是基于webpack3
|
||||
- vue-cli3的设计原则是"0配置",移除了配置文件,build和config等
|
||||
- vue-cli3提供`vue ui`的命令,提供了可视化配置
|
||||
- 移除了static文件夹,新增了public文件夹,并将index.html移入了public文件夹
|
||||
|
||||
**创建vue-cli3项目**
|
||||
|
||||
```bash
|
||||
vue create 04-vuecli3test
|
||||
```
|
||||
|
||||
**目录结构:**
|
||||
|
||||

|
||||
|
||||
- public 类似 static文件夹,里面的资源会原封不动的打包
|
||||
- src源码文件夹
|
||||
|
||||
|
||||
|
||||
使用`npm run serve`运行服务器,打开浏览器输入http://localhost:8080/
|
||||
|
||||
打开src下的main.js
|
||||
|
||||
```javascript
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
||||
```
|
||||
|
||||
`Vue.config.productionTip = false`构建信息是否显示
|
||||
|
||||
如果vue实例有el选项,vue内部会自动给你执行`$mount('#app')`,如果没有需要自己执行。
|
||||
|
||||
## 4.2 vue-cli3的配置
|
||||
|
||||
在创建vue-cli3项目的时候可以使用`vue ui`命令进入图形化界面创建项目,可以以可视化的方式创建项目,并配置项。
|
||||
|
||||
vue-cli3配置被隐藏起来了,可以在`node_modules`文件夹中找到`@vue`模块,打开其中的`cli-service`文件夹下的`webpack.config.js`文件。
|
||||
|
||||

|
||||
|
||||
再次打开当前目录下的`lib`文件夹,发现配置文件`service.js`,并导入了许多模块,来自与lib下面的config、util等模块
|
||||
|
||||

|
||||
|
||||
**如何要自定义配置文件**
|
||||
|
||||
在项目根目录下新建一个`vue.config.js`配置文件,必须为`vue.config.js`,vue-cli3会自动扫描此文件,在此文件中修改配置文件。
|
||||
|
||||
```javascript
|
||||
//在module.exports中修改配置
|
||||
module.exports = {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
1155
Vue/17-Vue-Router.md
Normal file
1155
Vue/17-Vue-Router.md
Normal file
File diff suppressed because it is too large
Load Diff
333
Vue/18-Promise.md
Normal file
333
Vue/18-Promise.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# 1. 什么是Promies
|
||||
|
||||
**简单说Promise是异步编程的一种解决方案。**
|
||||
|
||||
Promise是ES6中的特性。
|
||||
|
||||
> 什么是异步操作?
|
||||
|
||||
网络请求中,对端服务器处理需要时间,信息传递过程需要时间,不像我们本地调用一个js加法函数一样,直接获得`1+1=2`的结果。这里网络请求不是同步的有时延,不能立即得到结果。
|
||||
|
||||
> 如何处理异步事件?
|
||||
|
||||
对于网络请求这种,一般会使用回调函数,在服务端传给我数据成功后,调用回调函数。例如ajax调用。
|
||||
|
||||
```js
|
||||
$.ajax({
|
||||
success:function(){
|
||||
...
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
> 如果碰到嵌套网络请求,例如第一次网络请求成功后回调函数再次发送网络请求,这种代码就会让人很难受。
|
||||
|
||||
```json
|
||||
$.ajax({
|
||||
success:function(){
|
||||
$.ajax({
|
||||
...
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
如果还需要再次网络请求,那么又要嵌套一层,这样的代码层次不分明很难读,也容易出问题。
|
||||
|
||||
# 2. Promise的基本使用
|
||||
|
||||
## 2.1 什么时候使用Promise
|
||||
|
||||
解决异步请求冗余这样的问题,promise就是用于封装异步请求的。
|
||||
|
||||
## 2.2 Promise对象
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {})
|
||||
```
|
||||
|
||||
Promise对象的参数是一个函数`(resolve, reject) => {}`,这个函数又有2个参数分别是`resolve`和`reject`。这2个参数本身也是函数,是不是有点绕?后面还有回调函数`then(func)`的参数也是一个函数。
|
||||
|
||||
> 模拟定时器的异步事件
|
||||
|
||||
用定时器模拟网络请求,定时一秒为网络请求事件,用console.log()表示需要执行的代码。
|
||||
|
||||
```js
|
||||
//1.使用setTimeout模拟嵌套的三次网络请求
|
||||
setTimeout(() => {//第一次请求
|
||||
console.log("hello world")//第一次处理代码
|
||||
setTimeout(() => {//第二次请求
|
||||
console.log("hello vuejs")//第二次处理代码
|
||||
setTimeout(() => {//第三次请求
|
||||
console.log("hello java")//第三次处理代码
|
||||
}, 1000)
|
||||
}, 1000)
|
||||
}, 1000)
|
||||
```
|
||||
|
||||
一层套一层,看起是不是很绕。
|
||||
|
||||
使用promise来处理异步操作
|
||||
|
||||
```js
|
||||
//参数 -> 函数
|
||||
// resolve和reject本身也是函数
|
||||
//then()的参数也是一个函数
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {//第一次网络请求
|
||||
resolve()
|
||||
}, 1000)
|
||||
}).then(() => {
|
||||
console.log("hello world")//第一次处理代码
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {//第二次网络请求
|
||||
resolve()
|
||||
}, 1000).then(() => {
|
||||
console.log("hello vuejs")//第二次处理代码
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {//第三次网络请求
|
||||
resolve()
|
||||
}, 1000)
|
||||
}).then(() => {
|
||||
console.log("hello java")//第三次处理代码
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
是不是觉得代码还要更复杂了?仔细看看第一个如果使用了多个就找不到对应关系了。相反第二个流程就很清楚,调用`resolve()`就能跳转到`then()`方法就能执行处理代码,`then()`回调的返回值又是一个`Promise`对象。层次很明显,只要是`then()`必然就是执行处理代码,如果还有嵌套必然就是返回一个Promise对象,这样调用就像java中的StringBuffer的append()方法一样,链式调用。
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve('success')
|
||||
}, 1000).then(success => {
|
||||
console.log(success)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
setTimeout()模拟的是网络请求,而then()执行的是网络请求后的代码,这就将网络请求和请求得到响应后的操作分离了,每个地方干自己的事情。在resolve中传参了,那么在then()方法中的参数就有这个参数,例如data。
|
||||
|
||||
**网络请求中也会有失败情况?例如网络堵塞。**
|
||||
|
||||
如何处理失败情况,此时就要用到reject()
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
reject('error message')
|
||||
}, 1000).catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
此时`reject(error)`,`catch()`方法捕获到`reject()`中的error。
|
||||
|
||||
> 合起来
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
// 成功的时候调用resolve()
|
||||
// resolve('hello world')
|
||||
|
||||
// 失败的时候调用reject()
|
||||
reject('error message')
|
||||
}, 1000).then(success => {
|
||||
console.log(success)
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
拿ajax来举例子:
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
$.ajax({
|
||||
success:function(){
|
||||
// 成功的时候调用resolve()
|
||||
// resolve('hello world')
|
||||
|
||||
// 失败的时候调用reject()
|
||||
reject('error message')
|
||||
}
|
||||
}).then(success => {
|
||||
console.log(success)
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
# 3. Promise的三种状态
|
||||
|
||||

|
||||
|
||||
- pending:等待状态,比如正在进行的网络请求还未响应,或者定时器还没有到时间
|
||||
- fulfill:满足状态,当我们主动回调了resolve函数,就处于满足状态,并会回调then()
|
||||
- reject:拒绝状态,当我们主动回调reject函数,就处于该状态,并且会回调catch()
|
||||
|
||||
# 4. Promies的链式调用
|
||||
|
||||
1. 网络请求响应结果为 hello ,打印hello
|
||||
2. 处理: hello world ,打印hello world
|
||||
3. 处理: hello world,vuejs ,打印hello world,vuejs
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve('hello')
|
||||
}, 1000)
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello
|
||||
return new Promise(resolve => {
|
||||
resolve(res + ' world')
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world
|
||||
return new Promise(resolve => {
|
||||
resolve(res + ',vuejs')
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world,vuejs
|
||||
})
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
链式调用就是`then()`方法的返回值返回一个Promise对象继续调用`then()`,此外还有简写`Promise.resolve()`。
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve('hello')
|
||||
}, 1000)
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello
|
||||
return Promise.resolve(res + ' world')
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world
|
||||
return Promise.resolve(res + ',vuejs')
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world,vuejs
|
||||
})
|
||||
```
|
||||
|
||||
还可以直接省略掉`Promise.resolve()`
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve('hello')
|
||||
}, 1000)
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello
|
||||
return res + ' world'
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world
|
||||
return res + ',vuejs'
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world,vuejs
|
||||
})
|
||||
```
|
||||
|
||||
如果中途发生异常,可以通过`catch()`捕获异常
|
||||
|
||||
```js
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve('hello')
|
||||
}, 1000)
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello
|
||||
return res + ' world'
|
||||
}).then(res => {
|
||||
console.log(res)
|
||||
// return Promise.reject('error message')//发生异常
|
||||
throw 'error message' //抛出异常
|
||||
}).then(res => {
|
||||
console.log(res)//打印hello world,vuejs
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
```
|
||||
|
||||
也可以通过`throw`抛出异常,类似java
|
||||
|
||||
```js
|
||||
throw 'error message' //抛出异常
|
||||
```
|
||||
|
||||
# 5. Promies的all使用
|
||||
|
||||
有这样一个情况,一个业务需要请求2个地方(A和B)的数据,只有A和B的数据都拿到才能走下一步。
|
||||
|
||||
> ajax实现
|
||||
|
||||
```js
|
||||
$.ajax({
|
||||
...//结果A
|
||||
resultA = true
|
||||
callback()
|
||||
})
|
||||
$.ajax({
|
||||
...//结果B
|
||||
resultB = true
|
||||
callback()
|
||||
})
|
||||
//回调函数
|
||||
function callback(){
|
||||
if(resultA&&resultB){
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
由于不知道网络请求A和网络请求B哪个先返回结果,所以需要定义一个函数只有2个请求都返回数据才回调成功。
|
||||
|
||||
> Promise实现
|
||||
|
||||
```js
|
||||
Promise.all([
|
||||
new Promise((resolve, resjct) => {
|
||||
$.ajax({
|
||||
url: 'url1',
|
||||
success: function (data) {
|
||||
resolve(data)
|
||||
}
|
||||
})
|
||||
}),
|
||||
new Promise((resolve, resjct) => {
|
||||
$.ajax({
|
||||
url: 'url2',
|
||||
success: function (data) {
|
||||
resolve(data)
|
||||
}
|
||||
})
|
||||
}).then(results => {
|
||||
console.log(results)
|
||||
})
|
||||
])
|
||||
```
|
||||
|
||||
上面是伪代码,只是包装了ajax,ajaxA和ajaxB的结果都放在`resolve()`中,Promise将其放在`results`中了,使用`setTimeout`模拟。
|
||||
|
||||
```js
|
||||
Promise.all([
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {// 请求A
|
||||
resolve('结果A')
|
||||
}, 1000)
|
||||
}),
|
||||
new Promise((resolve, reject) => {
|
||||
setTimeout(() => {// 请求B
|
||||
resolve('结果B')
|
||||
}, 1000)
|
||||
})
|
||||
]).then(results => {
|
||||
console.log(results)
|
||||
})
|
||||
```
|
||||
1534
Vue/19-Vuex.md
Normal file
1534
Vue/19-Vuex.md
Normal file
File diff suppressed because it is too large
Load Diff
625
Vue/20-Axios的封装.md
Normal file
625
Vue/20-Axios的封装.md
Normal file
@@ -0,0 +1,625 @@
|
||||
# 1. Axios简介
|
||||
|
||||
## 1.1 什么是Axios
|
||||
|
||||
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
|
||||
|
||||
## 1.2 特性
|
||||
|
||||
- 浏览器端发起XMLHttpRequests请求
|
||||
- node端发起http请求
|
||||
- 支持Promise API
|
||||
- 监听请求和返回
|
||||
- 转化请求和返回
|
||||
- 取消请求
|
||||
- 自动转化json数据
|
||||
- 客户端支持抵御
|
||||
|
||||
# 2. Axios的使用和配置
|
||||
|
||||
## 2.1 安装
|
||||
|
||||
```shell
|
||||
npm install axios --save
|
||||
```
|
||||
|
||||
或者使用cdn
|
||||
|
||||
```javascript
|
||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||
```
|
||||
|
||||
## 2.2 基本使用
|
||||
|
||||
### 2.2.1 Get请求
|
||||
|
||||
```javascript
|
||||
axios.get('/user', {
|
||||
params: {
|
||||
name: 'krislin'
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(response);
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2.2 Post请求
|
||||
|
||||
```javascript
|
||||
axios.post('/user',{
|
||||
name:'krislin',
|
||||
address:'china'
|
||||
})
|
||||
.then(function(response){
|
||||
console.log(response);
|
||||
})
|
||||
.catch(function(error){
|
||||
console.log(error);
|
||||
});
|
||||
```
|
||||
|
||||
### 2.2.3 并发操作
|
||||
|
||||
```javascript
|
||||
function getUserAccount(){
|
||||
return axios.get('/user/12345');
|
||||
}
|
||||
|
||||
function getUserPermissions(){
|
||||
return axios.get('/user/12345/permissions');
|
||||
}
|
||||
|
||||
axios.all([getUerAccount(),getUserPermissions()])
|
||||
.then(axios.spread(function(acc,pers){
|
||||
//两个请求现在都完成
|
||||
}));
|
||||
```
|
||||
|
||||
## 2.3 请求API配置
|
||||
|
||||
axios 能够在进行请求时进行一些设置,具体如下:
|
||||
|
||||
```javascript
|
||||
axios({
|
||||
method:'post',
|
||||
url:'/user/12345',
|
||||
data:{
|
||||
name:'krislin',
|
||||
address:'china'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 2.4 请求设置
|
||||
|
||||
请求配置中,只有url是必须的,如果没有指明的话,默认是Get请求
|
||||
|
||||
```javascript
|
||||
{
|
||||
//`url`是服务器链接,用来请求用
|
||||
url:'/user',
|
||||
|
||||
//`method`是发起请求时的请求方法
|
||||
method:`get`,
|
||||
|
||||
//`baseURL`如果`url`不是绝对地址,那么将会加在其前面。
|
||||
//当axios使用相对地址时这个设置非常方便
|
||||
//在其实例中的方法
|
||||
baseURL:'http://some-domain.com/api/',
|
||||
|
||||
//`transformRequest`允许请求的数据在传到服务器之前进行转化。
|
||||
//这个也支持`PUT`,`GET`,`PATCH`方法。
|
||||
//数组中的最后一个函数必须返回一个字符串,一个`ArrayBuffer`,或者`Stream`
|
||||
transformRequest:[function(data){
|
||||
//依自己的需求对请求数据进行处理
|
||||
return data;
|
||||
}],
|
||||
|
||||
//`transformResponse`允许返回的数据传入then/catch之前进行处理
|
||||
transformResponse:[function(data){
|
||||
//依需要对数据进行处理
|
||||
return data;
|
||||
}],
|
||||
|
||||
//`headers`是自定义的要被发送的头信息
|
||||
headers:{'X-Requested-with':'XMLHttpRequest'},
|
||||
|
||||
//`params`是请求连接中的请求参数,必须是一个纯对象,或者URLSearchParams对象
|
||||
params:{
|
||||
ID:12345
|
||||
},
|
||||
|
||||
//`paramsSerializer`是一个可选的函数,是用来序列化参数
|
||||
//例如:(https://ww.npmjs.com/package/qs,http://api.jquery.com/jquery.param/)
|
||||
paramsSerializer: function(params){
|
||||
return Qs.stringify(params,{arrayFormat:'brackets'})
|
||||
},
|
||||
|
||||
//`data`是请求提需要设置的数据
|
||||
//只适用于应用的'PUT','POST','PATCH',请求方法
|
||||
//当没有设置`transformRequest`时,必须是以下其中之一的类型(不可重复?):
|
||||
//-string,plain object,ArrayBuffer,ArrayBufferView,URLSearchParams
|
||||
//-仅浏览器:FormData,File,Blob
|
||||
//-仅Node:Stream
|
||||
data:{
|
||||
firstName:'fred'
|
||||
},
|
||||
//`timeout`定义请求的时间,单位是毫秒。
|
||||
//如果请求的时间超过这个设定时间,请求将会停止。
|
||||
timeout:1000,
|
||||
|
||||
//`withCredentials`表明是否跨域请求,
|
||||
//应该是用证书
|
||||
withCredentials:false //默认值
|
||||
|
||||
//`adapter`适配器,允许自定义处理请求,这会使测试更简单。
|
||||
//返回一个promise,并且提供验证返回(查看[response docs](#response-api))
|
||||
adapter:function(config){
|
||||
/*...*/
|
||||
},
|
||||
|
||||
//`auth`表明HTTP基础的认证应该被使用,并且提供证书。
|
||||
//这个会设置一个`authorization` 头(header),并且覆盖你在header设置的Authorization头信息。
|
||||
auth:{
|
||||
username:'janedoe',
|
||||
password:'s00pers3cret'
|
||||
},
|
||||
|
||||
//`responsetype`表明服务器返回的数据类型,这些类型的设置应该是
|
||||
//'arraybuffer','blob','document','json','text',stream'
|
||||
responsetype:'json',
|
||||
|
||||
//`xsrfHeaderName` 是http头(header)的名字,并且该头携带xsrf的值
|
||||
xrsfHeadername:'X-XSRF-TOKEN',//默认值
|
||||
|
||||
//`onUploadProgress`允许处理上传过程的事件
|
||||
onUploadProgress: function(progressEvent){
|
||||
//本地过程事件发生时想做的事
|
||||
},
|
||||
|
||||
//`onDownloadProgress`允许处理下载过程的事件
|
||||
onDownloadProgress: function(progressEvent){
|
||||
//下载过程中想做的事
|
||||
},
|
||||
|
||||
//`maxContentLength` 定义http返回内容的最大容量
|
||||
maxContentLength: 2000,
|
||||
|
||||
//`validateStatus` 定义promise的resolve和reject。
|
||||
//http返回状态码,如果`validateStatus`返回true(或者设置成null/undefined),promise将会接受;其他的promise将会拒绝。
|
||||
validateStatus: function(status){
|
||||
return status >= 200 && stauts < 300;//默认
|
||||
},
|
||||
|
||||
//`httpAgent` 和 `httpsAgent`当产生一个http或者https请求时分别定义一个自定义的代理,在nodejs中。
|
||||
//这个允许设置一些选选个,像是`keepAlive`--这个在默认中是没有开启的。
|
||||
httpAgent: new http.Agent({keepAlive:treu}),
|
||||
httpsAgent: new https.Agent({keepAlive:true}),
|
||||
|
||||
//`proxy`定义服务器的主机名字和端口号。
|
||||
//`auth`表明HTTP基本认证应该跟`proxy`相连接,并且提供证书。
|
||||
//这个将设置一个'Proxy-Authorization'头(header),覆盖原先自定义的。
|
||||
proxy:{
|
||||
host:127.0.0.1,
|
||||
port:9000,
|
||||
auth:{
|
||||
username:'cdd',
|
||||
password:'123456'
|
||||
}
|
||||
},
|
||||
|
||||
//`cancelTaken` 定义一个取消,能够用来取消请求
|
||||
//(查看 下面的Cancellation 的详细部分)
|
||||
cancelToke: new CancelToken(function(cancel){
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## 2.5 响应数据Response
|
||||
|
||||
一个请求的返回包含以下信息
|
||||
|
||||
```javascript
|
||||
{
|
||||
//`data`是服务器的提供的回复(相对于请求)
|
||||
data{},
|
||||
|
||||
//`status`是服务器返回的http状态码
|
||||
status:200,
|
||||
|
||||
|
||||
//`statusText`是服务器返回的http状态信息
|
||||
statusText: 'ok',
|
||||
|
||||
//`headers`是服务器返回中携带的headers
|
||||
headers:{},
|
||||
|
||||
//`config`是对axios进行的设置,目的是为了请求(request)
|
||||
config:{}
|
||||
}
|
||||
```
|
||||
|
||||
## 2.6 拦截器Interceptors
|
||||
|
||||
你可以在 请求 或者 返回 被 then 或者 catch 处理之前对他们进行拦截。
|
||||
|
||||
添加拦截器:
|
||||
|
||||
```javascript
|
||||
//添加一个请求拦截器
|
||||
axios.interceptors.request.use(function(config){
|
||||
//在请求发送之前做一些事
|
||||
return config;
|
||||
},function(error){
|
||||
//当出现请求错误是做一些事
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
//添加一个返回拦截器
|
||||
axios.interceptors.response.use(function(response){
|
||||
//对返回的数据进行一些处理
|
||||
return response;
|
||||
},function(error){
|
||||
//对返回的错误进行一些处理
|
||||
return Promise.reject(error);
|
||||
});
|
||||
```
|
||||
|
||||
移除拦截器:
|
||||
|
||||
```javascript
|
||||
var myInterceptor = axios.interceptors.request.use(function(){/*...*/});
|
||||
axios.interceptors.rquest.eject(myInterceptor);
|
||||
```
|
||||
|
||||
# 3. 跨域
|
||||
|
||||
因为在Vue的开发阶段,基本都是用webpack打包编译,需要node环境本地运行,因而运行的域名为本地的localhost,这个时候调用后端接口就涉及到跨域的问题了。
|
||||
|
||||
## 3.1 ProxyTable
|
||||
|
||||
vue 的 proxyTable 是用于开发阶段配置跨域的工具,可以同时配置多个后台服务器跨越请求接口,其真正依赖的npm包是 [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware), 在GitHub上拥有更丰富的配置,可以按需配置
|
||||
|
||||
**在不考虑后端CROS跨域方案的情况下,前端配置ProxyTable实现跨域请求的用法如下:**
|
||||
|
||||
### 1. 找到 **config/index.js** 文件中的 `proxyTable:{}` 将其修改
|
||||
|
||||
```javascript
|
||||
proxyTable: {
|
||||
'/api': {
|
||||
target: 'https://tasst.sinoxk.cn', // 这个是你要代理的地址(开发阶段接口地址)
|
||||
changeOrigin: true, //跨域需要加上这个
|
||||
pathRewrite: {
|
||||
'^/api': '' //可以理解为用 / api代表target里的地址
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
proxyTable支持配置多个接口:
|
||||
|
||||
```javascript
|
||||
proxyTable: {
|
||||
'/api': {
|
||||
target: 'https://tasst.sinoxk.cn', // 这个是你要代理的地址(开发阶段接口地址)
|
||||
changeOrigin: true, //跨域需要加上这个
|
||||
pathRewrite: {
|
||||
'^/api': '' //可以理解为用 / api代表target里的地址
|
||||
}
|
||||
},
|
||||
'/service': {
|
||||
target: 'https://tasst.sinoxk.cn', // 这个是你要代理的地址(开发阶段接口地址)
|
||||
changeOrigin: true, //跨域需要加上这个
|
||||
pathRewrite: {
|
||||
'^/service': '' //可以理解为用 / api代表target里的地址
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 找到 **config/dev.env.js** 文件,配置`BASE_URL`
|
||||
|
||||
```javascript
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
BASE_URL:'"/api"' //开发环境域名
|
||||
})
|
||||
```
|
||||
|
||||
### 3. 找到 **config/prod.env.js** 文件,配置`BASE_URL`
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"',
|
||||
BASE_URL:'"https://asst.sinoxk.com"' //生产环境保持正式域名
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 配置 **axios** 的基础域名
|
||||
|
||||
```properties
|
||||
axios.defaults.baseURL = process.env.BASE_URL
|
||||
```
|
||||
|
||||
**修改完所有的配置文件后,要注意,需要重启下环境**
|
||||
|
||||
```shell
|
||||
npm run dev / npm run start
|
||||
```
|
||||
|
||||
# 4. 封装
|
||||
|
||||
在日常项目开发过程中,在和后台交互获取数据的时候,我们都需要使用到网络库,通常在vue的项目中 ,使用的是 **axios** 库 ,在此基于自身项目业务,做一个二次封装。
|
||||
|
||||
## 4.1 条件准备
|
||||
|
||||
在UI轻提示组件上,选定的是 **vant** 库中的 **Toast** 组件([Vant文档](https://youzan.github.io/vant/#/zh-CN/intro)),可按实际需要选定具体要使用的UI框架
|
||||
|
||||
安装:
|
||||
|
||||
```shell
|
||||
npm install vant --save
|
||||
```
|
||||
|
||||
数据序列化,如果有实际需要的项目,可以使用`qs`,在这里做一个简单的介绍
|
||||
|
||||
安装:
|
||||
|
||||
```shell
|
||||
npm install qs --save
|
||||
```
|
||||
|
||||
**qs.stringify和JSON.stringify的使用和区别**
|
||||
|
||||
qs.stringify()将对象 序列化成URL的形式,以&进行拼接
|
||||
|
||||
JSON.stringify 是将对象转化成一个json字符串的形式
|
||||
|
||||
**用法:**
|
||||
|
||||
```javascript
|
||||
var a = {name:'xiaoming',age:10}
|
||||
|
||||
qs.stringify(a); //log: 'name=xiaoming&age=10'
|
||||
|
||||
JSON.stringify(a) //log: '{"name":"hehe","age":10}'
|
||||
```
|
||||
|
||||
基于底层配置和业务接口分离,在src目录中会新建文件夹 **httpServer**,同时新建立 **ajax.js** 和 **api.js** 文件
|
||||
|
||||
```
|
||||
ajax.js: axios的二次封装,作为基础网络库,添加基础的配置
|
||||
```
|
||||
|
||||
|
||||
|
||||
```
|
||||
api.js: 管理项目实际业务基础接口的输出,以及返回响应数据的处理
|
||||
```
|
||||
|
||||
在日常项目模块中,基于多人开发,当然可以在api.js的基础上,可以根据功能模块实现业务拓展延伸,比如
|
||||
|
||||
```javascript
|
||||
小明负责list模块业务
|
||||
|
||||
新建api-list.js,并导入api.js ....
|
||||
|
||||
//api-list.js文件中:
|
||||
import api from './api'
|
||||
|
||||
export default {
|
||||
getList(url,params){
|
||||
api.get(url,params)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
对于个别项目,可能存在多个域名配置的情况下, 可以重新建立 **base.js** , 来管理多个接口域名
|
||||
|
||||
**base.js:**
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* 接口域名的管理
|
||||
*/
|
||||
const base = {
|
||||
sq: 'https://xxxx111111.com/api/v1',
|
||||
bd: 'http://xxxxx22222.com/api'
|
||||
}
|
||||
|
||||
export default base;
|
||||
```
|
||||
|
||||
## 4.2 axios封装(单域名)
|
||||
|
||||
**src/main.js文件:**
|
||||
|
||||
```javascript
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
import router from './router'
|
||||
import Api from './httpServer/api'
|
||||
|
||||
//挂载到vue的全局属性上
|
||||
Vue.prototype.$https = Api
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
components: { App },
|
||||
template: '<App/>'
|
||||
})
|
||||
```
|
||||
|
||||
**src/httpServer/ajax.js文件:**
|
||||
|
||||
```javascript
|
||||
import axios from 'axios'
|
||||
import {Toast} from 'vant'
|
||||
|
||||
|
||||
const ajax = axios.create({
|
||||
timeout:60000,
|
||||
baseURL:process.env.BASE_URL //基础域名
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* 请求拦截器
|
||||
* 每次请求前,如果存在token则在请求头中携带token
|
||||
*/
|
||||
ajax.interceptors.request.use(
|
||||
config => {
|
||||
//判断token(根据实际情况拦截)
|
||||
|
||||
return config;
|
||||
},
|
||||
error => Promise.error(error)
|
||||
)
|
||||
|
||||
/**
|
||||
* 响应拦截器
|
||||
*/
|
||||
ajax.interceptors.response.use(
|
||||
// 请求成功
|
||||
res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
|
||||
error => {
|
||||
const {response} = error;
|
||||
if (response) { // 请求已发出,但是不在2xx的范围
|
||||
Toast({message: response.message});
|
||||
return Promise.reject(response);
|
||||
} else {
|
||||
// 处理断网的情况
|
||||
// eg:请求超时或断网时,更新state的network状态
|
||||
// network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
|
||||
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
|
||||
Toast({message: '网络开小差,请稍后重试'});
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export default ajax;
|
||||
```
|
||||
|
||||
对于**process.env.BASE_URL**的配置,在开发环境中,需要以代理的方式进行访问:
|
||||
|
||||
```javascript
|
||||
//config/dev.env.js
|
||||
|
||||
'use strict'
|
||||
const merge = require('webpack-merge')
|
||||
const prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
BASE_URL:'"/api"' //对api进行处理
|
||||
})
|
||||
```
|
||||
|
||||
```javascript
|
||||
//config/prod.env.js
|
||||
|
||||
'use strict'
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"',
|
||||
BASE_URL:'"https://www.xxx.com"' //生产环境不需要处理
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
//config/index.js
|
||||
...
|
||||
|
||||
proxyTable: {
|
||||
'/api': {
|
||||
target: 'https://tasst.sinoxk.cn',//后端接口地址
|
||||
changeOrigin: true,//是否允许跨越
|
||||
pathRewrite: {
|
||||
'^/api': '',//重写(接口地址带api会被替换)
|
||||
},
|
||||
}
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
**src/httpServer/api.js文件:**
|
||||
|
||||
```javascript
|
||||
import ajax from './ajax'
|
||||
import {Toast} from 'vant'
|
||||
|
||||
/**
|
||||
* 业务接口成功或者失败的情况处理
|
||||
*
|
||||
*/
|
||||
const handleResponse = (res, success, failure) => {
|
||||
switch (res.code) {
|
||||
case 200: //成功
|
||||
success && success(res.data);
|
||||
break;
|
||||
case 401: //登录token失效
|
||||
|
||||
break;
|
||||
default:
|
||||
if (failure) {
|
||||
failure(res);
|
||||
} else {
|
||||
Toast({message:res.msg || '请求失败,请稍后重试!'});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
get: function (url, params, success, failure) {
|
||||
ajax.get(url, {
|
||||
params: params
|
||||
}).then(res => {
|
||||
if (res.status == 200) {
|
||||
handleResponse(res.data.data, success, failure);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
post: function (url, params, success, failure) {
|
||||
ajax.post(url, params).then(res => {
|
||||
if (res.status == 200) {
|
||||
handleResponse(res.data.data, success, failure);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在**src/components/HelloWorld.vue**文件中使用:
|
||||
|
||||
```javascript
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
data() {
|
||||
return {
|
||||
msg: 'Welcome to Your Vue.js App'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
//请求接口数据
|
||||
this.$https.get('/xkzx/member/service', {
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
}, function (data) { //成功
|
||||
console.log(data);
|
||||
|
||||
}, function (res) { //失败
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
311
Vue/README.md
Normal file
311
Vue/README.md
Normal file
@@ -0,0 +1,311 @@
|
||||
# [01-ES6补充](01-ES6补充.md)
|
||||
- [1. 块级作用域](01-ES6补充.md/#1-块级作用域)
|
||||
- [1.1. 什么是变量作用域](01-ES6补充.md/#11-什么是变量作用域)
|
||||
- [1.2. 没有块级作用域造成的问题](01-ES6补充.md/#12-没有块级作用域造成的问题)
|
||||
- [if块级](01-ES6补充.md/#if块级)
|
||||
- [for块级](01-ES6补充.md/#for块级)
|
||||
- [2. const的使用](01-ES6补充.md/#2-const的使用)
|
||||
- [3. ES6的增强写法](01-ES6补充.md/#3-es6的增强写法)
|
||||
- [3.1. ES6的对象属性增强型写法](01-ES6补充.md/#31-es6的对象属性增强型写法)
|
||||
- [3.2 ES6对象的函数增强型写法](01-ES6补充.md/#32es6对象的函数增强型写法)
|
||||
- [4. 箭头函数](#4箭头函数)
|
||||
- [4.1 箭头函数的参数和返回值](01-ES6补充.md/#41箭头函数的参数和返回值)
|
||||
- [4.1.1 参数问题](01-ES6补充.md/#411参数问题)
|
||||
- [4.1.2 函数内部](01-ES6补充.md/#412函数内部)
|
||||
- [4.3 箭头函数的this使用](01-ES6补充.md/#43箭头函数的this使用)
|
||||
- [5. 高阶函数](01-ES6补充.md/#5-高阶函数)
|
||||
- [5.1 filter过滤函数](01-ES6补充.md/#51filter过滤函数)
|
||||
- [5.2 map高阶函数](01-ES6补充.md/#52map高阶函数)
|
||||
- [5.3 reduce高阶函数](01-ES6补充.md/#53reduce高阶函数)
|
||||
- [5.4综合使用](01-ES6补充.md/#54综合使用)
|
||||
|
||||
# [02-HelloVue](02-HelloVue.md)
|
||||
- [1. HelloVuejs](02-HelloVue.md/#1-hellovuejs)
|
||||
- [1.1. 命令式编程](02-HelloVue.md/#11-命令式编程)
|
||||
- [1.2 . 声明式编程](02-HelloVue.md/#12--声明式编程)
|
||||
- [2. vue列表的展示(v-for)](02-HelloVue.md/#2-vue列表的展示v-for)
|
||||
- [3. vue案例-计数器](02-HelloVue.md/#3-vue案例-计数器)
|
||||
|
||||
# [03-插值操作](03-插值操作.md)
|
||||
- [1. Mustache语法](03-插值操作.md/#1-mustache语法)
|
||||
- [2. v-once](03-插值操作.md/#2-v-once)
|
||||
- [3. v-html](03-插值操作.md/#3-v-html)
|
||||
- [4. v-text](03-插值操作.md/#4-v-text)
|
||||
- [5. v-pre](03-插值操作.md/#5-v-pre)
|
||||
- [6. v-cloak](03-插值操作.md/#6-v-cloak)
|
||||
|
||||
# [04-动态绑定属性](04-动态绑定属性.md)
|
||||
- [1. v-bind的基本使用](04-动态绑定属性.md/#1-v-bind的基本使用)
|
||||
- [2. v-bind动态绑定class](04-动态绑定属性.md/#2-v-bind动态绑定class)
|
||||
- [2.1. v-bind动态绑定class(对象语法)](04-动态绑定属性.md/#21-v-bind动态绑定class对象语法)
|
||||
- [2.2. v-bind动态绑定class(数组用法)](04-动态绑定属性.md/#22-v-bind动态绑定class数组用法)
|
||||
- [3. v-for和v-bind结合](04-动态绑定属性.md/#3-v-for和v-bind结合)
|
||||
- [4. v-bind动态绑定style](04-动态绑定属性.md/#4-v-bind动态绑定style)
|
||||
- [4.1 v-bind动态绑定style(对象语法)](04-动态绑定属性.md/#41-v-bind动态绑定style对象语法)
|
||||
- [4.2 v-bind动态绑定style(数组语法)](04-动态绑定属性.md/#42-v-bind动态绑定style数组语法)
|
||||
|
||||
# [05-计算属性与侦听器](05-计算属性与侦听器.md)
|
||||
- [1. 计算属性的基本使用](05-计算属性与侦听器.md/#1-计算属性的基本使用)
|
||||
- [2. 计算属性的复杂使用](05-计算属性与侦听器.md/#2-计算属性的复杂使用)
|
||||
- [3. 计算属性的setter和getter](05-计算属性与侦听器.md/#3-计算属性的setter和getter)
|
||||
- [4. 计算属性和methods的对比](05-计算属性与侦听器.md/#4-计算属性和methods的对比)
|
||||
- [5. Vue计算属性与侦听器总结](05-计算属性与侦听器.md/#5-vue计算属性与侦听器总结)
|
||||
|
||||
# [06-事件监听](06-事件监听.md)
|
||||
- [1. v-on的基本使用](06-事件监听.md/#1-v-on的基本使用)
|
||||
- [2. v-on的参数传递](06-事件监听.md/#2-v-on的参数传递)
|
||||
- [3. v-on的修饰词](06-事件监听.md/#3-v-on的修饰词)
|
||||
|
||||
# [07-条件判断](07-条件判断.md)
|
||||
- [1. v-if、v-else、v-elseif](07-条件判断.md/#1-v-ifv-elsev-elseif)
|
||||
- [2. v-if的demo](07-条件判断.md/#2-v-if的demo)
|
||||
- [3. v-show](07-条件判断.md/#3-v-show)
|
||||
|
||||
# [08-循环遍历](08-循环遍历.md)
|
||||
- [1. v-for遍历数组](08-循环遍历.md/#1-v-for遍历数组)
|
||||
- [2. v-for遍历对象](08-循环遍历.md/#2-v-for遍历对象)
|
||||
- [3. v-for使用key](08-循环遍历.md/#3-v-for使用key)
|
||||
- [4. 数组的响应方式](08-循环遍历.md/#4-数组的响应方式)
|
||||
- [5. 综合练习](08-循环遍历.md/#5-综合练习)
|
||||
|
||||
# [09-综合练习](09-综合练习.md)
|
||||
- [1. 目录结构](09-综合练习.md/#1-目录结构)
|
||||
- [2. index.html](09-综合练习.md/#2-indexhtml)
|
||||
- [3.main.js](09-综合练习.md/#3mainjs)
|
||||
- [4. style.css](09-综合练习.md/#4-stylecss)
|
||||
- [filter、map、reduce](09-综合练习.md/#filtermapreduce)
|
||||
|
||||
# [10-v-model](10-v-model.md)
|
||||
- [1. v-model的基本使用](10-v-model.md/#1-v-model的基本使用)
|
||||
- [2. v-model的原理](10-v-model.md/#2-v-model的原理)
|
||||
- [3. v-model结合radio类型使用](10-v-model.md/#3-v-model结合radio类型使用)
|
||||
- [4. v-model结合checkbox类型使用](10-v-model.md/#4-v-model结合checkbox类型使用)
|
||||
- [5. v-model结合select](10-v-model.md/#5-v-model结合select)
|
||||
- [6. v-model的修饰符的使用](10-v-model.md/#6-v-model的修饰符的使用)
|
||||
|
||||
# [11-组件化开发](11-组件化开发.md)
|
||||
- [1. 组件的基本使用](11-组件化开发.md/#1-组件的基本使用)
|
||||
- [1.1 创建组件构造器对象](11-组件化开发.md/#11-创建组件构造器对象)
|
||||
- [1.2 注册组件](11-组件化开发.md/#12-注册组件)
|
||||
- [1.3 使用组件](11-组件化开发.md/#13-使用组件)
|
||||
- [2. 全局组件和局部组件](11-组件化开发.md/#2-全局组件和局部组件)
|
||||
- [2.1 全局组件](11-组件化开发.md/#21-全局组件)
|
||||
- [2.2 局部组件](11-组件化开发.md/#22-局部组件)
|
||||
- [3. 父组件和子组件的区别](11-组件化开发.md/#3-父组件和子组件的区别)
|
||||
- [4. 注册组件的语法糖](11-组件化开发.md/#4-注册组件的语法糖)
|
||||
- [5. 组件模板的分离写法](11-组件化开发.md/#5-组件模板的分离写法)
|
||||
- [5.1 script标签](11-组件化开发.md/#51-script标签)
|
||||
- [5.2 template标签](11-组件化开发.md/#52-template标签)
|
||||
- [6. 组件的数据](11-组件化开发.md/#6-组件的数据)
|
||||
- [6.1 存放问题](11-组件化开发.md/#61-存放问题)
|
||||
- [6.2 组件的data为什么必须要是函数](11-组件化开发.md/#62-组件的data为什么必须要是函数)
|
||||
- [7. 父组件给子组件传递数据](11-组件化开发.md/#7-父组件给子组件传递数据)
|
||||
- [7.1 使用`props`属性,父组件向子组件传递数据](11-组件化开发.md/#71-使用props属性父组件向子组件传递数据)
|
||||
- [7.2 props属性使用](11-组件化开发.md/#72-props属性使用)
|
||||
- [8. 组件通信](11-组件化开发.md/#8-组件通信)
|
||||
- [8.1 父传子(props的驼峰标识)](11-组件化开发.md/#81-父传子props的驼峰标识)
|
||||
- [8.2 子传父`$emit`](11-组件化开发.md/#82-子传父emit)
|
||||
- [8.3 父子组件通信案例](11-组件化开发.md/#83-父子组件通信案例)
|
||||
- [9. 父访问子(children-ref)](11-组件化开发.md/#9-父访问子children-ref)
|
||||
|
||||
# [12-组件化高级](12-组件化高级.md)
|
||||
- [1. slot-插槽的基本使用](12-组件化高级.md/#1-slot-插槽的基本使用)
|
||||
- [2. slot-具名插槽的使用](12-组件化高级.md/#2-slot-具名插槽的使用)
|
||||
- [3. 编译的作用域](12-组件化高级.md/#3-编译的作用域)
|
||||
- [4. 作用域插槽案例](12-组件化高级.md/#4-作用域插槽案例)
|
||||
|
||||
# [13-Vue实例的生命周期](13-Vue实例的生命周期.md)
|
||||
- [1. 生命周期图](13-Vue实例的生命周期.md/#1-生命周期图)
|
||||
- [2. 再探究](13-Vue实例的生命周期.md/#2-再探究)
|
||||
- [2.1 beforeCreate之前](13-Vue实例的生命周期.md/#21-beforecreate之前)
|
||||
- [2.2 beforeCreate和created钩子函数间的生命周期](13-Vue实例的生命周期.md/#22-beforecreate和created钩子函数间的生命周期)
|
||||
- [2.3 created钩子函数和beforeMount间的生命周期](13-Vue实例的生命周期.md/#23-created钩子函数和beforemount间的生命周期)
|
||||
- [2.3.1 el选项对生命周期影响](13-Vue实例的生命周期.md/#231-el选项对生命周期影响)
|
||||
- [2.3.2 template](13-Vue实例的生命周期.md/#232-template)
|
||||
- [2.4 beforeMount和mounted钩子函数间的生命周期](13-Vue实例的生命周期.md/#24-beforemount和mounted钩子函数间的生命周期)
|
||||
- [2.5 beforeUpdate钩子函数和updated钩子函数间的生命周期](13-Vue实例的生命周期.md/#25-beforeupdate钩子函数和updated钩子函数间的生命周期)
|
||||
- [2.6 beforeDestroy和destroyed钩子函数间的生命周期](13-Vue实例的生命周期.md/#26-beforedestroy和destroyed钩子函数间的生命周期)
|
||||
- [2.6.1 beforeDestroy](13-Vue实例的生命周期.md/#261-beforedestroy)
|
||||
- [2.6.2 destroyed](13-Vue实例的生命周期.md/#262-destroyed)
|
||||
- [总结](13-Vue实例的生命周期.md/#总结)
|
||||
|
||||
# [14-前端模块化](14-前端模块化.md)
|
||||
- [1. 为什么要模块化](14-前端模块化.md/#1-为什么要模块化)
|
||||
- [2. 使用导出全局变量模块解决全局变量同名问题](14-前端模块化.md/#2-使用导出全局变量模块解决全局变量同名问题)
|
||||
- [3. CommonJS的模块化实现](14-前端模块化.md/#3-commonjs的模块化实现)
|
||||
- [4. ES6的模块化实现](14-前端模块化.md/#4-es6的模块化实现)
|
||||
- [4.1 直接导出](14-前端模块化.md/#41-直接导出)
|
||||
- [](#)
|
||||
- [4.2 统一导出](14-前端模块化.md/#42-统一导出)
|
||||
- [4.3 导出函数/类](14-前端模块化.md/#43-导出函数类)
|
||||
- [4.4 默认导入 export default](14-前端模块化.md/#44-默认导入-export-default)
|
||||
- [4.5 统一全部导入](14-前端模块化.md/#45-统一全部导入)
|
||||
|
||||
# [15-webpack](15-webpack.md)
|
||||
- [1. webpack起步](15-webpack.md/#1-webpack起步)
|
||||
- [1.1 什么是webpack](15-webpack.md/#11-什么是webpack)
|
||||
- [1.2 webpack的安装](15-webpack.md/#12-webpack的安装)
|
||||
- [1.3 起步](15-webpack.md/#13-起步)
|
||||
- [**目录结构**](15-webpack.md/#目录结构)
|
||||
- [**1.新建入口js文件`main.js`和`mathUtils.js`,`main.js`依赖`mathUtils.js`。**](15-webpack.md/#1新建入口js文件mainjs和mathutilsjsmainjs依赖mathutilsjs)
|
||||
- [**2.使用webpack命令打包js文件**](15-webpack.md/#2使用webpack命令打包js文件)
|
||||
- [**3.新建一个index.html文件,导入bundle.js**](15-webpack.md/#3新建一个indexhtml文件导入bundlejs)
|
||||
- [**4.新建一个`info.js`使用ES6的语法导出**](15-webpack.md/#4新建一个infojs使用es6的语法导出)
|
||||
- [**5.打开index.html测试**](15-webpack.md/#5打开indexhtml测试)
|
||||
- [2. webpack的配置](15-webpack.md/#2-webpack的配置)
|
||||
- [2.1 基本配置](15-webpack.md/#21-基本配置)
|
||||
- [**1.在根目录下新建一个`webpack.config.js`**](15-webpack.md/#1在根目录下新建一个webpackconfigjs)
|
||||
- [**2.在根目录执行`npm init`初始化node包,因为配置文件中用到了node的path包**](15-webpack.md/#2在根目录执行npm-init初始化node包因为配置文件中用到了node的path包)
|
||||
- [**3.使用webpack打包**](15-webpack.md/#3使用webpack打包)
|
||||
- [**4.使用自定义脚本(script)启动**](15-webpack.md/#4使用自定义脚本script启动)
|
||||
- [2.2 全局安装和局部安装](15-webpack.md/#22-全局安装和局部安装)
|
||||
- [3. webpack的loader](15-webpack.md/#3-webpack的loader)
|
||||
- [3.1 什么是loader](15-webpack.md/#31-什么是loader)
|
||||
- [3.2 CSS文件处理](15-webpack.md/#32-css文件处理)
|
||||
- [3.3 less文件处理](15-webpack.md/#33-less文件处理)
|
||||
- [3.4 图片文件的处理](15-webpack.md/#34-图片文件的处理)
|
||||
- [3.5 ES6语法处理](15-webpack.md/#35-es6语法处理)
|
||||
- [4. webpack的vue](15-webpack.md/#4-webpack的vue)
|
||||
- [4.1 简单安装使用vue](15-webpack.md/#41-简单安装使用vue)
|
||||
- [4.2 如何分步抽取实现vue模块](15-webpack.md/#42-如何分步抽取实现vue模块)
|
||||
- [5. webpack的plugin](15-webpack.md/#5-webpack的plugin)
|
||||
- [5.1 添加版权的Plugin](15-webpack.md/#51-添加版权的plugin)
|
||||
- [5.2 打包html的plugin](15-webpack.md/#52-打包html的plugin)
|
||||
- [5.3压缩打包代码插件](15-webpack.md/#53压缩打包代码插件)
|
||||
- [6. webpack搭建本地服务器](15-webpack.md/#6-webpack搭建本地服务器)
|
||||
- [7. webpack的配置文件分离](15-webpack.md/#7-webpack的配置文件分离)
|
||||
|
||||
# [16-VueCLI](16-VueCLI.md)
|
||||
- [1. vue-cli起步](16-VueCLI.md/#1-vue-cli起步)
|
||||
- [1.1 什么是vue-cli](16-VueCLI.md/#11-什么是vue-cli)
|
||||
- [1.2 **CLI是什么意思?**](16-VueCLI.md/#12-cli是什么意思)
|
||||
- [1.3 vue cli使用](16-VueCLI.md/#13-vue-cli使用)
|
||||
- [2. vue-cli2的目录结构](16-VueCLI.md/#2-vue-cli2的目录结构)
|
||||
- [2.1 build和config](16-VueCLI.md/#21-build和config)
|
||||
- [2.2 src和static](16-VueCLI.md/#22-src和static)
|
||||
- [2.3 其他相关文件](16-VueCLI.md/#23-其他相关文件)
|
||||
- [2.3.1 .babelrc文件](16-VueCLI.md/#231-babelrc文件)
|
||||
- [2.3.2 .editorconfig文件](16-VueCLI.md/#232-editorconfig文件)
|
||||
- [2.3.3 .eslintignore文件](16-VueCLI.md/#233-eslintignore文件)
|
||||
- [2.3.4 .gitignore文件](16-VueCLI.md/#234-gitignore文件)
|
||||
- [2.3.5 .postcssrc.js文件](16-VueCLI.md/#235-postcssrcjs文件)
|
||||
- [2.3.6 index.html文件](16-VueCLI.md/#236-indexhtml文件)
|
||||
- [2.3.7 package.json和package-lock.json](16-VueCLI.md/#237-packagejson和package-lockjson)
|
||||
- [3. runtime-compiler和runtime-only区别](16-VueCLI.md/#3-runtime-compiler和runtime-only区别)
|
||||
- [4. vue-cli3](16-VueCLI.md/#4-vue-cli3)
|
||||
- [4.1 vue-cli3起步](16-VueCLI.md/#41-vue-cli3起步)
|
||||
- [4.2 vue-cli3的配置](16-VueCLI.md/#42-vue-cli3的配置)
|
||||
|
||||
# [17-Vue-Router](17-Vue-Router.md/)
|
||||
- [1. 路由简介](17-Vue-Router.md/#1-路由简介)
|
||||
- [2. 前端/后端路由](17-Vue-Router.md/#2-前端后端路由)
|
||||
- [3. URL的hash和HTML5的history](17-Vue-Router.md/#3-url的hash和html5的history)
|
||||
- [3.1 URL的hash](17-Vue-Router.md/#31-url的hash)
|
||||
- [3.2 HTML5的history模式](17-Vue-Router.md/#32-html5的history模式)
|
||||
- [4. vue-router的安装配置](17-Vue-Router.md/#4-vue-router的安装配置)
|
||||
- [5. vue-router的使用](17-Vue-Router.md/#5-vue-router的使用)
|
||||
- [5.1 创建路由组件](17-Vue-Router.md/#51-创建路由组件)
|
||||
- [5.2 配置路由映射:组件和路径映射关系](17-Vue-Router.md/#52-配置路由映射组件和路径映射关系)
|
||||
- [5.3 使用路由:通过`<router-link>`和`<router-view>`](17-Vue-Router.md/#53-使用路由通过router-link和router-view)
|
||||
- [5.4 路由的默认值和history模式](17-Vue-Router.md/#54-路由的默认值和history模式)
|
||||
- [5.5 `<router-link>`的其他属性](17-Vue-Router.md/#55-router-link的其他属性)
|
||||
- [5.6 通过代码修改路由跳转](17-Vue-Router.md/#56-通过代码修改路由跳转)
|
||||
- [6. vue-router深入](17-Vue-Router.md/#6-vue-router深入)
|
||||
- [6.1 vue-router的动态路由](17-Vue-Router.md/#61-vue-router的动态路由)
|
||||
- [6.2 vue-router的打包文件解析](17-Vue-Router.md/#62-vue-router的打包文件解析)
|
||||
- [6.3 嵌套路由](17-Vue-Router.md/#63-嵌套路由)
|
||||
- [6.4 vue-router的参数传递](17-Vue-Router.md/#64-vue-router的参数传递)
|
||||
- [6.5 router和route的由来](17-Vue-Router.md/#65-router和route的由来)
|
||||
- [7. vue-router其他](17-Vue-Router.md/#7-vue-router其他)
|
||||
- [7.1 vue-router的导航守卫](17-Vue-Router.md/#71-vue-router的导航守卫)
|
||||
- [7.2 导航守卫补充](17-Vue-Router.md/#72-导航守卫补充)
|
||||
- [7.3 完整的导航解析流程](17-Vue-Router.md/#73-完整的导航解析流程)
|
||||
- [8. keep-alive](17-Vue-Router.md/#8-keep-alive)
|
||||
|
||||
# [18-Promise](18-Promise.md)
|
||||
- [1. 什么是Promies](18-Promise.md/#1-什么是promies)
|
||||
- [2. Promise的基本使用](18-Promise.md/#2-promise的基本使用)
|
||||
- [2.1 什么时候使用Promise](18-Promise.md/#21-什么时候使用promise)
|
||||
- [2.2 Promise对象](18-Promise.md/#22-promise对象)
|
||||
- [3. Promise的三种状态](18-Promise.md/#3-promise的三种状态)
|
||||
- [4. Promies的链式调用](18-Promise.md/#4-promies的链式调用)
|
||||
- [5. Promies的all使用](18-Promise.md/#5-promies的all使用)
|
||||
|
||||
# [19-Vuex](19-Vuex.md/)
|
||||
- [1. 什么是Vuex](19-Vuex.md/#1-什么是vuex)
|
||||
- [1.1 使用场景](19-Vuex.md/#11-使用场景)
|
||||
- [1.2 数据流层](19-Vuex.md/#12-数据流层)
|
||||
- [注意事项](19-Vuex.md/#注意事项)
|
||||
- [2. 核心概念](19-Vuex.md/#2-核心概念)
|
||||
- [2.1 state](19-Vuex.md/#21-state)
|
||||
- [2.1.1 在 Vue 组件中获得 Vuex 状态](19-Vuex.md/#211-在-vue-组件中获得-vuex-状态)
|
||||
- [2.1.2 mapState 辅助函数](19-Vuex.md/#212-mapstate-辅助函数)
|
||||
- [2.2 Getter](19-Vuex.md/#22-getter)
|
||||
- [2.2.1 通过属性访问](19-Vuex.md/#221-通过属性访问)
|
||||
- [2.2.2 通过方法访问](19-Vuex.md/#222-通过方法访问)
|
||||
- [2.2.3 mapGetters 辅助函数](19-Vuex.md/#223-mapgetters-辅助函数)
|
||||
- [2.3 Mutation](#23-mutation)
|
||||
- [2.3.1 提交载荷(Payload)](19-Vuex.md/#231-提交载荷payload)
|
||||
- [2.3.2 对象风格的提交方式](19-Vuex.md/#232-对象风格的提交方式)
|
||||
- [2.3.3 Mutation 需遵守 Vue 的响应规则](19-Vuex.md/#233-mutation-需遵守-vue-的响应规则)
|
||||
- [2.3.4 使用常量替代 Mutation 事件类型](19-Vuex.md/#234-使用常量替代-mutation-事件类型)
|
||||
- [2.3.5 Mutation 必须是同步函数](19-Vuex.md/#235-mutation-必须是同步函数)
|
||||
- [2.3.6 在组件中提交 Mutation](19-Vuex.md/#236-在组件中提交-mutation)
|
||||
- [2.4 Action](19-Vuex.md/#24-action)
|
||||
- [2.4.1 分发 Action](19-Vuex.md/#241-分发-action)
|
||||
- [2.4.2 在组件中分发 Action](19-Vuex.md/#242-在组件中分发-action)
|
||||
- [2.4.3 组合 Action](19-Vuex.md/#243-组合-action)
|
||||
- [2.5 Module](19-Vuex.md/#25-module)
|
||||
- [2.5.1 模块的局部状态](19-Vuex.md/#251-模块的局部状态)
|
||||
- [2.5.2 命名空间](19-Vuex.md/#252-命名空间)
|
||||
- [3. `Vuex`项目开发中常见的文件布局](19-Vuex.md/#3-vuex项目开发中常见的文件布局)
|
||||
- [3.1 项目结构](19-Vuex.md/#31-项目结构)
|
||||
- [3.2 文件的说明](19-Vuex.md/#32-文件的说明)
|
||||
- [4. Vuex的简单案例](19-Vuex.md/#4-vuex的简单案例)
|
||||
- [4.1 目录结构](19-Vuex.md/#41-目录结构)
|
||||
- [4.2 新建store存储于vuex相关](19-Vuex.md/#42-新建store存储于vuex相关)
|
||||
- [4.2.1 state.js](19-Vuex.md/#421-statejs)
|
||||
- [4.2.2 getters.js](19-Vuex.md/#422-gettersjs)
|
||||
- [4.2.3 mutations-types.js](19-Vuex.md/#423-mutations-typesjs)
|
||||
- [4.2.4 mutations.js](19-Vuex.md/#424-mutationsjs)
|
||||
- [4.2.5 index.js](19-Vuex.md/#425-indexjs)
|
||||
- [4.3 在main.js中注册store](19-Vuex.md/#43-在mainjs中注册store)
|
||||
- [4.4 在App.vue中使用](19-Vuex.md/#44-在appvue中使用)
|
||||
- [4.5 结果](#45-结果)
|
||||
- [5. Vuex工作原理详解](19-Vuex.md/#5-vuex工作原理详解)
|
||||
- [5.1 理解computed](19-Vuex.md/#51-理解computed)
|
||||
- [vue中data属性和computed相关的源代码](19-Vuex.md/#vue中data属性和computed相关的源代码)
|
||||
- [`initData`](19-Vuex.md/#initdata)
|
||||
- [`initComputed`](19-Vuex.md/#initcomputed)
|
||||
- [`defineComputed`所代理属性的get方法](19-Vuex.md/#definecomputed所代理属性的get方法)
|
||||
- [获取依赖并更新的过程](19-Vuex.md/#获取依赖并更新的过程)
|
||||
- [5.2 vuex插件](19-Vuex.md/#52-vuex插件)
|
||||
|
||||
# [20-Axios的封装](20-Axios的封装.md)
|
||||
- [1. Axios简介](20-Axios的封装.md/#1-axios简介)
|
||||
- [1.1 什么是Axios](20-Axios的封装.md/#11-什么是axios)
|
||||
- [1.2 特性](20-Axios的封装.md/#12-特性)
|
||||
- [2. Axios的使用和配置](20-Axios的封装.md/#2-axios的使用和配置)
|
||||
- [2.1 安装](20-Axios的封装.md/#21-安装)
|
||||
- [2.2 基本使用](20-Axios的封装.md/#22-基本使用)
|
||||
- [2.2.1 Get请求](20-Axios的封装.md/#221-get请求)
|
||||
- [2.2.2 Post请求](20-Axios的封装.md/#222-post请求)
|
||||
- [2.2.3 并发操作](20-Axios的封装.md/#223-并发操作)
|
||||
- [2.3 请求API配置](20-Axios的封装.md/#23-请求api配置)
|
||||
- [2.4 请求设置](20-Axios的封装.md/#24-请求设置)
|
||||
- [2.5 响应数据Response](20-Axios的封装.md/#25-响应数据response)
|
||||
- [2.6 拦截器Interceptors](20-Axios的封装.md/#26-拦截器interceptors)
|
||||
- [3. 跨域](20-Axios的封装.md/#3-跨域)
|
||||
- [3.1 ProxyTable](20-Axios的封装.md/#31-proxytable)
|
||||
- [1. 找到 **config/index.js** 文件中的 `proxyTable:{}` 将其修改](20-Axios的封装.md/#1-找到-configindexjs-文件中的-proxytable-将其修改)
|
||||
- [2. 找到 **config/dev.env.js** 文件,配置`BASE_URL`](20-Axios的封装.md/#2-找到-configdevenvjs-文件配置base_url)
|
||||
- [3. 找到 **config/prod.env.js** 文件,配置`BASE_URL`](20-Axios的封装.md/#3-找到-configprodenvjs-文件配置base_url)
|
||||
- [4. 配置 **axios** 的基础域名](20-Axios的封装.md/#4-配置-axios-的基础域名)
|
||||
- [4. 封装](20-Axios的封装.md/#4-封装)
|
||||
- [4.1 条件准备](20-Axios的封装.md/#41-条件准备)
|
||||
- [4.2 axios封装(单域名)](20-Axios的封装.md/#42-axios封装单域名)
|
||||
|
||||
# [综合练习-实现Tab-Bar ](综合练习-实现Tab-Bar.md)
|
||||
- [1. 实现Tab-Bar思路](综合练习-实现Tab-Bar.md/#1-实现tab-bar思路)
|
||||
- [2. 代码实现](综合练习-实现Tab-Bar.md/#2-代码实现)
|
||||
- [3. 别名配置](综合练习-实现Tab-Bar.md/#3-别名配置)
|
||||
461
Vue/综合练习-实现Tab-Bar.md
Normal file
461
Vue/综合练习-实现Tab-Bar.md
Normal file
@@ -0,0 +1,461 @@
|
||||

|
||||
|
||||
# 1. 实现Tab-Bar思路
|
||||
|
||||
1. 下方单独的`Tab-Bar`组件如何封装?
|
||||
- 自定义`Tab-Bar`组件,在APP中使用
|
||||
- 让`Tab-Bar`位置在底部,并设置你需要的样式
|
||||
2. `Tab-Bar`中显示的内容由外部决定
|
||||
- 定义插槽
|
||||
- flex布局平分`Tab-Bar`
|
||||
3. 自定义`Tab-Bar-Item`,可以传入图片和文字
|
||||
- 定义`Tab-Bar-Item`,并定义两个插槽:图片和文字
|
||||
- 给插槽外层包装`div`,设置样式
|
||||
- 填充插槽,实现底部`Tab-Bar`的效果
|
||||
4. 传入高亮图片
|
||||
- 定义另一个插槽,插入`active-icon`的数据
|
||||
- 定义一个变量`isActicve`,通过`v-show`来决定是否显示对应的icon
|
||||
5. `Tab-Bar-Item`绑定路由数据
|
||||
- 安装路由:`npm install vue-router --save`
|
||||
- 在`router/index.js`配置路由信息,并创建对应的组件
|
||||
- `main.js`中注册`router`
|
||||
- `App.vue`中使用`router-link`和`router-view`
|
||||
6. 点击item跳转到对应的路由,并且动态决定`isActive`
|
||||
- 监听`item`的点击,通过`this.$router.replace()`替换路由路径
|
||||
- 通过`this.$route.path.indexOf(this.link)!==-1`来判断是否使`active`
|
||||
7. 动态计算active样式
|
||||
- 封装新的计算属性:`this.isActive?{'color': 'red'}:{}`
|
||||
|
||||
# 2. 代码实现
|
||||
|
||||
使用`vue init webpack 02-vue-router-tabbar-v1`新建一个项目工程(使用`vuecli2`)。
|
||||
|
||||
1. 在文件夹assest下新建css/base.css,用于初始化css
|
||||
|
||||
> base.css
|
||||
|
||||
|
||||
|
||||
```css
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
```
|
||||
|
||||
> 修改App.vue,添加初步样式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="tar-bar">
|
||||
<div class="tar-bar-item">首页</div>
|
||||
<div class="tar-bar-item">分类</div>
|
||||
<div class="tar-bar-item">购物车</div>
|
||||
<div class="tar-bar-item">我的</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* style中引用使用@import */
|
||||
@import url('./assets/css/base.css');
|
||||
|
||||
#tar-bar {
|
||||
display: flex;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
box-shadow: 0 -1px 1px rgba(100, 100, 100, .2);
|
||||
}
|
||||
|
||||
.tar-bar-item {
|
||||
flex: auto;
|
||||
text-align: center;
|
||||
height: 49px;
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
```
|
||||
|
||||
> 使用npm run dev,查看网页效果
|
||||
|
||||

|
||||
|
||||
> 思考:如果每次都要复用tabbar,那每次都需要复制粘贴,应该要把tabbar抽离出来,vue就是组件化思想。
|
||||
|
||||
|
||||
|
||||
2. 将tabbar抽离成组件
|
||||
|
||||
在components下新建tabbar文件夹,新建`TarBar.vue`和`TabBarItem.vue`,`TabBarItem`组件是在组件`TarBar`中抽取出来的,可以传入图片和文字(比如首页),所有需要使用插槽`<slot>`代替。
|
||||
|
||||
> TarBar.vue
|
||||
|
||||
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div id="tab-bar">
|
||||
<!-- 插槽代替tabbaritem -->
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/ecmascript-6">
|
||||
export default {
|
||||
name: 'TabBar'
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
#tab-bar {
|
||||
display: flex;
|
||||
background-color: #f6f6f6;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
box-shadow: 0 -1px 1px rgba(100, 100, 100, .2);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
TabBar弄一个slot插槽用于插入TabBarItem组件(可能插入多个).
|
||||
|
||||
|
||||
|
||||
> TabBarItem.vue
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="tab-bar-item">
|
||||
<!-- item-icon表示图片插槽 item-text表示文字插槽,例如首页 -->
|
||||
<slot name="item-icon"></slot>
|
||||
<slot name="item-text"></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/ecmascript-6">
|
||||
export default {
|
||||
name: 'TabBarItem'
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.tab-bar-item {
|
||||
flex: auto;
|
||||
text-align: center;
|
||||
height: 49px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.tab-bar-item img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-top: 3px;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
TabBarItem组件中插入2个插槽一个用于插入图片一个用于插入文字。
|
||||
|
||||
|
||||
|
||||
> MainTabBar.vue
|
||||
|
||||
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="main-tab-bar">
|
||||
<TabBar>
|
||||
<TabBarItem path="/home" activeColor="blue">
|
||||
<img slot="item-icon" src="~assets/img/tabbar/home.png" alt="" srcset="">
|
||||
<template v-slot:item-text>
|
||||
<div>首页</div>
|
||||
</template>
|
||||
</TabBarItem>
|
||||
<TabBarItem path="/categories">
|
||||
<template #item-icon>
|
||||
<img src="~assets/img/tabbar/categories.png" alt="" srcset="">
|
||||
</template>
|
||||
<template #item-text>
|
||||
<div>分类</div>
|
||||
</template>
|
||||
</TabBarItem>
|
||||
<TabBarItem path="/shop">
|
||||
<template #item-icon>
|
||||
<img src="~assets/img/tabbar/shopcart.png" alt="" srcset="">
|
||||
</template>
|
||||
<template #item-text>
|
||||
<div>购物车</div>
|
||||
</template>
|
||||
</TabBarItem>
|
||||
<TabBarItem path="/me">
|
||||
<template #item-icon>
|
||||
<img src="~assets/img/tabbar/profile.png" alt="" srcset="">
|
||||
</template>
|
||||
<template #item-text>
|
||||
<div>我的</div>
|
||||
</template>
|
||||
</TabBarItem>
|
||||
</TabBar>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/ecmascript-6">
|
||||
import TabBar from "@/components/tabbar/TabBar"
|
||||
import TabBarItem from "@/components/tabbar/TabBarItem"
|
||||
export default {
|
||||
name: "MainTabBar",
|
||||
components: {
|
||||
TabBar,
|
||||
TabBarItem
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
</style>
|
||||
|
||||
```
|
||||
|
||||
在MainTabBar组件中加入另外2个组件。
|
||||
|
||||
> 注意此处使用`~assets`和`@/components`是使用了别名配置,[详情请看3.别名配置](#3.别名配置)
|
||||
|
||||
|
||||
|
||||
最后在app.vue中导入MainTabBar组件。
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div id="app">
|
||||
<MainTabBar></MainTabBar>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MainTabBar from '@/components/MainTabBar'
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
MainTabBar
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* style中引用使用@import */
|
||||
@import url('./assets/css/base.css');
|
||||
</style>
|
||||
|
||||
```
|
||||
|
||||
效果如图所示,将组件进行了分离重组,只要修改MainTabBar组件就可以修改图片和文字描述,可以复用。
|
||||
|
||||

|
||||
|
||||
3. 如何实现点击首页首页字体变红图片变红色
|
||||
|
||||
这里需要用到路由的`active-class`。
|
||||
|
||||
> 思路:引用2张图片,一张是正常颜色一张是红色,使用`v-if`和`v-else`来处理是否变色,在路由处于活跃状态的时候,变红色。
|
||||
|
||||
引入路由使用路由就不细说了,这里仅贴上tabbar的修改代码。
|
||||
|
||||
> TabBarItem.vue组件
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="tab-bar-item" :style="activeStyle" @click="itemClick">
|
||||
<!-- item-icon表示图片插槽 item-text表示文字插槽,例如首页 -->
|
||||
<div v-if="!isActive">
|
||||
<slot name="item-icon"></slot>
|
||||
</div>
|
||||
<div v-else>
|
||||
<slot name="item-icon-active"></slot>
|
||||
</div>
|
||||
<div :class="{active:isActive}">
|
||||
<slot name="item-text"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/ecmascript-6">
|
||||
export default {
|
||||
name: 'TabBarItem',
|
||||
props:{
|
||||
path:String,
|
||||
activeColor:{
|
||||
type:String,
|
||||
default:'red'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isActive(){
|
||||
return this.$route.path.indexOf(this.path) !== -1
|
||||
},
|
||||
activeStyle(){
|
||||
return this.isActive ? {color: this.activeColor} : {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
itemClick(){
|
||||
this.$router.push(this.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tab-bar-item {
|
||||
flex: auto;
|
||||
text-align: center;
|
||||
height: 49px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tab-bar-item img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-top: 3px;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
|
||||
|
||||
1. 使用`props`获取传递的值,这里传递是激活颜色,默认是红色
|
||||
2. 设置计算属性`isActive`和`activeStyle`,分别表示激活状态和激活的样式
|
||||
3. 定义`itemClick()`方法用于获取点击事件,点击后使用代码实现路由跳转,这里使用默认的hash模式
|
||||
4. 使用`v-if`和`v-else`来进行条件判断
|
||||
|
||||
> MainTabBar.vue组件
|
||||
|
||||
```vue
|
||||
<TabBarItem path="/home">
|
||||
<img slot="item-icon" src="~assets/img/tabbar/home.png" alt="" srcset="">
|
||||
<img slot="item-icon-active" src="~assets/img/tabbar/home_active.png" alt="" srcset="">
|
||||
<template v-slot:item-text>
|
||||
<div>首页</div>
|
||||
</template>
|
||||
</TabBarItem>
|
||||
```
|
||||
|
||||
添加激活状态的图片与未激活的图片并列。
|
||||
|
||||
4. 配置路由信息,参考之前的代码
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/home'//缺省时候重定向到/home
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
component: () => import ('../views/home/Home.vue')
|
||||
},
|
||||
{
|
||||
path: '/categories',
|
||||
component: () => import ('../views/categories/Categories.vue')
|
||||
},
|
||||
{
|
||||
path: '/shop',
|
||||
component: () => import ('../views/shop/Shop.vue')
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
component: () => import ('../views/profile/Profile.vue')
|
||||
},
|
||||
]
|
||||
|
||||
export default new Router({
|
||||
routes,
|
||||
// linkActiveClass:"active"
|
||||
})
|
||||
```
|
||||
|
||||

|
||||
|
||||
5. 修改main.js和App.vue
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import App from './App'
|
||||
import router from './router'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
render: h => h(App)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
<MainTabBar></MainTabBar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MainTabBar from '@/components/MainTabBar'
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
MainTabBar
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* style中引用使用@import */
|
||||
@import url('./assets/css/base.css');
|
||||
|
||||
</style>
|
||||
|
||||
```
|
||||
|
||||
# 3. 别名配置
|
||||
|
||||
经常的我们向引入图片文件等资源的时候使用相对路径,诸如`../assets/xxx`这样的使用`../`获取上一层,如果有多个上层就需要`../../xxx`等等这样不利于维护代码。此时就需要一个能获取到指定目录的资源的就好了。
|
||||
|
||||
> 配置
|
||||
|
||||
在`webpack.base.config`中配置使用别名,找到resolve:{}模块,增加配置信息
|
||||
|
||||
```js
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'@': resolve('src'),
|
||||
'assets': resolve('src/assets'),
|
||||
'components': resolve('src/components'),
|
||||
'views': resolve('scr/views')
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
这里`@`指定目录是`src`,例如`@/components`表示`src/components`目录,`assets`表示`src/assets`前缀,如果是`assets/img`就表示`src/assets/img`目录。
|
||||
90
test.json
Normal file
90
test.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"status": "UP",
|
||||
"details": {
|
||||
"SOFABootReadinessHealthCheckInfo": {
|
||||
"status": "UP",
|
||||
"details": {
|
||||
"HealthChecker": {
|
||||
"alipaySofaRuntimeHealthChecker": {
|
||||
"status": "UP"
|
||||
},
|
||||
"sofaComponentHealthChecker": {
|
||||
"status": "UP",
|
||||
"details": {
|
||||
"reference:com.alipay.sofa.cloud.osp.instance.facade.MeterFacade:#-259276000": "[bolt,passed] [jvm,passed]",
|
||||
"extension-point:opscloudExtension$opsSyncChangeService": "passed",
|
||||
"service:com.alipay.opscloudcore.common.service.client.http.HttpHeartbeatCheck": "[jvm,passed]",
|
||||
"reference:com.alipay.sofa.cloud.osp.instance.facade.InstanceFacade:#-528282148": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.ExecutionNotifyClient": "[jvm,passed]",
|
||||
"extension-point:opscloudExtension$opsChangeService": "passed",
|
||||
"service:com.alipay.sofa.servicegovern.common.service.facade.RouterRuleFacade": "[tr,passed]",
|
||||
"reference:com.alipay.sofa.cloud.osp.user.facade.UserFacade:#1276066022": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.antcloud.dsrconsole.common.service.facade.DrmServiceFacade": "[bolt,passed]",
|
||||
"reference:com.alipay.antcloud.drmdata.facade.DrmDataQueryFacade:#1340292234": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.framework.sdk.clientframework.SyncChangeServiceShortcut": "[jvm,passed]",
|
||||
"reference:com.alipay.antscheduler.facade.IAntJobFacade:#-54943409": "[jvm,passed] [bolt,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.OpsChngTraceClient": "[jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.OpscloudApiSwitch": "[jvm,passed]",
|
||||
"service:com.alipay.antcloud.dsrconsole.core.service.opscloud.template.OpscloudFacadeTemplate": "[jvm,passed]",
|
||||
"service:com.alipay.huanyu.facade.change.ChangePlanCallback:dsrconsoleMAIN_SITE": "[tr,passed]",
|
||||
"service:com.alipay.opscloudcore.framework.core.facade.OpscloudClientSyncServiceFacade:dsrconsole": "[tr,passed] [jvm,passed]",
|
||||
"reference:com.alipay.antcloud.drmdata.facade.DrmDataClusterFacade:#-234876751": "[bolt,passed] [jvm,passed]",
|
||||
"extension-point:opscloudExtension$opsChangeTransaction": "passed",
|
||||
"service:com.alipay.opscloudcore.common.service.client.ChangeServiceCheckClient": "[jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.http.HttpOpsChngTraceFacade": "[jvm,passed]",
|
||||
"reference:com.alipay.huanyu.facade.change.ChangePlanFacade:#2078914018": "[tr,passed] [jvm,passed]",
|
||||
"reference:com.alipay.sofa.discovery.sync.enterprise.facade.api.ServiceRestFacade:#223367432": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.http.HttpChangeServiceSyncExecuteFacade": "[jvm,passed]",
|
||||
"reference:com.alipay.sofa.cloud.osp.instance.facade.OSPMetadataFacade:#1502309493": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.http.HttpChangeServiceCheckFacade": "[jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.ChangeServiceAsyncCheckClient": "[jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.ChangeServiceSyncExecuteClient": "[jvm,passed]",
|
||||
"service:com.alipay.antcloud.dsrconsole.core.service.opscloud.OpscloudStrategy": "[jvm,passed]",
|
||||
"service:com.alipay.antcloud.dsrconsole.common.service.facade.ReportServiceFacade": "[tr,passed]",
|
||||
"extension-point:opscloudClientExtension$facades": "passed",
|
||||
"reference:com.alipay.antscheduler.facade.ISwitchZoneFacade:#-1973549567": "[bolt,passed] [jvm,passed]",
|
||||
"reference:com.alipay.antscheduler.facade.IJobTriggerInstanceFacade:#973874193": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.http.HttpChangeServiceAsyncCheckFacade": "[jvm,passed]",
|
||||
"reference:com.alipay.sofa.cloud.auth.AuthenticationService:#-1387992122": "[bolt,passed] [jvm,passed]",
|
||||
"reference:com.alipay.antscheduler.facade.IJobExecuteInstanceFacade:#1941186356": "[bolt,passed] [jvm,passed]",
|
||||
"service:com.alipay.antcloud.dsrconsole.common.service.facade.DrmResourceMetaFacade": "[bolt,passed]",
|
||||
"service:com.alipay.opscloudcore.common.service.client.extension.OpscloudClientExtensionImpl": "[jvm,passed]",
|
||||
"service:com.alipay.antcloud.dsrconsole.common.service.facade.AuthFacade": "[bolt,passed]",
|
||||
"reference:com.alipay.sofa.discovery.sync.enterprise.facade.api.ClusterRestFacade:#685631288": "[bolt,passed] [jvm,passed]",
|
||||
"reference:com.alipay.sofa.cloud.osp.console.openapi.OspOpenAPIConfigFacade:#208429739": "[bolt,passed] [jvm,passed]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReadinessCheckCallback": {
|
||||
"applicationAfterReadinessCheckCallback": {
|
||||
"status": "UP"
|
||||
},
|
||||
"lazyActivateBeanProcessor": {
|
||||
"status": "UP"
|
||||
},
|
||||
"rpcAfterHealthCheckCallback": {
|
||||
"status": "UP"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"diskSpace": {
|
||||
"status": "UP",
|
||||
"details": {
|
||||
"total": 528311816192,
|
||||
"free": 457311166464,
|
||||
"threshold": 10485760,
|
||||
"exists": true
|
||||
}
|
||||
},
|
||||
"pingHealthContributor": {
|
||||
"status": "UP"
|
||||
},
|
||||
"sessionConnectionHealthChecker": {
|
||||
"status": "UP",
|
||||
"details": {
|
||||
"sessionConnection": "session connection is health"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
214
数据库/Redis命令总结/01.redis安装.md
Normal file
214
数据库/Redis命令总结/01.redis安装.md
Normal file
@@ -0,0 +1,214 @@
|
||||
- [1. 在主机上安装](#1-在主机上安装)
|
||||
- [**(1) 修改后修改配置文件**](#1-修改后修改配置文件)
|
||||
- [**(2) 设置开机启动**](#2-设置开机启动)
|
||||
- [**(3) 将redis的bin命令添加到PATH**](#3-将redis的bin命令添加到path)
|
||||
- [2. 在docker安装redis](#2-在docker安装redis)
|
||||
- [**(1) 无持久化方式**](#1-无持久化方式)
|
||||
- [**(2) 有持久化方式**](#2-有持久化方式)
|
||||
- [**(3) 自定义redis配置**](#3-自定义redis配置)
|
||||
|
||||
官网:[http://redis.io](http://redis.io/)
|
||||
|
||||
redis定义:是开源、BSD许可、高级的key-value存储系统。可以用来存储字符串、哈希结构、链表、集合,因此常用来提供数据结构服务。
|
||||
|
||||
# 1. 在主机上安装
|
||||
|
||||
| 名称 | 操作 |
|
||||
| :-------------- | :------------------------------------------- |
|
||||
| 下载redis源代码 | wget http://t.cn/Eqw5XJ3 |
|
||||
| 解压 | tar -zxvf 5.0.2.tar |
|
||||
| 进入目录 | cd redis-5.0.2 |
|
||||
| 编译 | make |
|
||||
| 安装指定目录 | make install PREFIX=/usr/local/redis install |
|
||||
| 复制配置文件 | cp redis.conf /usr/local/redis/ |
|
||||
|
||||
## **(1) 修改后修改配置文件**
|
||||
|
||||
```bash
|
||||
# 打开配置文件
|
||||
vim /usr/local/redis/redis.conf
|
||||
|
||||
# 使redis启动后在后台运行
|
||||
daemonize yes
|
||||
|
||||
# 设置密码,默认密码为空
|
||||
requirepass 123456
|
||||
|
||||
# 允许远程连接,取消绑定本机
|
||||
#bind 127.0.0.1
|
||||
```
|
||||
|
||||
|
||||
|
||||
## **(2) 设置开机启动**
|
||||
|
||||
在自启动/etc/init.d/文件夹下新建名字为redis的启动脚本,内容如下:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
|
||||
# chkconfig: 2345 90 10
|
||||
# description: Redis is a persistent key-value database
|
||||
|
||||
PATH=/usr/local/bin:/sbin:/usr/bin:/bin
|
||||
|
||||
REDISPORT=6379
|
||||
EXEC=/usr/local/redis/bin/redis-server
|
||||
REDIS_CLI=/usr/local/redis/bin/redis-cli
|
||||
|
||||
PIDFILE=/var/run/redis_6379.pid
|
||||
CONF="/usr/local/redis/redis.conf"
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ -f $PIDFILE ]
|
||||
then
|
||||
echo "$PIDFILE exists, process is already running or crashed"
|
||||
else
|
||||
echo "Starting Redis server..."
|
||||
$EXEC $CONF
|
||||
fi
|
||||
if [ "$?"="0" ]
|
||||
then
|
||||
echo "Redis is running..."
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
if [ ! -f $PIDFILE ]
|
||||
then
|
||||
echo "$PIDFILE does not exist, process is not running"
|
||||
else
|
||||
PID=$(cat $PIDFILE)
|
||||
echo "Stopping ..."
|
||||
$REDIS_CLI -p $REDISPORT SHUTDOWN
|
||||
while [ -x ${PIDFILE} ]
|
||||
do
|
||||
echo "Waiting for Redis to shutdown ..."
|
||||
sleep 1
|
||||
done
|
||||
echo "Redis stopped"
|
||||
fi
|
||||
;;
|
||||
restart|force-reload)
|
||||
${0} stop
|
||||
${0} start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit 0
|
||||
```
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
# 设置脚本文件的可执行权限
|
||||
chmod +x /etc/init.d/redis
|
||||
|
||||
# 添加服务到service,开机启动
|
||||
chkconfig --add /etc/init.d/redis
|
||||
|
||||
#启动服务
|
||||
service redis start
|
||||
|
||||
# 停止服务
|
||||
service redis stop
|
||||
```
|
||||
|
||||
|
||||
|
||||
## **(3) 将redis的bin命令添加到PATH**
|
||||
|
||||
```bash
|
||||
# 打开profile文件
|
||||
vim /etc/profile
|
||||
# 在文件末尾添加内容如下:
|
||||
export PATH=$PATH:/usr/local/redis/bin
|
||||
|
||||
# 使profile生效
|
||||
source /etc/profile
|
||||
|
||||
# 停止无密码redis服务
|
||||
redis-cli shutdown
|
||||
# 停止有密码redis服务
|
||||
redis-cli -a 123456 shutdown
|
||||
# 启动客户端
|
||||
redis-cli
|
||||
# 授权
|
||||
auth 123456
|
||||
```
|
||||
|
||||
# 2. 在docker安装redis
|
||||
|
||||
## **(1) 无持久化方式**
|
||||
|
||||
操作的数据只在内存中,容器关闭了,数据会消失。
|
||||
|
||||
docker-compose.yml配置内容如下:
|
||||
|
||||
```dockerfile
|
||||
version: "3"
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
restart: always
|
||||
container_name: "redis-app"
|
||||
command: redis-server --requirepass 123456
|
||||
ports:
|
||||
- 6379:6379
|
||||
```
|
||||
|
||||
其中参数–requirepass表示客户端连接redis服务端时需要密码。
|
||||
|
||||
|
||||
|
||||
## **(2) 有持久化方式**
|
||||
|
||||
AOF模式持久化,每秒钟强制写入磁盘一次。
|
||||
|
||||
docker-compose.yml配置内容如下:
|
||||
|
||||
```dockerfile
|
||||
version: "3"
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
restart: always
|
||||
container_name: "redis-app"
|
||||
command: redis-server --requirepass 123456 --appendonly yes --appendfsync everysec
|
||||
ports:
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- /data/redis:/data
|
||||
```
|
||||
|
||||
其中–requirepass 表示客户端连接redis服务端时需要密码; –appendonly表示使用AOF模式持久化, –appendfsync表示多长时间把数据写入硬盘
|
||||
|
||||
|
||||
|
||||
## **(3) 自定义redis配置**
|
||||
|
||||
docker-compose.yml配置内容如下:
|
||||
|
||||
```dockerfile
|
||||
version: "3"
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
restart: always
|
||||
container_name: "redis-app"
|
||||
command: redis-server /usr/local/etc/redis/redis.conf
|
||||
ports:
|
||||
- 6379:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
- /data/redis:/data
|
||||
```
|
||||
|
||||
自定义配置文件,为了支持远程连接,在默认的配置修改了以下信息:
|
||||
|
||||
- bind:默认绑定本机,已取消
|
||||
- protected-mode:默认开启,已取消
|
||||
- requirepass:默认密码为空,已开启和设置密码
|
||||
236
数据库/Redis命令总结/02.库和key操作命令.md
Normal file
236
数据库/Redis命令总结/02.库和key操作命令.md
Normal file
@@ -0,0 +1,236 @@
|
||||
- [key操作命令](#key操作命令)
|
||||
- [set 设置key的值](#set-设置key的值)
|
||||
- [get 获取key的值](#get-获取key的值)
|
||||
- [del 删除key](#del-删除key)
|
||||
- [exists 判断key是否存在](#exists-判断key是否存在)
|
||||
- [type 获取key类型](#type-获取key类型)
|
||||
- [expire 设置key有效期](#expire-设置key有效期)
|
||||
- [tll 查看key有效期](#tll-查看key有效期)
|
||||
- [rename 重命名key](#rename-重命名key)
|
||||
- [renamenx 重命名不存在的key](#renamenx-重命名不存在的key)
|
||||
- [persist 设置key永久有效](#persist-设置key永久有效)
|
||||
- [move 把key移动到其他库](#move-把key移动到其他库)
|
||||
- [库操作命令](#库操作命令)
|
||||
- [dbsize 查看当前有多少个key](#dbsize-查看当前有多少个key)
|
||||
- [select 选择库](#select-选择库)
|
||||
- [flushdb 删除选中数据库中的key](#flushdb-删除选中数据库中的key)
|
||||
- [flushall 删除所有库的key](#flushall-删除所有库的key)
|
||||
|
||||
# key操作命令
|
||||
|
||||
## set 设置key的值
|
||||
|
||||
```bash
|
||||
set key value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set name zhangsan
|
||||
OK
|
||||
127.0.0.1:6379> set age 25
|
||||
OK
|
||||
```
|
||||
|
||||
## get 获取key的值
|
||||
|
||||
```bash
|
||||
get key
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> get name
|
||||
"zhangsan"
|
||||
```
|
||||
|
||||
## del 删除key
|
||||
|
||||
```bash
|
||||
del key
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> del name
|
||||
(integer) 1
|
||||
```
|
||||
|
||||
## exists 判断key是否存在
|
||||
|
||||
```bash
|
||||
exists key
|
||||
# 判断key是否存在,存在返回1,不存在返回0
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> exists name
|
||||
(integer) 1
|
||||
127.0.0.1:6379> exists title
|
||||
(integer) 0
|
||||
```
|
||||
|
||||
## type 获取key类型
|
||||
|
||||
```bash
|
||||
type key
|
||||
# 获取key存储的值的类型
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> type name
|
||||
string
|
||||
127.0.0.1:6379> type age
|
||||
string
|
||||
```
|
||||
|
||||
## expire 设置key有效期
|
||||
|
||||
```bash
|
||||
expire key
|
||||
# 设置key的生命周期
|
||||
# pexpire key 表示以毫秒为单位设置声明周期
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379[1]> expire login 60
|
||||
(integer) 1
|
||||
127.0.0.1:6379[1]> ttl login
|
||||
(integer) 47
|
||||
```
|
||||
|
||||
## tll 查看key有效期
|
||||
|
||||
```bash
|
||||
ttl key
|
||||
# 查询key的生命周期
|
||||
# 大于0 :生命周期单位为秒,
|
||||
# 等于-1:永久有效
|
||||
# 等于-2:该key不存在
|
||||
# pttl key表示毫秒为单位
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> ttl name
|
||||
(integer) -1
|
||||
127.0.0.1:6379> ttl title
|
||||
(integer) -2
|
||||
```
|
||||
|
||||
## rename 重命名key
|
||||
|
||||
```bash
|
||||
rename key newkey
|
||||
# 重命名key,如果newkey已经存在,修改后则替换新key的值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set title "redis test"
|
||||
OK
|
||||
127.0.0.1:6379> exists title
|
||||
(integer) 1
|
||||
127.0.0.1:6379> rename title biaoti
|
||||
OK
|
||||
127.0.0.1:6379> get biaoti
|
||||
"redis test"
|
||||
```
|
||||
|
||||
## renamenx 重命名不存在的key
|
||||
|
||||
```bash
|
||||
renamenx key newkey
|
||||
# 重命名key,如果newkey已经存在则不修改。
|
||||
# nx表示not exists
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> keys *
|
||||
1) "biaoti"
|
||||
2) "age"
|
||||
3) "name"
|
||||
127.0.0.1:6379> renamenx biaoti name
|
||||
(integer) 0
|
||||
```
|
||||
|
||||
## persist 设置key永久有效
|
||||
|
||||
```bash
|
||||
persist key
|
||||
# 设置key永久有效
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set login on
|
||||
OK
|
||||
127.0.0.1:6379> expire login 60
|
||||
(integer) 1
|
||||
127.0.0.1:6379> ttl login
|
||||
(integer) 55
|
||||
127.0.0.1:6379> persist login
|
||||
(integer) 1
|
||||
127.0.0.1:6379> ttl login
|
||||
(integer) -1
|
||||
```
|
||||
|
||||
## move 把key移动到其他库
|
||||
|
||||
```bash
|
||||
move key db
|
||||
# 把key移动到另一个数据库,db为整数
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> keys *
|
||||
1) "biaoti"
|
||||
2) "age"
|
||||
3) "name"
|
||||
127.0.0.1:6379> move biaoti 1
|
||||
(integer) 1
|
||||
127.0.0.1:6379> select 1
|
||||
OK
|
||||
127.0.0.1:6379[1]> keys *
|
||||
1) "biaoti"
|
||||
```
|
||||
|
||||
# 库操作命令
|
||||
|
||||
## dbsize 查看当前有多少个key
|
||||
|
||||
```bash
|
||||
dbsize
|
||||
# 查看当前有多少个key
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> dbsize
|
||||
12
|
||||
```
|
||||
|
||||
## select 选择库
|
||||
|
||||
```bash
|
||||
select db
|
||||
# 选择使用哪个数据库,db为整数
|
||||
# 默认有16个数据库0~15,如果想修改数据库数量,修改redis.conf配置文件的databases值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> select 1
|
||||
OK
|
||||
127.0.0.1:6379[2]> select 15
|
||||
OK
|
||||
```
|
||||
|
||||
## flushdb 删除选中数据库中的key
|
||||
|
||||
```bash
|
||||
flushdb
|
||||
# 删除当前选择数据库中的所有key
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379[1]> keys *
|
||||
1) "biaoti"
|
||||
127.0.0.1:6379[1]> flushdb
|
||||
OK
|
||||
127.0.0.1:6379[1]> keys *
|
||||
(empty list or set)
|
||||
```
|
||||
|
||||
## flushall 删除所有库的key
|
||||
|
||||
```bash
|
||||
flushall
|
||||
# 删除所有数据库中的key
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379[1]> flushall
|
||||
OK
|
||||
127.0.0.1:6379[1]> select 0
|
||||
OK
|
||||
127.0.0.1:6379> keys *
|
||||
(empty list or set)
|
||||
```
|
||||
220
数据库/Redis命令总结/03.字符串类型操作.md
Normal file
220
数据库/Redis命令总结/03.字符串类型操作.md
Normal file
@@ -0,0 +1,220 @@
|
||||
- [set 设置kv、效期、判断key是否存在](#set-设置kv效期判断key是否存在)
|
||||
- [mset 一次性输入多个kv](#mset-一次性输入多个kv)
|
||||
- [setrange 修改偏移字节值为valuev](#setrange-修改偏移字节值为valuev)
|
||||
- [append 在key的值后面追加字符串](#append-在key的值后面追加字符串)
|
||||
- [getrange 获取key值的部分内容](#getrange-获取key值的部分内容)
|
||||
- [getset 设置新值返回旧值](#getset-设置新值返回旧值)
|
||||
- [incr/decr 指定key的值加/减1](#incrdecr-指定key的值加减1)
|
||||
- [incrby/decrby 指定key的值加/减number](#incrbydecrby-指定key的值加减number)
|
||||
- [incrbyfloat 指定key的值加浮点数](#incrbyfloat-指定key的值加浮点数)
|
||||
- [setbit 设置二进制位上的值](#setbit-设置二进制位上的值)
|
||||
- [getbit 获取二进制位上的值](#getbit-获取二进制位上的值)
|
||||
- [bitop 对多个key逻辑操作](#bitop-对多个key逻辑操作)
|
||||
|
||||
# set 设置kv、效期、判断key是否存在
|
||||
|
||||
```bash
|
||||
set key value [ex 秒数]|[px 毫秒数] [nx]|[xx]
|
||||
# 设置kv时也可以设置有效期和判断key是否存在
|
||||
# ex和px不要同时写,否则以后面有效期为准
|
||||
# nx表示key不存在时执行操作
|
||||
# xx表示key存在时执行操作
|
||||
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set name zhangsan
|
||||
OK
|
||||
127.0.0.1:6379> set name zhangsan ex 100
|
||||
OK
|
||||
127.0.0.1:6379> ttl name
|
||||
(integer) 78
|
||||
127.0.0.1:6379> set name lisi nx
|
||||
(nil)
|
||||
127.0.0.1:6379> get name
|
||||
"zhangsan"
|
||||
```
|
||||
|
||||
# mset 一次性输入多个kv
|
||||
|
||||
```bash
|
||||
mset key1 value1 key2 value2......
|
||||
# 一次性输入多个key-value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> mset x 1 y 2 z 3
|
||||
OK
|
||||
127.0.0.1:6379> keys *
|
||||
1) "y"
|
||||
2) "z"
|
||||
3) "x"
|
||||
```
|
||||
|
||||
# setrange 修改偏移字节值为valuev
|
||||
|
||||
```bash
|
||||
setrange key offset value
|
||||
# 把字符串的偏移字节改为value
|
||||
# 如果偏移量大于字符长度,中间字符自动补0x00
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set name zhangsan
|
||||
OK
|
||||
127.0.0.1:6379> setrange name 5 ***
|
||||
(integer) 8
|
||||
127.0.0.1:6379> get name
|
||||
"zhang***"
|
||||
```
|
||||
|
||||
# append 在key的值后面追加字符串
|
||||
|
||||
```bash
|
||||
append key value
|
||||
# 在key的值后面追加value字符串
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set name zhangsan
|
||||
OK
|
||||
127.0.0.1:6379> append name "@126.com"
|
||||
(integer) 16
|
||||
127.0.0.1:6379> get name
|
||||
"zhangsan@126.com"
|
||||
```
|
||||
|
||||
# getrange 获取key值的部分内容
|
||||
|
||||
```bash
|
||||
getrange key start stop
|
||||
# 获取key值的一部分内容
|
||||
# start表示起始位置
|
||||
# stop表示结束位置,可以为为负数,表示从最后数起
|
||||
# start>length 空字符串
|
||||
# stop>length 截取到结尾
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set title "hello world"
|
||||
OK
|
||||
127.0.0.1:6379> getrange title 6 11
|
||||
"world"
|
||||
127.0.0.1:6379> getrange title 0 -7
|
||||
"hello"
|
||||
```
|
||||
|
||||
# getset 设置新值返回旧值
|
||||
|
||||
```bash
|
||||
getset key newvalue
|
||||
# 设置新值,并返回旧值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set login on
|
||||
OK
|
||||
127.0.0.1:6379> get login
|
||||
"on"
|
||||
127.0.0.1:6379> getset login off
|
||||
"on"
|
||||
127.0.0.1:6379> get login
|
||||
"off"
|
||||
```
|
||||
|
||||
# incr/decr 指定key的值加/减1
|
||||
|
||||
```bash
|
||||
incr/decr key
|
||||
# 指定key的值加/减1,返回结果
|
||||
# key不存在时,自动创建并加减1
|
||||
# key的值为字符串时无效
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set num 100
|
||||
OK
|
||||
127.0.0.1:6379> incr num
|
||||
(integer) 101
|
||||
127.0.0.1:6379> decr num
|
||||
(integer) 100
|
||||
```
|
||||
|
||||
# incrby/decrby 指定key的值加/减number
|
||||
|
||||
```bash
|
||||
incrby/decrby key number
|
||||
# 指定key的值加减number大小
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set num 100
|
||||
OK
|
||||
127.0.0.1:6379> incrby num 50
|
||||
(integer) 150
|
||||
127.0.0.1:6379> decrby num 100
|
||||
(integer) 50
|
||||
```
|
||||
|
||||
# incrbyfloat 指定key的值加浮点数
|
||||
|
||||
```bash
|
||||
incrbyfloat key floatnumber
|
||||
# 指定key的值加浮点数
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set num 10
|
||||
OK
|
||||
127.0.0.1:6379> incrbyfloat num 0.5
|
||||
"10.5"
|
||||
127.0.0.1:6379> incrbyfloat num -1.5
|
||||
"9"
|
||||
```
|
||||
|
||||
# setbit 设置二进制位上的值
|
||||
|
||||
```bash
|
||||
setbit key offset value
|
||||
# 设置offset对应二进制位上的值
|
||||
# 返回改位的旧值
|
||||
# 如果offset过大则会在中间填充0
|
||||
# offset最大为2^32-1,即512M
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set letter A
|
||||
OK
|
||||
127.0.0.1:6379> setbit letter 2 1
|
||||
(integer) 0
|
||||
127.0.0.1:6379> get letter
|
||||
"a"
|
||||
# 把0100 0001(65)改为0110 0001(97)即把大写A改为了小写a
|
||||
```
|
||||
|
||||
# getbit 获取二进制位上的值
|
||||
|
||||
```bash
|
||||
getbit key offset
|
||||
# 获取二进制offset对应位的值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> set letter A
|
||||
OK
|
||||
127.0.0.1:6379> getbit letter 0
|
||||
(integer) 0
|
||||
127.0.0.1:6379> getbit letter 1
|
||||
(integer) 1
|
||||
127.0.0.1:6379> getbit letter 7
|
||||
(integer) 1
|
||||
```
|
||||
|
||||
# bitop 对多个key逻辑操作
|
||||
|
||||
```bash
|
||||
bitop operation destkey key1 [key2 ......]
|
||||
# 对key1 key2 keyN做operation,并把结果保存到destkey 上
|
||||
# operation有AND、OR、NOT、XOR
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> setbit lower 2 1
|
||||
(integer) 0
|
||||
127.0.0.1:6379> setbit upper 2 0
|
||||
(integer) 0
|
||||
127.0.0.1:6379> set letter A
|
||||
OK
|
||||
127.0.0.1:6379> bitop or letter letter lower
|
||||
(integer) 1
|
||||
127.0.0.1:6379> get letter
|
||||
"a"
|
||||
```
|
||||
180
数据库/Redis命令总结/04.链表类型操作.md
Normal file
180
数据库/Redis命令总结/04.链表类型操作.md
Normal file
@@ -0,0 +1,180 @@
|
||||
- [lpush/rpush 在链表头/尾增加一个成员](#lpushrpush-在链表头尾增加一个成员)
|
||||
- [lrange 获取链表成员](#lrange-获取链表成员)
|
||||
- [lpop/rpop 弹出链表中头/尾的成员](#lpoprpop-弹出链表中头尾的成员)
|
||||
- [lrem 删除链表成员](#lrem-删除链表成员)
|
||||
- [lindex 获取链表索引对应的值](#lindex-获取链表索引对应的值)
|
||||
- [llen key 获取链表成员个数](#llen-key-获取链表成员个数)
|
||||
- [linsert 在链表中指定位置插入成员](#linsert-在链表中指定位置插入成员)
|
||||
- [blpop/brpop 一直等待弹出头/尾成员](#blpopbrpop-一直等待弹出头尾成员)
|
||||
|
||||
# lpush/rpush 在链表头/尾增加一个成员
|
||||
|
||||
```bash
|
||||
lpush/rpush key value
|
||||
# 在链表头/尾增加一个成员,返回链表成员的个数
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> lpush letters A
|
||||
(integer) 1
|
||||
127.0.0.1:6379> rpush letters B
|
||||
(integer) 2
|
||||
127.0.0.1:6379> rpush letters C
|
||||
(integer) 3
|
||||
127.0.0.1:6379> rpush letters D
|
||||
(integer) 4
|
||||
```
|
||||
|
||||
# lrange 获取链表成员
|
||||
|
||||
```bash
|
||||
lrange key start stop
|
||||
# 返回链表中[start,stop]范围的成员
|
||||
# 规律: 左数从0开始,右数从-1开始
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> lrange letters 0 -1
|
||||
1) "A"
|
||||
2) "B"
|
||||
3) "C"
|
||||
4) "D"
|
||||
127.0.0.1:6379> lrange letters 1 2
|
||||
1) "B"
|
||||
2) "C"
|
||||
```
|
||||
|
||||
# lpop/rpop 弹出链表中头/尾的成员
|
||||
|
||||
```bash
|
||||
lpop/rpop key
|
||||
# 弹出链表中头/尾的成员
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> lrange letters 0 -1
|
||||
1) "A"
|
||||
2) "B"
|
||||
3) "C"
|
||||
4) "D"
|
||||
127.0.0.1:6379> lpop letters
|
||||
"A"
|
||||
127.0.0.1:6379> rpop letters
|
||||
"D"
|
||||
127.0.0.1:6379> lrange letters 0 -1
|
||||
1) "B"
|
||||
2) "C"
|
||||
```
|
||||
|
||||
# lrem 删除链表成员
|
||||
|
||||
```bash
|
||||
lrem key count value
|
||||
# 从key链表中删除 value值
|
||||
# 删除count的绝对值个value后结束
|
||||
# count>0 从表头删除
|
||||
# count<0 从表尾删除
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> rpush letters A B C D A B C D A B C D
|
||||
(integer) 12
|
||||
127.0.0.1:6379> lrem letters 2 A
|
||||
(integer) 2
|
||||
127.0.0.1:6379> lrange letters 0 -1
|
||||
1) "B"
|
||||
2) "C"
|
||||
3) "D"
|
||||
4) "B"
|
||||
5) "C"
|
||||
6) "D"
|
||||
7) "A"
|
||||
8) "B"
|
||||
9) "C"
|
||||
10) "D"
|
||||
127.0.0.1:6379> lrem letters -3 D
|
||||
(integer) 3
|
||||
127.0.0.1:6379> lrange letters 0 -1
|
||||
1) "B"
|
||||
2) "C"
|
||||
3) "B"
|
||||
4) "C"
|
||||
5) "A"
|
||||
6) "B"
|
||||
7) "C"
|
||||
```
|
||||
|
||||
# lindex 获取链表索引对应的值
|
||||
|
||||
```bash
|
||||
lindex key index
|
||||
# 获取链表索引index对应的值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> rpush letters A B C D
|
||||
(integer) 4
|
||||
127.0.0.1:6379> lindex letters 1
|
||||
"B"
|
||||
127.0.0.1:6379> lindex letters 2
|
||||
"C"
|
||||
```
|
||||
|
||||
# llen key 获取链表成员个数
|
||||
|
||||
```bash
|
||||
BASHllen key
|
||||
# 获取链表成员个数
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> rpush letters A B C D
|
||||
(integer) 4
|
||||
127.0.0.1:6379> llen letters
|
||||
(integer) 4
|
||||
```
|
||||
|
||||
# linsert 在链表中指定位置插入成员
|
||||
|
||||
```bash
|
||||
linsert key after|before search value
|
||||
# 在key链表中寻找"search",并在search值之前|之后插入value
|
||||
# 如果没有找到,不插入值
|
||||
# 如果找到一个search后,命令就结束了,因此不会插入多个value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> rpush id 1 3 5 7
|
||||
(integer) 4
|
||||
127.0.0.1:6379> linsert id before 3 2
|
||||
(integer) 5
|
||||
127.0.0.1:6379> lrange id 0 -1
|
||||
1) "1"
|
||||
2) "2"
|
||||
3) "3"
|
||||
4) "5"
|
||||
5) "7"
|
||||
127.0.0.1:6379> linsert id after 5 6
|
||||
(integer) 6
|
||||
127.0.0.1:6379> lrange id 0 -1
|
||||
1) "1"
|
||||
2) "2"
|
||||
3) "3"
|
||||
4) "5"
|
||||
5) "6"
|
||||
6) "7"
|
||||
```
|
||||
|
||||
# blpop/brpop 一直等待弹出头/尾成员
|
||||
|
||||
```bash
|
||||
blpop/brpop key timeout
|
||||
# 等待弹出key的头/尾成员
|
||||
# Timeout为等待超时时间
|
||||
# 如果timeout为0,则一直等待
|
||||
# 应用s场景: 长轮询Ajax,在线聊天时,能够用到
|
||||
|
||||
# 示例
|
||||
# 第一个终端操作:
|
||||
127.0.0.1:6379> brpop chat 0
|
||||
1) "chat"
|
||||
2) "hello"
|
||||
(40.97s)
|
||||
|
||||
# 第二个终端操作:
|
||||
127.0.0.1:6379> rpush chat "hello"
|
||||
(integer) 1
|
||||
```
|
||||
210
数据库/Redis命令总结/05.无序集合操作.md
Normal file
210
数据库/Redis命令总结/05.无序集合操作.md
Normal file
@@ -0,0 +1,210 @@
|
||||
- [sadd 往集合添加成员](#sadd-往集合添加成员)
|
||||
- [srem 删除集合成员](#srem-删除集合成员)
|
||||
- [spop 随机删除集合一个成员](#spop-随机删除集合一个成员)
|
||||
- [srandmember 随机获取集合成员](#srandmember-随机获取集合成员)
|
||||
- [smembers 获取集合所有的成员](#smembers-获取集合所有的成员)
|
||||
- [sismember 判断成员是否存在集合中](#sismember-判断成员是否存在集合中)
|
||||
- [scard 获取集合成员的个数](#scard-获取集合成员的个数)
|
||||
- [smove 把一个集合中成员移动到另一个集合](#smove-把一个集合中成员移动到另一个集合)
|
||||
- [sunion 获取多个集合的并集](#sunion-获取多个集合的并集)
|
||||
- [sdiff 获取多个集合的差集](#sdiff-获取多个集合的差集)
|
||||
- [sinterstore 获取多个集合的交集并储存](#sinterstore-获取多个集合的交集并储存)
|
||||
|
||||
集合特性:无序性、唯一性、确定性
|
||||
|
||||
# sadd 往集合添加成员
|
||||
|
||||
```bash
|
||||
sadd key value1 value2 ...
|
||||
# 往集合key中增加成员
|
||||
# 增加相同成员时只会添加一个(唯一性)
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd names zhangsan lisi
|
||||
(integer) 2
|
||||
127.0.0.1:6379> sadd names wangwu wangwu
|
||||
(integer) 1
|
||||
```
|
||||
|
||||
# srem 删除集合成员
|
||||
|
||||
```bash
|
||||
srem key value1 value2 ...
|
||||
# 删除集合中为value1 value2...成员
|
||||
# 返回真正删除掉的成员个数(不包括不存在的成员)
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd names zhangsan lisi wangwu
|
||||
(integer) 3
|
||||
127.0.0.1:6379> srem names zhangsan lisi
|
||||
(integer) 2
|
||||
127.0.0.1:6379> smembers names
|
||||
1) "wangwu"
|
||||
```
|
||||
|
||||
# spop 随机删除集合一个成员
|
||||
|
||||
```bash
|
||||
spop key
|
||||
# 随机删除集合key中的一个成员
|
||||
# 应用场景:抽奖,抽中的人已经排除,不可能会被再次抽中了
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd letters A B C D E F
|
||||
(integer) 6
|
||||
127.0.0.1:6379> spop letters
|
||||
"A"
|
||||
127.0.0.1:6379> spop letters
|
||||
"F"
|
||||
127.0.0.1:6379> spop letters
|
||||
"B"
|
||||
127.0.0.1:6379> spop letters
|
||||
"D"
|
||||
```
|
||||
|
||||
# srandmember 随机获取集合成员
|
||||
|
||||
```bash
|
||||
srandmember key [count]
|
||||
# 随机获取集合key的count个成员,默认count是1
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> srandmember letters
|
||||
"C"
|
||||
127.0.0.1:6379> srandmember letters 2
|
||||
1) "E"
|
||||
2) "B"
|
||||
127.0.0.1:6379> srandmember letters 3
|
||||
1) "D"
|
||||
2) "C"
|
||||
3) "E"
|
||||
```
|
||||
|
||||
# smembers 获取集合所有的成员
|
||||
|
||||
```bash
|
||||
smembers key
|
||||
# 返回集合所有的成员
|
||||
# 返回值的顺序不一定是添加成员的顺序(无序性)
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd names zhangsan lisi wangwu
|
||||
(integer) 3
|
||||
127.0.0.1:6379> smembers names
|
||||
1) "lisi"
|
||||
2) "wangwu"
|
||||
3) "zhangsan"
|
||||
```
|
||||
|
||||
# sismember 判断成员是否存在集合中
|
||||
|
||||
```bash
|
||||
sismember key value
|
||||
# 判断value是否存在集合key中,存在返回1,不存在返回0
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd names zhangsan lisi wangwu
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sismember names lisi
|
||||
(integer) 1
|
||||
127.0.0.1:6379> sismember names zhaoliu
|
||||
(integer) 0
|
||||
```
|
||||
|
||||
# scard 获取集合成员的个数
|
||||
|
||||
```bash
|
||||
scard key
|
||||
# 获取集合成员的个数
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd letters A B C D
|
||||
(integer) 4
|
||||
127.0.0.1:6379> sadd letters E F
|
||||
(integer) 2
|
||||
127.0.0.1:6379> scard letters
|
||||
(integer) 6
|
||||
```
|
||||
|
||||
# smove 把一个集合中成员移动到另一个集合
|
||||
|
||||
```bash
|
||||
smove <source> <dest> value
|
||||
# 把集合source中的value删除,并添加到集合dest中
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd letters A B C
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd num 1 2 3
|
||||
(integer) 3
|
||||
127.0.0.1:6379> smove letters num A
|
||||
(integer) 1
|
||||
127.0.0.1:6379> smembers letters
|
||||
1) "C"
|
||||
2) "B"
|
||||
127.0.0.1:6379> smembers num
|
||||
1) "3"
|
||||
2) "1"
|
||||
3) "A"
|
||||
4) "2"
|
||||
```
|
||||
|
||||
# sunion 获取多个集合的并集
|
||||
|
||||
```bash
|
||||
sunion key1 key2 ...
|
||||
# 获取多个集合的并集
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd zhangsan A E G
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd lisi B E F
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd wangwu C D E
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sunion zhangsan lisi wangwu
|
||||
1) "B"
|
||||
2) "G"
|
||||
3) "D"
|
||||
4) "C"
|
||||
5) "E"
|
||||
6) "F"
|
||||
7) "A"
|
||||
```
|
||||
|
||||
# sdiff 获取多个集合的差集
|
||||
|
||||
```bash
|
||||
sdiff key1 key2 ...
|
||||
# 获取key1与key2...的差集
|
||||
# 即key1-key2...(key1有其他集合没有的成员)
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd zhangsan A B C
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd lisi B D E
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd wangwu C E F
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sdiff zhangsan lisi wangwu
|
||||
1) "A"
|
||||
```
|
||||
|
||||
# sinterstore 获取多个集合的交集并储存
|
||||
|
||||
```bash
|
||||
sinterstore dest key1 key2 ...
|
||||
# 求出key1 key2 ...集合中的交集,并赋给dest
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> sadd zhangsan A C D
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd lisi B D E
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sadd wangwu D E G
|
||||
(integer) 3
|
||||
127.0.0.1:6379> sinterstore class zhangsan lisi wangwu
|
||||
(integer) 1
|
||||
127.0.0.1:6379> smembers class
|
||||
1) "D"
|
||||
```
|
||||
224
数据库/Redis命令总结/06.有序集合操作.md
Normal file
224
数据库/Redis命令总结/06.有序集合操作.md
Normal file
@@ -0,0 +1,224 @@
|
||||
- [1. zadd 往有序集合添加成员](#1-zadd-往有序集合添加成员)
|
||||
- [2. zrange 按名次取成员](#2-zrange-按名次取成员)
|
||||
- [3. zrangebyscore 按分数取成员](#3-zrangebyscore-按分数取成员)
|
||||
- [4. zscore 获取指定成员的分数](#4-zscore-获取指定成员的分数)
|
||||
- [5. zcount 计算分数区间成员个数](#5-zcount-计算分数区间成员个数)
|
||||
- [6. zrank/zrevrank 获取成员升序/降序的排名](#6-zrankzrevrank-获取成员升序降序的排名)
|
||||
- [7. zrem 删除有序集合成员](#7-zrem-删除有序集合成员)
|
||||
- [8. zremrangebyrank 按排名删除成员](#8-zremrangebyrank-按排名删除成员)
|
||||
- [9. zremrangebyscore 按分数删除成员](#9-zremrangebyscore-按分数删除成员)
|
||||
- [10. zinterstore 求交集再计算](#10-zinterstore-求交集再计算)
|
||||
- [11. zunionstore 求并集再计算](#11-zunionstore-求并集再计算)
|
||||
|
||||
# 1. zadd 往有序集合添加成员
|
||||
|
||||
```bash
|
||||
zadd key score1 key2 score2 key2 ...
|
||||
# 往有序集合key添加成员
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd ages 28 zhangsan 24 lisi 26 wangwu
|
||||
(integer) 0
|
||||
127.0.0.1:6379> zrange ages 0 -1
|
||||
1) "lisi"
|
||||
2) "wangwu"
|
||||
3) "zhangsan"
|
||||
```
|
||||
|
||||
# 2. zrange 按名次取成员
|
||||
|
||||
```bash
|
||||
zrange key start stop [WITHSCORES]
|
||||
# 把集合排序后,返回名次[start,stop]的成员按名次取成员
|
||||
# 默认是升续排列,withscores 是把score也打印出来
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zrange ages 0 -1 withscores
|
||||
1) "lisi"
|
||||
2) "24"
|
||||
3) "wangwu"
|
||||
4) "26"
|
||||
5) "zhangsan"
|
||||
6) "28"
|
||||
```
|
||||
|
||||
# 3. zrangebyscore 按分数取成员
|
||||
|
||||
```bash
|
||||
zrangebyscore key min max [withscores] limit offset N
|
||||
# 集合(升序)排序后,取score在[min,max]内的成员,并跳过offset个,取出N个,按分数取成员
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd ages 28 zhangsan 24 lisi 26 wangwu
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zrangebyscore ages 25 30
|
||||
1) "wangwu"
|
||||
2) "zhangsan"
|
||||
127.0.0.1:6379> zrangebyscore ages 25 30 limit 1 1
|
||||
1) "zhangsan"
|
||||
```
|
||||
|
||||
# 4. zscore 获取指定成员的分数
|
||||
|
||||
```bash
|
||||
ZSCORE key member
|
||||
# 获取指定成员的分数
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zscore height lisi
|
||||
"167"
|
||||
```
|
||||
|
||||
# 5. zcount 计算分数区间成员个数
|
||||
|
||||
```bash
|
||||
zcount key min max
|
||||
# 计算[min,max]区间内成员的数量
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zcount height 170 180
|
||||
(integer) 1
|
||||
```
|
||||
|
||||
# 6. zrank/zrevrank 获取成员升序/降序的排名
|
||||
|
||||
```bash
|
||||
zrank/zrevrank key member
|
||||
# 查询member的升序/降序排名,名次从0开始
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd ages 28 zhangsan 24 lisi 26 wangwu
|
||||
(integer) 0
|
||||
127.0.0.1:6379> zrange ages 0 -1
|
||||
1) "lisi"
|
||||
2) "wangwu"
|
||||
3) "zhangsan"
|
||||
127.0.0.1:6379> zrank ages zhangsan
|
||||
(integer) 2
|
||||
127.0.0.1:6379> zrevrank ages zhangsan
|
||||
(integer) 0
|
||||
```
|
||||
|
||||
# 7. zrem 删除有序集合成员
|
||||
|
||||
```bash
|
||||
zrem key value1 value2 ..
|
||||
# 删除集合中的成员
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zrem ages wangwu
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zrange ages 0 -1
|
||||
1) "lisi"
|
||||
2) "zhangsan"
|
||||
```
|
||||
|
||||
# 8. zremrangebyrank 按排名删除成员
|
||||
|
||||
```bash
|
||||
zremrangebyrank key start end
|
||||
# 按排名删除成员,删除名次在[start,end]之间的
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu 178 zhaoliu
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zremrangebyrank height 0 1
|
||||
(integer) 2
|
||||
127.0.0.1:6379> zrange height 0 -1
|
||||
1) "zhaoliu"
|
||||
2) "wangwu"
|
||||
```
|
||||
|
||||
# 9. zremrangebyscore 按分数删除成员
|
||||
|
||||
```bash
|
||||
zremrangebyscore key min max
|
||||
# 按照socre来删除成员,删除score在[min,max]之间的
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd height 175 zhangsan 167 lisi 185 wangwu 178 zhaoliu
|
||||
(integer) 2
|
||||
127.0.0.1:6379> zremrangebyscore height 170 180
|
||||
(integer) 2
|
||||
127.0.0.1:6379> zrange height 0 -1
|
||||
1) "lisi"
|
||||
2) "wangwu"
|
||||
```
|
||||
|
||||
# 10. zinterstore 求交集再计算
|
||||
|
||||
```bash
|
||||
zinterstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
|
||||
# 求key1、key2...的交集,key1、key2...的权重分别是 weight1、weight2...
|
||||
# 聚合方法用: sum|min|max
|
||||
# 聚合的结果保存在destination集合内
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd zhangsan 5 iphone6s 7 galaxyS7 6 huaweiP9
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zadd lisi 3 iphone6s 9 galaxyS7 4 huaweiP9 2 HTC10
|
||||
(integer) 4
|
||||
127.0.0.1:6379> zinterstore result 2 zhangsan lisi
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zrange result 0 -1 withscores
|
||||
1) "iphone6s"
|
||||
2) "8"
|
||||
3) "huaweiP9"
|
||||
4) "10"
|
||||
5) "galaxyS7"
|
||||
6) "16"
|
||||
127.0.0.1:6379> zinterstore result 2 zhangsan lisi aggregate max
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zrange result 0 -1 withscores
|
||||
1) "iphone6s"
|
||||
2) "5"
|
||||
3) "huaweiP9"
|
||||
4) "6"
|
||||
5) "galaxyS7"
|
||||
6) "9"
|
||||
```
|
||||
|
||||
# 11. zunionstore 求并集再计算
|
||||
|
||||
```bash
|
||||
zunionstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
|
||||
# 求key1、key2...的并集,key1、key2...的权重分别是 weight1、weight2...
|
||||
# 聚合方法用: sum|min|max
|
||||
# 聚合的结果保存在destination集合内
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> zadd zhangsan 4 iphone6s 6 huaweiP9 8 xiaomi5
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zadd lisi 2 iphone6s 8 galaxS7 5 meizu6
|
||||
(integer) 3
|
||||
127.0.0.1:6379> zunionstore result 2 zhangsan lisi
|
||||
(integer) 5
|
||||
127.0.0.1:6379> zrange result 0 -1 withscores
|
||||
1) "meizu6"
|
||||
2) "5"
|
||||
3) "huaweiP9"
|
||||
4) "6"
|
||||
5) "iphone6s"
|
||||
6) "6"
|
||||
7) "galaxS7"
|
||||
8) "8"
|
||||
9) "xiaomi5"
|
||||
10) "8"
|
||||
127.0.0.1:6379> zunionstore result 2 zhangsan lisi aggregate max
|
||||
(integer) 5
|
||||
127.0.0.1:6379> zrange result 0 -1 withscores
|
||||
1) "iphone6s"
|
||||
2) "4"
|
||||
3) "meizu6"
|
||||
4) "5"
|
||||
5) "huaweiP9"
|
||||
6) "6"
|
||||
7) "galaxS7"
|
||||
8) "8"
|
||||
9) "xiaomi5"
|
||||
10) "8"
|
||||
```
|
||||
183
数据库/Redis命令总结/07.哈希数据类操作.md
Normal file
183
数据库/Redis命令总结/07.哈希数据类操作.md
Normal file
@@ -0,0 +1,183 @@
|
||||
- [1. hset 设置哈希field域的值](#1-hset-设置哈希field域的值)
|
||||
- [2. hmset 设置哈希多个field域的值](#2-hmset-设置哈希多个field域的值)
|
||||
- [3. hget 获取field域的值](#3-hget-获取field域的值)
|
||||
- [4. hmget 获取多个field域的值](#4-hmget-获取多个field域的值)
|
||||
- [5. hgetall 获取所有field域和值](#5-hgetall-获取所有field域和值)
|
||||
- [6. hlen 获取field的数量](#6-hlen-获取field的数量)
|
||||
- [7. hdel 删除field域](#7-hdel-删除field域)
|
||||
- [8. hexists 判断field域是否存在](#8-hexists-判断field域是否存在)
|
||||
- [9. hincrby 使field域的值加上整数](#9-hincrby-使field域的值加上整数)
|
||||
- [10. hincrbyfloat 使field域的值加上浮点数](#10-hincrbyfloat-使field域的值加上浮点数)
|
||||
- [11. hkeys 获取所有所有field域的名字](#11-hkeys-获取所有所有field域的名字)
|
||||
- [12. kvals 获取所有所有field域的值](#12-kvals-获取所有所有field域的值)
|
||||
|
||||
# 1. hset 设置哈希field域的值
|
||||
|
||||
```bash
|
||||
hset key field value
|
||||
# 把key中 filed域的值设为value
|
||||
# 注:如果没有field域,直接添加,如果有,则覆盖原field域的值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hset user name zhangsan
|
||||
(integer) 1
|
||||
127.0.0.1:6379> hset user age 25
|
||||
(integer) 1
|
||||
127.0.0.1:6379> hset user gender male
|
||||
(integer) 1
|
||||
```
|
||||
|
||||
# 2. hmset 设置哈希多个field域的值
|
||||
|
||||
```bash
|
||||
hmset key field1 value1 [field2 value2 field3 value3 ......fieldn valuen]
|
||||
# 一次设置多个field和对应的value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
OK
|
||||
```
|
||||
|
||||
# 3. hget 获取field域的值
|
||||
|
||||
```bash
|
||||
hget key field
|
||||
# 获取field域的值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
OK
|
||||
127.0.0.1:6379> hget user age
|
||||
"26
|
||||
```
|
||||
|
||||
# 4. hmget 获取多个field域的值
|
||||
|
||||
```bash
|
||||
hget key field
|
||||
# 获取多个field域的值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
OK
|
||||
127.0.0.1:6379> hmget user name age
|
||||
1) "lisi"
|
||||
2) "26"
|
||||
```
|
||||
|
||||
# 5. hgetall 获取所有field域和值
|
||||
|
||||
```bash
|
||||
hgetall key
|
||||
# 获取哈希key的所有field域和值
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
127.0.0.1:6379> hgetall user
|
||||
1) "name"
|
||||
2) "lisi"
|
||||
3) "age"
|
||||
4) "26"
|
||||
5) "gender"
|
||||
6) "male"
|
||||
```
|
||||
|
||||
# 6. hlen 获取field的数量
|
||||
|
||||
```bash
|
||||
hlen key
|
||||
# 获取field的数量
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
127.0.0.1:6379> hlen user
|
||||
(integer) 3
|
||||
```
|
||||
|
||||
# 7. hdel 删除field域
|
||||
|
||||
```bash
|
||||
hdel key field
|
||||
# 删除key中 field域
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
127.0.0.1:6379> hdel user age
|
||||
(integer) 1
|
||||
127.0.0.1:6379> hgetall user
|
||||
1) "name"
|
||||
2) "lisi"
|
||||
3) "gender"
|
||||
4) "male"
|
||||
```
|
||||
|
||||
# 8. hexists 判断field域是否存在
|
||||
|
||||
```bash
|
||||
hexists key field
|
||||
# 判断key中有没有field域
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name lisi age 26 gender male
|
||||
OK
|
||||
127.0.0.1:6379> hexists user age
|
||||
(integer) 1
|
||||
127.0.0.1:6379> hexists user height
|
||||
(integer) 0
|
||||
```
|
||||
|
||||
# 9. hincrby 使field域的值加上整数
|
||||
|
||||
```bash
|
||||
hincrby key field value
|
||||
# 使key中的field域的值加上整型值value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name zhangsan height 158
|
||||
OK
|
||||
127.0.0.1:6379> hincrby user height 2
|
||||
(integer) 160
|
||||
```
|
||||
|
||||
# 10. hincrbyfloat 使field域的值加上浮点数
|
||||
|
||||
```bash
|
||||
hincrbyfloat key field value
|
||||
# 使key中的field域的值加上浮点值value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name zhangsan height 158
|
||||
OK
|
||||
127.0.0.1:6379> hincrbyfloat user height 5.5
|
||||
"165.5"
|
||||
```
|
||||
|
||||
# 11. hkeys 获取所有所有field域的名字
|
||||
|
||||
```bash
|
||||
hkeys key
|
||||
# 获取key中所有的field
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name zhangsan age 25 gender male
|
||||
OK
|
||||
127.0.0.1:6379> hkeys user
|
||||
1) "name"
|
||||
2) "age"
|
||||
3) "gender"
|
||||
```
|
||||
|
||||
# 12. kvals 获取所有所有field域的值
|
||||
|
||||
```bash
|
||||
kvals key
|
||||
# 返回key中所有的value
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> hmset user name zhangsan age 25 gender male
|
||||
OK
|
||||
127.0.0.1:6379> hvals user
|
||||
1) "zhangsan"
|
||||
2) "25"
|
||||
3) "male"
|
||||
```
|
||||
228
数据库/Redis命令总结/08.经纬度数据操作.md
Normal file
228
数据库/Redis命令总结/08.经纬度数据操作.md
Normal file
@@ -0,0 +1,228 @@
|
||||
- [1. geoadd 添加地理位置信息](#1-geoadd-添加地理位置信息)
|
||||
- [2. geopos 查询位置的坐标](#2-geopos-查询位置的坐标)
|
||||
- [3. geodist 查询位置距离](#3-geodist-查询位置距离)
|
||||
- [4. georadius 查询某点的附近点](#4-georadius-查询某点的附近点)
|
||||
- [5. georadiusbymember 查询某位置距离的附近点](#5-georadiusbymember-查询某位置距离的附近点)
|
||||
- [6. geohash 查询位置GEOHASH编码](#6-geohash-查询位置geohash编码)
|
||||
|
||||
# 1. geoadd 添加地理位置信息
|
||||
|
||||
命令:`geoadd key longitude latitude member [longitude latitude member ...]`
|
||||
|
||||
longitude表示经度,latitude表示纬度,member表示成员
|
||||
|
||||
命令描述:将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
|
||||
|
||||
返回值:添加到sorted set元素的数目,但不包括已更新score的元素。
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
127.0.0.1:6379> geoadd Guangdong-cities 113.2278442 23.1255978 Guangzhou 113.106308 23.0088312 Foshan 113.7943267 22.9761989 Dongguan 114.0538788 22.5551603 Shenzhen
|
||||
(integer) 4
|
||||
```
|
||||
|
||||
# 2. geopos 查询位置的坐标
|
||||
|
||||
命令:`geopos location-set name [name ...]`
|
||||
|
||||
命令描述:从key里返回所有给定位置元素的位置(经度和纬度)。
|
||||
|
||||
返回值:GEOPOS 命令返回一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 而第二个元素则为给定位置元素的纬度。当给定的位置元素不存在时, 对应的数组项为空值。
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
127.0.0.1:6379> geopos Guangdong-cities Guangzhou Shenzhen
|
||||
1) 1) "113.22784155607223511"
|
||||
2) "23.1255982020608073"
|
||||
2) 1) "114.05388146638870239"
|
||||
2) "22.55515920515157546"
|
||||
```
|
||||
|
||||
# 3. geodist 查询位置距离
|
||||
|
||||
命令:`geodist key member1 member2 [m|km|mi|ft]`
|
||||
|
||||
命令描述:
|
||||
|
||||
返回两个给定位置之间的距离。如果两个位置之间的其中一个不存在, 那么命令返回空值。指定单位的参数 unit 必须是以下单位的其中一个:
|
||||
|
||||
m 表示单位为米。
|
||||
|
||||
km 表示单位为千米。
|
||||
|
||||
mi 表示单位为英里。
|
||||
|
||||
ft 表示单位为英尺。
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
127.0.0.1:6379> geodist Guangdong-cities Guangzhou Shenzhen
|
||||
"105806.7782"
|
||||
```
|
||||
|
||||
# 4. georadius 查询某点的附近点
|
||||
|
||||
命令:`GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]`
|
||||
|
||||
命令描述:以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
|
||||
|
||||
范围可以使用以下其中一个单位:
|
||||
|
||||
m 表示单位为米。
|
||||
|
||||
km 表示单位为千米。
|
||||
|
||||
mi 表示单位为英里。
|
||||
|
||||
ft 表示单位为英尺。
|
||||
|
||||
在给定以下可选项时, 命令会返回额外的信息:
|
||||
|
||||
**WITHDIST**: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
|
||||
|
||||
**WITHCOORD**: 将位置元素的经度和维度也一并返回。
|
||||
|
||||
**WITHHASH**: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
|
||||
|
||||
命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:
|
||||
|
||||
**ASC**: 根据中心的位置, 按照从近到远的方式返回位置元素。
|
||||
|
||||
**DESC**: 根据中心的位置, 按照从远到近的方式返回位置元素。
|
||||
|
||||
在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 COUNT <count> 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。
|
||||
|
||||
返回值:
|
||||
|
||||
在没有给定任何 WITH 选项的情况下, 命令只会返回一个像 [“New York”,”Milan”,”Paris”] 这样的线性(linear)列表。
|
||||
|
||||
在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等选项的情况下, 命令返回一个二层嵌套数组, 内层的每个子数组就表示一个元素。
|
||||
|
||||
在返回嵌套数组时, 子数组的第一个元素总是位置元素的名字。 至于额外的信息, 则会作为子数组的后续元素, 按照以下顺序被返回:
|
||||
|
||||
1. 以浮点数格式返回的中心与位置元素之间的距离, 单位与用户指定范围时的单位一致。
|
||||
2. geohash 整数。
|
||||
3. 由两个元素组成的坐标,分别为经度和纬度。
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km
|
||||
1) "Foshan"
|
||||
2) "Guangzhou"
|
||||
3) "Dongguan"
|
||||
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km withcoord
|
||||
1) 1) "Foshan"
|
||||
2) 1) "113.10631066560745"
|
||||
2) "23.008831202413539"
|
||||
2) 1) "Guangzhou"
|
||||
2) 1) "113.22784155607224"
|
||||
2) "23.125598202060807"
|
||||
3) 1) "Dongguan"
|
||||
2) 1) "113.79432410001755"
|
||||
2) "22.9761992022082"
|
||||
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km withcoord withdist
|
||||
1) 1) "Foshan"
|
||||
2) "17.9820"
|
||||
3) 1) "113.10631066560745"
|
||||
2) "23.008831202413539"
|
||||
2) 1) "Guangzhou"
|
||||
2) "0.0003"
|
||||
3) 1) "113.22784155607224"
|
||||
2) "23.125598202060807"
|
||||
3) 1) "Dongguan"
|
||||
2) "60.3111"
|
||||
3) 1) "113.79432410001755"
|
||||
2) "22.9761992022082"
|
||||
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km withcoord withdist withhash
|
||||
1) 1) "Foshan"
|
||||
2) "17.9820"
|
||||
3) (integer) 4046506835759376
|
||||
4) 1) "113.10631066560745"
|
||||
2) "23.008831202413539"
|
||||
2) 1) "Guangzhou"
|
||||
2) "0.0003"
|
||||
3) (integer) 4046533621643967
|
||||
4) 1) "113.22784155607224"
|
||||
2) "23.125598202060807"
|
||||
3) 1) "Dongguan"
|
||||
2) "60.3111"
|
||||
3) (integer) 4046540375616238
|
||||
4) 1) "113.79432410001755"
|
||||
2) "22.9761992022082"
|
||||
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km withcoord withdist withhash count 2
|
||||
1) 1) "Guangzhou"
|
||||
2) "0.0003"
|
||||
3) (integer) 4046533621643967
|
||||
4) 1) "113.22784155607224"
|
||||
2) "23.125598202060807"
|
||||
2) 1) "Foshan"
|
||||
2) "17.9820"
|
||||
3) (integer) 4046506835759376
|
||||
4) 1) "113.10631066560745"
|
||||
2) "23.008831202413539"
|
||||
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km withcoord withdist withhash asc
|
||||
1) 1) "Guangzhou"
|
||||
2) "0.0003"
|
||||
3) (integer) 4046533621643967
|
||||
4) 1) "113.22784155607224"
|
||||
2) "23.125598202060807"
|
||||
2) 1) "Foshan"
|
||||
2) "17.9820"
|
||||
3) (integer) 4046506835759376
|
||||
4) 1) "113.10631066560745"
|
||||
2) "23.008831202413539"
|
||||
3) 1) "Dongguan"
|
||||
2) "60.3111"
|
||||
3) (integer) 4046540375616238
|
||||
4) 1) "113.79432410001755"
|
||||
2) "22.9761992022082"
|
||||
|
||||
127.0.0.1:6379>georadius Guangdong-cities 113.2278442 23.1255978 100 km withcoord withdist withhash desc
|
||||
1) 1) "Dongguan"
|
||||
2) "60.3111"
|
||||
3) (integer) 4046540375616238
|
||||
4) 1) "113.79432410001755"
|
||||
2) "22.9761992022082"
|
||||
2) 1) "Foshan"
|
||||
2) "17.9820"
|
||||
3) (integer) 4046506835759376
|
||||
4) 1) "113.10631066560745"
|
||||
2) "23.008831202413539"
|
||||
3) 1) "Guangzhou"
|
||||
2) "0.0003"
|
||||
3) (integer) 4046533621643967
|
||||
4) 1) "113.22784155607224"
|
||||
2) "23.125598202060807"
|
||||
```
|
||||
|
||||
# 5. georadiusbymember 查询某位置距离的附近点
|
||||
|
||||
```bash
|
||||
georadiusbymember key member radius m|km|ft|mi
|
||||
# 指定成员作为中心来查询附近的点
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> georadiusbymember Guangdong-cities Guangzhou 100 km
|
||||
1) "Foshan"
|
||||
2) "Guangzhou"
|
||||
3) "Dongguan"
|
||||
```
|
||||
|
||||
# 6. geohash 查询位置GEOHASH编码
|
||||
|
||||
命令:`geohash key member [member ...]`
|
||||
|
||||
命令描述:返回一个或多个位置元素的 Geohash 表示。通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash
|
||||
|
||||
返回值:一个数组, 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应。
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
127.0.0.1:6379> geohash Guangdong-cities Guangzhou
|
||||
1) "ws0e89curg0"
|
||||
```
|
||||
65
数据库/Redis命令总结/09.事务.md
Normal file
65
数据库/Redis命令总结/09.事务.md
Normal file
@@ -0,0 +1,65 @@
|
||||
- [1. 事务命令](#1-事务命令)
|
||||
- [2. 乐观锁](#2-乐观锁)
|
||||
|
||||
# 1. 事务命令
|
||||
|
||||
| 命令 | 说明 |
|
||||
| :------ | :----------- |
|
||||
| muitl | 开启事务命令 |
|
||||
| command | 普通命令 |
|
||||
| discard | 在提交前取消 |
|
||||
| exec | 提交 |
|
||||
|
||||
注:discard只是结束本次事务,前2条语句已经执行,造成的影响仍然还在。
|
||||
|
||||
语句出错有两种情况: - 语法有问题,exec时报错,所有语句取消执行,没有对数据造成影响。 - 语法本身没错,但适用对象有问题(比如 zadd 操作list对象),exec之后,会执行正确的语句,并跳过有不适当的语句,对数据会造成影响,这点由程序员负责。
|
||||
|
||||
# 2. 乐观锁
|
||||
|
||||
redis的事务中启用的是乐观锁,只负责监测key没有被改动,如果在事务中发现key被改动,则取消事务。使用watch命令来监控一个或多个key,使用unwatch命令来取消监控所有key。
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
watch key
|
||||
muitl
|
||||
操作数据...
|
||||
exec
|
||||
unwatch
|
||||
```
|
||||
|
||||
模拟抢票,场景:用户买一张票,扣掉100元
|
||||
|
||||
```bash
|
||||
# 在zhangsan买票过程中,在提交事务前一瞬间,有人成功买到票,ticket已经改变(即使ticket还有票),导致zhangsan抢票失败。
|
||||
127.0.0.1:6379> watch ticket
|
||||
OK
|
||||
127.0.0.1:6379> multi
|
||||
OK
|
||||
127.0.0.1:6379> decr ticket
|
||||
QUEUED
|
||||
127.0.0.1:6379> decrby zhangsan 100
|
||||
QUEUED
|
||||
127.0.0.1:6379> exec
|
||||
(nil)
|
||||
127.0.0.1:6379> get zhangsan
|
||||
"1000"
|
||||
127.0.0.1:6379> get ticket
|
||||
"2"
|
||||
127.0.0.1:6379> unwatch
|
||||
OK
|
||||
|
||||
|
||||
# lisi在买票整个过程都没有人抢票,所以lisi一次抢票成功。
|
||||
127.0.0.1:6379> watch ticket
|
||||
OK
|
||||
127.0.0.1:6379> multi
|
||||
OK
|
||||
127.0.0.1:6379> decrby lisi 100
|
||||
QUEUED
|
||||
127.0.0.1:6379> decr ticket
|
||||
QUEUED
|
||||
127.0.0.1:6379> exec
|
||||
1) (integer) 700
|
||||
2) (integer) 1
|
||||
127.0.0.1:6379> unwatch
|
||||
```
|
||||
75
数据库/Redis命令总结/10.频道发布与订阅.md
Normal file
75
数据库/Redis命令总结/10.频道发布与订阅.md
Normal file
@@ -0,0 +1,75 @@
|
||||
- [1. publish 发布频道](#1-publish-发布频道)
|
||||
- [2. subscribe 订阅指定频道](#2-subscribe-订阅指定频道)
|
||||
- [3. psubscribe 订阅已匹配频道](#3-psubscribe-订阅已匹配频道)
|
||||
|
||||
- 发布端:publish
|
||||
- 订阅端:subscribe,psubscribe
|
||||
|
||||
# 1. publish 发布频道
|
||||
|
||||
```bash
|
||||
publish 频道名称 发布内容
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> publish music_2 "It's Not Goodbye"
|
||||
(integer) 1
|
||||
127.0.0.1:6379> publish music "just one last dance"
|
||||
(integer) 2
|
||||
127.0.0.1:6379> publish music "stay"
|
||||
(integer) 2
|
||||
|
||||
127.0.0.1:6379> publish music_2 "It's Not Goodbye"
|
||||
(integer) 1
|
||||
```
|
||||
|
||||
# 2. subscribe 订阅指定频道
|
||||
|
||||
```bash
|
||||
subscribe 频道名称
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> subscribe music
|
||||
Reading messages... (press Ctrl-C to quit)
|
||||
1) "subscribe"
|
||||
2) "music"
|
||||
3) (integer) 1
|
||||
1) "message"
|
||||
2) "music"
|
||||
3) "just one last dance"
|
||||
1) "message"
|
||||
2) "music"
|
||||
3) "stay" "music"
|
||||
3) (integer) 1
|
||||
1) "message"
|
||||
2) "music"
|
||||
3) "just one last dance"
|
||||
1) "message"
|
||||
2) "music"
|
||||
3) "stay"
|
||||
```
|
||||
|
||||
# 3. psubscribe 订阅已匹配频道
|
||||
|
||||
```bash
|
||||
psubscribe 匹配频道名称
|
||||
|
||||
# 示例
|
||||
127.0.0.1:6379> psubscribe music*
|
||||
Reading messages... (press Ctrl-C to quit)
|
||||
1) "psubscribe"
|
||||
2) "music*"
|
||||
3) (integer) 1
|
||||
1) "pmessage"
|
||||
2) "music*"
|
||||
3) "music"
|
||||
4) "just one last dance"
|
||||
1) "pmessage"
|
||||
2) "music*"
|
||||
3) "music"
|
||||
4) "stay"
|
||||
|
||||
1) "pmessage"
|
||||
2) "music*"
|
||||
3) "music_2"
|
||||
4) "It's Not Goodbye"
|
||||
```
|
||||
79
数据库/Redis命令总结/11.redis持久化和导入导出数据库.md
Normal file
79
数据库/Redis命令总结/11.redis持久化和导入导出数据库.md
Normal file
@@ -0,0 +1,79 @@
|
||||
- [1. redis持久化](#1-redis持久化)
|
||||
- [1.1. rdb快照持久化](#11-rdb快照持久化)
|
||||
- [1.2. aof日志持久化](#12-aof日志持久化)
|
||||
- [2. 导入和导出数据库](#2-导入和导出数据库)
|
||||
|
||||
# 1. redis持久化
|
||||
|
||||
## 1.1. rdb快照持久化
|
||||
|
||||
rdb的工作原理:每隔N分钟或N次写操作后,从内存dump数据形成rdb文件,压缩放在备份目录,设置配置文件参数:
|
||||
|
||||
```bash
|
||||
# 打开配置文件
|
||||
vim /usr/local/redis/ redis.conf
|
||||
|
||||
save 900 1 # 900秒内,有1条写入,则产生快照
|
||||
save 300 1000 # 如果300秒内有1000次写入,则产生快照
|
||||
save 60 10000 # 如果60秒内有10000次写入,则产生快照
|
||||
(这3个选项都屏蔽,则rdb禁用)
|
||||
|
||||
stop-writes-on-bgsave-error yes # 后台备份进程出错时,主进程停不停止写入
|
||||
rdbcompression yes # 导出的rdb文件是否压缩
|
||||
Rdbchecksum yes # 导入rbd恢复时数据时,要不要检验rdb的完整性
|
||||
|
||||
dbfilename dump.rdb # 导出来的rdb文件名
|
||||
dir /usr/local/redis/data # rdb的放置路径
|
||||
|
||||
# 压力测试来检测是否启用了rdb快照
|
||||
/usr/local/redis/bin/redis-benchmark
|
||||
```
|
||||
|
||||
rdb的缺陷:在2个保存点之间断电,将会丢失1-N分钟的数据
|
||||
|
||||
## 1.2. aof日志持久化
|
||||
|
||||
工作原理:redis主进程 –> 后台日志进程 –> aof文件
|
||||
|
||||
设置配置文件参数:
|
||||
|
||||
```bash
|
||||
# 打开配置文件
|
||||
vim /usr/local/redis/ redis.conf
|
||||
|
||||
appendonly no # 是否打开 aof日志功能
|
||||
appendfilename "appendonly.aof" # aof文件名,和rdb的dir公用一个路径
|
||||
|
||||
#appendfsync always # 每1个写命令都立即同步到aof文件,安全但速度慢
|
||||
appendfsync everysec # 折衷方案,每秒写1次
|
||||
上面方案选择一种,一般选择everysec
|
||||
|
||||
appendfsync no # 写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof文件,同步频率低,但速度快
|
||||
|
||||
no-appendfsync-on-rewrite yes # 正在导出rdb快照的过程中,要不要停止同步aof
|
||||
auto-aof-rewrite-percentage 100 # aof文件大小比起上次重写时的大小,增长率100%时重写
|
||||
auto-aof-rewrite-min-size 64mb # aof文件至少超过64M时才重写
|
||||
```
|
||||
|
||||
注意:如果需要持久化,一般推荐rdb和aof同时开启,同时开启后redis进程启动优先选择aof恢复数据。rdb恢复速度快。
|
||||
|
||||
在dump rdb过程中,aof如果停止同步,会不会丢失? 不会,所有的操作缓存在内存的队列里,dump完成后统一操作.
|
||||
|
||||
aof重写是指什么? aof重写是指把内存中的数据,逆化成命令,写入到.aof日志里,以解决 aof日志过大的问题,手动重写aof命令:bgrewriteaof
|
||||
|
||||
# 2. 导入和导出数据库
|
||||
|
||||
```bash
|
||||
(1) 安装redis-dump工具
|
||||
yum install ruby rubygems ruby-devel
|
||||
gem sources --remove http://ruby.taobao.org/
|
||||
gem sources -a https://ruby.taobao.org/
|
||||
gem install redis-dump -V
|
||||
|
||||
(2) 导出redis数据
|
||||
redis-dump -u 127.0.0.1:6379 > test.json
|
||||
|
||||
(3) 导入redis数据
|
||||
< test.json redis-load
|
||||
```
|
||||
|
||||
350
数据库/Redis命令总结/12.redis应用示例.md
Normal file
350
数据库/Redis命令总结/12.redis应用示例.md
Normal file
@@ -0,0 +1,350 @@
|
||||
- [1. 统计活跃用户](#1-统计活跃用户)
|
||||
- [2. 搭建高可用redis集群](#2-搭建高可用redis集群)
|
||||
- [1. 常见redis集群](#1-常见redis集群)
|
||||
- [2. 单机版redis集群](#2-单机版redis集群)
|
||||
- [2.1 修改redis配置文件](#21-修改redis配置文件)
|
||||
- [2.2 重新打包redis镜像](#22-重新打包redis镜像)
|
||||
- [2.3 编辑docker-compose.yml文件](#23-编辑docker-composeyml文件)
|
||||
- [2.4 创建redis集群](#24-创建redis集群)
|
||||
- [2.5 创建带有密码的redis集群](#25-创建带有密码的redis集群)
|
||||
- [2.6 创建集群中遇到的问题](#26-创建集群中遇到的问题)
|
||||
|
||||
# 1. 统计活跃用户
|
||||
|
||||
场景: 1亿个用户,用户登陆,标记为今天活跃,否则记为不活跃,记录最活跃用户。
|
||||
|
||||
```bash
|
||||
# 思路
|
||||
每个用户在数据库都有一个id,用第id个位的0和1来表示是否登录,例如:
|
||||
login0721: '011001...............0'
|
||||
......
|
||||
login0726: '011001...............0'
|
||||
login0727: '0110000.............1'
|
||||
|
||||
# 实现过程
|
||||
(1) 记录用户登陆,每天按日期生成一个位图,用户登陆后,把user_id位上的bit值置为1
|
||||
首先把所有用户的位置位0
|
||||
redis 127.0.0.1:6379> setbit login0721 100000000 0
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0721 3 1
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0721 5 1
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0721 7 1
|
||||
(integer) 0
|
||||
......
|
||||
redis 127.0.0.1:6379> setbit login0722 100000000 0
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0722 3 1
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0722 5 1
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0722 8 1
|
||||
(integer) 0
|
||||
......
|
||||
redis 127.0.0.1:6379> setbit login0723 100000000 0
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0723 3 1
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0723 4 1
|
||||
(integer) 0
|
||||
redis 127.0.0.1:6379> setbit login0723 6 1
|
||||
(integer) 0
|
||||
......
|
||||
(2)把1周/月的位图用and计算, 位为1的是连续登陆的用户。
|
||||
redis 127.0.0.1:6379> bitop and login0721 login0722 login0723......
|
||||
(integer) 12500001
|
||||
|
||||
# 优点
|
||||
(1) 节约空间,用1亿bit表示1亿人每天的登陆情况,1亿bit约为10M。
|
||||
(2) 计算方便,计算速度非常快
|
||||
```
|
||||
|
||||
# 2. 搭建高可用redis集群
|
||||
|
||||
## 1. 常见redis集群
|
||||
|
||||
常见redis集群有RedisCluster、Codis、Twemproxy,其中Codis、Twemproxy是有中心节点的,而RedisCluster是没中心节点,而且是redis内置的集群方案,推荐使用redisCluster集群。
|
||||
|
||||
redisCluster特点:
|
||||
|
||||
- 无中心节点,客户端与 redis节点直连,不需要中间代理层。
|
||||
- 数据可以被分片存储,集群数据加起来就是全量数据。
|
||||
- 可以通过任意一个节点,读写不属于本节点的数据。
|
||||
- 管理方便,后续可自行增加或删除节点。
|
||||
|
||||
|
||||
|
||||
由于RedisCluster是分片存储,当集群中一个节点故障时,会损失该节点数据,为了实现高可用,需要对每个节点各添加一个从节点,形成主从同步,当主redis(集群节点)出现故障时,从节点替换故障的主节点。
|
||||
|
||||
- Redist集群中的数据库复制是通过主从同步来实现的。
|
||||
- 主节点( Master)把数据分发给从节点(Slave)。
|
||||
- 主从同步的好处在于高可用, Redis节点有冗余设计。
|
||||
- 集群节点个数最好是奇数并且3个以上, 奇数个的好处是,有一个节点出现故障了,集群数量过半数,集群可以继续正常使用,数量少于半数则认为集群瘫痪了。
|
||||
|
||||

|
||||
|
||||
如果客户端本身带有负载均衡功能,可以省去使用haproxy搭建负载均衡,也可以在程序简单的实现负载均衡功能。
|
||||
|
||||
## 2. 单机版redis集群
|
||||
|
||||
在单机上搭建3个节点的集群,3个主节点分别有各自的从节点,如图所示:
|
||||
|
||||

|
||||
|
||||
### 2.1 修改redis配置文件
|
||||
|
||||
因为官方镜像中没有redis配置,也没有启动redis,需要去官方下载对应版本的redis源码获取redis.conf和redis-trib.rb文件,下载官方源码地址:http://download.redis.io/releases/
|
||||
|
||||
```bash
|
||||
mkdir redis-cluster
|
||||
cd redis-cluster
|
||||
wget http://download.redis.io/releases/redis-4.0.11.tar.gz
|
||||
tar zxvf redis-4.0.11.tar.gz
|
||||
|
||||
# 从源码中复制redis.conf和redis-trib.rb文件到当前目录
|
||||
cp redis-4.0.11/redis.conf .
|
||||
cp redis-4.0.11/src/redis-trib.rb .
|
||||
|
||||
# 删除redis源码文件
|
||||
rm -rf redis-4.0.11 redis-4.0.11.tar.gz
|
||||
```
|
||||
|
||||
|
||||
|
||||
因为redis默认没有开启集群功能,需要修改redis配置文件redis.conf,主要修改下面几个参数
|
||||
|
||||
```bash
|
||||
bind 0.0.0.0 # 允许外部登录
|
||||
cluster-enabled yes # 开启集群
|
||||
cluster-config-file nodes-6379.conf # 集群配置文件
|
||||
cluster-node-timeout 15000 # 超时时间
|
||||
appendonly yes # 并开启AOF模式
|
||||
```
|
||||
|
||||
### 2.2 重新打包redis镜像
|
||||
|
||||
下载指定版本redis官方镜像
|
||||
|
||||
> docker pull redis:4.0.11
|
||||
|
||||
因为官方redis镜像不能满足搭建redis集群要求,需要在官方镜像基础上添加ruby和启动redis命令功能,在当前目录创建Dockerfile文件,文件内容如下:
|
||||
|
||||
```dockerfile
|
||||
FROM redis
|
||||
|
||||
# 安装ruby
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y install ruby
|
||||
RUN apt-get -y install rubygems
|
||||
# ruby 安装redis接口
|
||||
RUN gem install redis
|
||||
# 安装vim
|
||||
RUN apt-get -y install vim
|
||||
|
||||
# 启动redis
|
||||
CMD redis-server /usr/local/etc/redis/redis.conf
|
||||
```
|
||||
|
||||
### 2.3 编辑docker-compose.yml文件
|
||||
|
||||
在当前目录创建docker-compose.yml文件来管理容器,共6个容器,文件内容如下:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
|
||||
redis-node1:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 20001:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
# 创建集群的配置文件,只需创建一次,其他节点不需要映射此文件
|
||||
- ./redis-trib.rb:/usr/local/etc/redis/redis-trib.rb
|
||||
networks:
|
||||
- redis-net
|
||||
|
||||
redis-node2:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 20002:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
networks:
|
||||
- redis-net
|
||||
|
||||
redis-node3:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 20003:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
networks:
|
||||
- redis-net
|
||||
|
||||
redis-node4:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 20004:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
networks:
|
||||
- redis-net
|
||||
|
||||
redis-node5:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 20005:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
networks:
|
||||
- redis-net
|
||||
|
||||
redis-node6:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 20006:6379
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
networks:
|
||||
- redis-net
|
||||
|
||||
networks:
|
||||
redis-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
### 2.4 创建redis集群
|
||||
|
||||
当前目录下完整文件列表如下所示:
|
||||
|
||||
```bash
|
||||
.
|
||||
├── docker-compose.yml
|
||||
├── Dockerfile
|
||||
├── redis.conf
|
||||
└── redis-trib.rb
|
||||
```
|
||||
|
||||
|
||||
|
||||
准备好文件后,开始创建redis集群:
|
||||
|
||||
```bash
|
||||
# 先打包好新的redis镜像
|
||||
docker-compose build
|
||||
|
||||
# 启动容器
|
||||
docker-compose up -d
|
||||
|
||||
# 获取所有启动redis容器ip地址,获取ip地址是用来创建集群准备
|
||||
docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq) | grep redis
|
||||
|
||||
# 执行命令的结果如下:
|
||||
# /redis-cluster_redis-node2_1 - 172.20.0.6
|
||||
# /redis-cluster_redis-node4_1 - 172.20.0.7
|
||||
# /redis-cluster_redis-node6_1 - 172.20.0.4
|
||||
# /redis-cluster_redis-node1_1 - 172.20.0.5
|
||||
# /redis-cluster_redis-node5_1 - 172.20.0.3
|
||||
# /redis-cluster_redis-node3_1 - 172.20.0.2
|
||||
|
||||
# 进入redis-node1容器,因为只有redis-node1容器映射了redis-trib.rb文件
|
||||
docker-compose exec redis-node1 bash
|
||||
|
||||
# 创建集群
|
||||
/usr/local/etc/redis/redis-trib.rb create --replicas 1 172.20.0.2:6379 172.20.0.3:6379 172.20.0.4:6379 172.20.0.5:6379 172.20.0.6:6379 172.20.0.7:6379
|
||||
|
||||
# 其中参数--replicas 1表示每个主节点有一个从节点。
|
||||
# 在创建集群过程会提示Can I set the above configuration? 在终端输入yes即可,如果不出现错误,很快就完成集群的创建。
|
||||
|
||||
# 创建完集群后,在任意一个redis节点都可以进入redis集群,-c表示连接的是集群
|
||||
redis-cli -c
|
||||
|
||||
# 查看集群节点
|
||||
127.0.0.1:6379> cluster nodes
|
||||
|
||||
# afb979236e96b6e9aac972af7508e4cd9505676d 172.20.0.6:6379@16379 slave 9715f836310b872961a7defc64bdb4a319f9848d 0 1537636386000 5 connected
|
||||
# 1ffa00413a5f75465e1bb5aaef551c38fb3db1f3 172.20.0.5:6379@16379 myself,master - 0 1537636387000 7 connected 10923-16383
|
||||
# 9715f836310b872961a7defc64bdb4a319f9848d 172.20.0.2:6379@16379 master - 0 1537636387811 1 connected 0-5460
|
||||
# d59a0ad710f35fe349f62eda4279e02972983fd3 172.20.0.3:6379@16379 master - 0 1537636386000 2 connected 5461-10922
|
||||
# c9371c4936d12b9f764e5bf5a7257928aa36cbc2 172.20.0.7:6379@16379 slave d59a0ad710f35fe349f62eda4279e02972983fd3 0 1537636385000 6 connected
|
||||
# b39a684ad281f03c1befcd90048c503d95526645 172.20.0.4:6379@16379 slave 1ffa00413a5f75465e1bb5aaef551c38fb3db1f3 0 1537636386807 7 connected
|
||||
|
||||
# 测试集群的主从复制
|
||||
127.0.0.1:6379> set testkey 100
|
||||
# -> Redirected to slot [4757] located at 172.20.0.2:6379
|
||||
# OK
|
||||
|
||||
# 根据172.20.0.2查到对应节点为redis-node3,暂停该容器
|
||||
docker-compose pause redis-node3
|
||||
|
||||
# 然后再次读看是否能够读取到数据
|
||||
172.20.0.2:6379> get testkey
|
||||
# "100"
|
||||
|
||||
# 此时可以查看到集群节点状态,显示172.20.0.2和集群连接失败状态
|
||||
127.0.0.1:6379> cluster nodes
|
||||
```
|
||||
|
||||
### 2.5 创建带有密码的redis集群
|
||||
|
||||
实际使用中一般连接redis是需要密码授权的,添加密码很简单,创建集群前修改redis.conf配置和gems的redis客户端client.rb配置。
|
||||
|
||||
删除没有密码的集群容器,重新建一个集群,然后在原来基础上修改配置文件。
|
||||
|
||||
> docker-compose down
|
||||
|
||||
|
||||
|
||||
修改redis.conf配置
|
||||
|
||||
```bash
|
||||
masterauth 123456
|
||||
requirepass 123456
|
||||
```
|
||||
|
||||
|
||||
|
||||
进入redis-node1容器,修改redis客户端client.rb配置
|
||||
|
||||
```bash
|
||||
# 找出client.rb配置文件位置
|
||||
find / -name client.rb
|
||||
|
||||
# 在配置中添加密码
|
||||
# 把 :password => nil 改为 :password => 123456
|
||||
|
||||
# 创建集群
|
||||
/usr/local/etc/redis/redis-trib.rb create --replicas 1 172.20.0.2:6379 172.20.0.3:6379 172.20.0.4:6379 172.20.0.5:6379 172.20.0.6:6379 172.20.0.7:6379
|
||||
|
||||
# 带密码登录集群
|
||||
redis-cli -a 123456 -c
|
||||
```
|
||||
|
||||
### 2.6 创建集群中遇到的问题
|
||||
|
||||
> redis-trib.rb create –replicas 1 redis-node1:6379 redis-node2:6379 redis-node3:6379 redis-node4:6379 redis-node5:6379 redis-node6:6379
|
||||
|
||||
问题1:使用容器名创建去创建集群报错:”ERR Invalid node address specified”
|
||||
|
||||
> 答:redis-trib.rb 不支持域名或主机名,必须使用ip:port的方式
|
||||
|
||||
|
||||
|
||||
问题2:创建集群时报错:err slot 0 is already busy (redis::commanderror)
|
||||
|
||||
> 答:由于第一次创建集群没有成功,但还在待创建状态,需要将nodes.conf和dir里面的文件全部删除,如果是在docker创建的话,删除容器重新创建。
|
||||
127
数据库/Redis命令总结/README.md
Normal file
127
数据库/Redis命令总结/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# [01.redis安装](01.redis安装.md)
|
||||
- [1. 在主机上安装](01.redis安装.md/#1-在主机上安装)
|
||||
- [**(1) 修改后修改配置文件**](01.redis安装.md/#1-修改后修改配置文件)
|
||||
- [**(2) 设置开机启动**](01.redis安装.md/#2-设置开机启动)
|
||||
- [**(3) 将redis的bin命令添加到PATH**](01.redis安装.md/#3-将redis的bin命令添加到path)
|
||||
- [2. 在docker安装redis](01.redis安装.md/#2-在docker安装redis)
|
||||
- [**(1) 无持久化方式**](01.redis安装.md/#1-无持久化方式)
|
||||
- [**(2) 有持久化方式**](01.redis安装.md/#2-有持久化方式)
|
||||
- [**(3) 自定义redis配置**](01.redis安装.md/#3-自定义redis配置)
|
||||
|
||||
# [02.库和key操作命令](02.库和key操作命令.md)
|
||||
- [key操作命令](02.库和key操作命令.md/#key操作命令)
|
||||
- [set 设置key的值](02.库和key操作命令.md/#set-设置key的值)
|
||||
- [get 获取key的值](02.库和key操作命令.md/#get-获取key的值)
|
||||
- [del 删除key](02.库和key操作命令.md/#del-删除key)
|
||||
- [exists 判断key是否存在](02.库和key操作命令.md/#exists-判断key是否存在)
|
||||
- [type 获取key类型](02.库和key操作命令.md/#type-获取key类型)
|
||||
- [expire 设置key有效期](02.库和key操作命令.md/#expire-设置key有效期)
|
||||
- [tll 查看key有效期](02.库和key操作命令.md/#tll-查看key有效期)
|
||||
- [rename 重命名key](02.库和key操作命令.md/#rename-重命名key)
|
||||
- [renamenx 重命名不存在的key](02.库和key操作命令.md/#renamenx-重命名不存在的key)
|
||||
- [persist 设置key永久有效](02.库和key操作命令.md/#persist-设置key永久有效)
|
||||
- [move 把key移动到其他库](02.库和key操作命令.md/#move-把key移动到其他库)
|
||||
- [库操作命令](02.库和key操作命令.md/#库操作命令)
|
||||
- [dbsize 查看当前有多少个key](02.库和key操作命令.md/#dbsize-查看当前有多少个key)
|
||||
- [select 选择库](02.库和key操作命令.md/#select-选择库)
|
||||
- [flushdb 删除选中数据库中的key](02.库和key操作命令.md/#flushdb-删除选中数据库中的key)
|
||||
- [flushall 删除所有库的key](02.库和key操作命令.md/#flushall-删除所有库的key)
|
||||
|
||||
# [03.字符串类型操作](03.字符串类型操作.md)
|
||||
- [set 设置kv、效期、判断key是否存在](03.字符串类型操作.md#set-设置kv效期判断key是否存在)
|
||||
- [mset 一次性输入多个kv](03.字符串类型操作.md#mset-一次性输入多个kv)
|
||||
- [setrange 修改偏移字节值为valuev](03.字符串类型操作.md#setrange-修改偏移字节值为valuev)
|
||||
- [append 在key的值后面追加字符串](03.字符串类型操作.md#append-在key的值后面追加字符串)
|
||||
- [getrange 获取key值的部分内容](03.字符串类型操作.md#getrange-获取key值的部分内容)
|
||||
- [getset 设置新值返回旧值](03.字符串类型操作.md#getset-设置新值返回旧值)
|
||||
- [incr/decr 指定key的值加/减1](03.字符串类型操作.md#incrdecr-指定key的值加减1)
|
||||
- [incrby/decrby 指定key的值加/减number](03.字符串类型操作.md#incrbydecrby-指定key的值加减number)
|
||||
- [incrbyfloat 指定key的值加浮点数](03.字符串类型操作.md#incrbyfloat-指定key的值加浮点数)
|
||||
- [setbit 设置二进制位上的值](03.字符串类型操作.md#setbit-设置二进制位上的值)
|
||||
- [getbit 获取二进制位上的值](03.字符串类型操作.md#getbit-获取二进制位上的值)
|
||||
- [bitop 对多个key逻辑操作](03.字符串类型操作.md#bitop-对多个key逻辑操作)
|
||||
|
||||
# [04.链表类型操作](04.链表类型操作.md)
|
||||
- [lpush/rpush 在链表头/尾增加一个成员](04.链表类型操作.md/#lpushrpush-在链表头尾增加一个成员)
|
||||
- [lrange 获取链表成员](04.链表类型操作.md/#lrange-获取链表成员)
|
||||
- [lpop/rpop 弹出链表中头/尾的成员](04.链表类型操作.md/#lpoprpop-弹出链表中头尾的成员)
|
||||
- [lrem 删除链表成员](04.链表类型操作.md/#lrem-删除链表成员)
|
||||
- [lindex 获取链表索引对应的值](04.链表类型操作.md/#lindex-获取链表索引对应的值)
|
||||
- [llen key 获取链表成员个数](04.链表类型操作.md/#llen-key-获取链表成员个数)
|
||||
- [linsert 在链表中指定位置插入成员](04.链表类型操作.md/#linsert-在链表中指定位置插入成员)
|
||||
- [blpop/brpop 一直等待弹出头/尾成员](04.链表类型操作.md/#blpopbrpop-一直等待弹出头尾成员)
|
||||
|
||||
# [05.无序集合操作](05.无序集合操作.md)
|
||||
- [sadd 往集合添加成员](05.无序集合操作.md/#sadd-往集合添加成员)
|
||||
- [srem 删除集合成员](05.无序集合操作.md/#srem-删除集合成员)
|
||||
- [spop 随机删除集合一个成员](05.无序集合操作.md/#spop-随机删除集合一个成员)
|
||||
- [srandmember 随机获取集合成员](05.无序集合操作.md/#srandmember-随机获取集合成员)
|
||||
- [smembers 获取集合所有的成员](05.无序集合操作.md/#smembers-获取集合所有的成员)
|
||||
- [sismember 判断成员是否存在集合中](05.无序集合操作.md/#sismember-判断成员是否存在集合中)
|
||||
- [scard 获取集合成员的个数](05.无序集合操作.md/#scard-获取集合成员的个数)
|
||||
- [smove 把一个集合中成员移动到另一个集合](05.无序集合操作.md/#smove-把一个集合中成员移动到另一个集合)
|
||||
- [sunion 获取多个集合的并集](05.无序集合操作.md/#sunion-获取多个集合的并集)
|
||||
- [sdiff 获取多个集合的差集](05.无序集合操作.md/#sdiff-获取多个集合的差集)
|
||||
- [sinterstore 获取多个集合的交集并储存](05.无序集合操作.md/#sinterstore-获取多个集合的交集并储存)
|
||||
|
||||
# [06.有序集合操作](06.有序集合操作.md)
|
||||
- [1. zadd 往有序集合添加成员](06.有序集合操作.md/#1-zadd-往有序集合添加成员)
|
||||
- [2. zrange 按名次取成员](06.有序集合操作.md/#2-zrange-按名次取成员)
|
||||
- [3. zrangebyscore 按分数取成员](06.有序集合操作.md/#3-zrangebyscore-按分数取成员)
|
||||
- [4. zscore 获取指定成员的分数](06.有序集合操作.md/#4-zscore-获取指定成员的分数)
|
||||
- [5. zcount 计算分数区间成员个数](06.有序集合操作.md/#5-zcount-计算分数区间成员个数)
|
||||
- [6. zrank/zrevrank 获取成员升序/降序的排名](06.有序集合操作.md/#6-zrankzrevrank-获取成员升序降序的排名)
|
||||
- [7. zrem 删除有序集合成员](06.有序集合操作.md/#7-zrem-删除有序集合成员)
|
||||
- [8. zremrangebyrank 按排名删除成员](06.有序集合操作.md/#8-zremrangebyrank-按排名删除成员)
|
||||
- [9. zremrangebyscore 按分数删除成员](06.有序集合操作.md/#9-zremrangebyscore-按分数删除成员)
|
||||
- [10. zinterstore 求交集再计算](06.有序集合操作.md/#10-zinterstore-求交集再计算)
|
||||
- [11. zunionstore 求并集再计算](06.有序集合操作.md/#11-zunionstore-求并集再计算)
|
||||
|
||||
# [07.哈希数据类操作](07.哈希数据类操作.md)
|
||||
- [1. hset 设置哈希field域的值](07.哈希数据类操作.md/#1-hset-设置哈希field域的值)
|
||||
- [2. hmset 设置哈希多个field域的值](07.哈希数据类操作.md/#2-hmset-设置哈希多个field域的值)
|
||||
- [3. hget 获取field域的值](07.哈希数据类操作.md/#3-hget-获取field域的值)
|
||||
- [4. hmget 获取多个field域的值](07.哈希数据类操作.md/#4-hmget-获取多个field域的值)
|
||||
- [5. hgetall 获取所有field域和值](07.哈希数据类操作.md/#5-hgetall-获取所有field域和值)
|
||||
- [6. hlen 获取field的数量](07.哈希数据类操作.md/#6-hlen-获取field的数量)
|
||||
- [7. hdel 删除field域](07.哈希数据类操作.md/#7-hdel-删除field域)
|
||||
- [8. hexists 判断field域是否存在](07.哈希数据类操作.md/#8-hexists-判断field域是否存在)
|
||||
- [9. hincrby 使field域的值加上整数](07.哈希数据类操作.md/#9-hincrby-使field域的值加上整数)
|
||||
- [10. hincrbyfloat 使field域的值加上浮点数](07.哈希数据类操作.md/#10-hincrbyfloat-使field域的值加上浮点数)
|
||||
- [11. hkeys 获取所有所有field域的名字](07.哈希数据类操作.md/#11-hkeys-获取所有所有field域的名字)
|
||||
- [12. kvals 获取所有所有field域的值](07.哈希数据类操作.md/#12-kvals-获取所有所有field域的值)
|
||||
|
||||
# [08.经纬度数据操作](08.经纬度数据操作.md)
|
||||
- [1. geoadd 添加地理位置信息](08.经纬度数据操作.md/#1-geoadd-添加地理位置信息)
|
||||
- [2. geopos 查询位置的坐标](08.经纬度数据操作.md/#2-geopos-查询位置的坐标)
|
||||
- [3. geodist 查询位置距离](08.经纬度数据操作.md/#3-geodist-查询位置距离)
|
||||
- [4. georadius 查询某点的附近点](08.经纬度数据操作.md/#4-georadius-查询某点的附近点)
|
||||
- [5. georadiusbymember 查询某位置距离的附近点](08.经纬度数据操作.md/#5-georadiusbymember-查询某位置距离的附近点)
|
||||
- [6. geohash 查询位置GEOHASH编码](08.经纬度数据操作.md/#6-geohash-查询位置geohash编码)
|
||||
|
||||
# [09.事务](09.事务.md)
|
||||
- [1. 事务命令](09.事务.md/#1-事务命令)
|
||||
- [2. 乐观锁](09.事务.md/#2-乐观锁)
|
||||
|
||||
# [10.频道发布与订阅](10.频道发布与订阅.md)
|
||||
- [1. publish 发布频道](10.频道发布与订阅.md/#1-publish-发布频道)
|
||||
- [2. subscribe 订阅指定频道](10.频道发布与订阅.md/#2-subscribe-订阅指定频道)
|
||||
- [3. psubscribe 订阅已匹配频道](10.频道发布与订阅.md/#3-psubscribe-订阅已匹配频道)
|
||||
|
||||
# [11.redis持久化和导入导出数据库](11.redis持久化和导入导出数据库.md)
|
||||
- [1. redis持久化](11.redis持久化和导入导出数据库.md/#1-redis持久化)
|
||||
- [1.1. rdb快照持久化](11.redis持久化和导入导出数据库.md/#11-rdb快照持久化)
|
||||
- [1.2. aof日志持久化](11.redis持久化和导入导出数据库.md/#12-aof日志持久化)
|
||||
- [2. 导入和导出数据库](11.redis持久化和导入导出数据库.md/#2-导入和导出数据库)
|
||||
|
||||
# [12.redis应用示例](12.redis应用示例.md)
|
||||
- [1. 统计活跃用户](12.redis应用示例.md/#1-统计活跃用户)
|
||||
- [2. 搭建高可用redis集群](12.redis应用示例.md/#2-搭建高可用redis集群)
|
||||
- [1. 常见redis集群](12.redis应用示例.md/#1-常见redis集群)
|
||||
- [2. 单机版redis集群](12.redis应用示例.md/#2-单机版redis集群)
|
||||
- [2.1 修改redis配置文件](12.redis应用示例.md/#21-修改redis配置文件)
|
||||
- [2.2 重新打包redis镜像](12.redis应用示例.md/#22-重新打包redis镜像)
|
||||
- [2.3 编辑docker-compose.yml文件](12.redis应用示例.md/#23-编辑docker-composeyml文件)
|
||||
- [2.4 创建redis集群](12.redis应用示例.md/#24-创建redis集群)
|
||||
- [2.5 创建带有密码的redis集群](12.redis应用示例.md/#25-创建带有密码的redis集群)
|
||||
- [2.6 创建集群中遇到的问题](12.redis应用示例.md/#26-创建集群中遇到的问题)
|
||||
Reference in New Issue
Block a user