查看git日志的命令

查看日志

1
git log

查看近两次提交的日志

1
git log -2

查看近两周提交的日志

1
git log --since=2.weeks

查看某一天提交的日志

1
git log --since=2019--01--14

查看最近两年三个月前天3分钟的日志

1
git log --since="2 years 1 day 3 minutes ago"

log查看分支图

1
git log --oneline --all --graph

显示提交的差异

1
git log --patch

查看某一段时间内的提交记录

1
git log --since="2024-1-07" --until="2024-1-17" --pretty= --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "添加的行数:%s, 删除的行数:%s, 总行数:%s\n", add, subs, loc }' -

结果是

1
添加的行数:142, 删除的行数:100, 总行数:42

git问题处理


Q1

fatal: remote origin already exists.

1
git remote rm origin

Q2

取消文件跟踪

1
git rm -r --cached [filename]

Q3

fatal: refusing to merge unrelated histories

1
git pull origin master --allow-unrelated-histories

Q4

git log查看分支图

1
git log --oneline --decorate --graph --all

Q5

查看跟踪的文件

1
git ls-files

Q6

Please move or remove them before you can merge

1
git reset --hard HEAD

JavaScript添加点击事件

方法一 使用 onclick 事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>

<body>
<button id="mybutton">点我</button>
</body>
<script>
var newButton = document.getElementById("mybutton");
// 绑定 oncclick 事件

newButton.onclick = function () {
alert("onclick");
}
</script>

</html>

运行结果如下

运行结果

方法二 使用 click 方法

click 方法,模拟鼠标点击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>

<body>
<button id="mybutton">点我</button>
</body>
<script>
var newButton = document.getElementById("mybutton");
newButton.onclick = function () {
alert("onclick");
}
// 直接打开页面就会执行 click 方法,同时会触发上面的 onclick 事件
// 注意下面的语句不是绑定事件 而是 模拟点击鼠标的动作

newButton.click(alert("click"))
</script>

</html>

模拟点击鼠标

同时会触发绑定的 onclick 事件

方法三 使用 addEventListener 来绑定事件 (推荐使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>

<body>
<button id="mybutton">点我</button>
</body>
<script>
var newButton = document.getElementById("mybutton");
// 推荐使用这种方法
newButton.addEventListener("click",function () {
alert("addEventListener");

}, false);
</script>

</html>

运行结果:

使用addEventListener()

为什么使用这种方法,以下来自 MDN

addEventListener() 是 W3C DOM 规范中提供的注册事件监听器的方法。它的优点包括:

  • 它允许给一个事件注册多个监听器。 特别是在使用AJAX库,JavaScript模块,或其他需要第三方库/插件的代码。
    • 它提供了一种更精细的手段控制listener 的触发阶段。(即可以选择捕获或者冒泡)。
    • 它对任何 DOM 元素都是有效的,而不仅仅只对 HTML 元素有效。

新建一个Vue项目

以下操作步骤基于 Vue CLI 3.0 (@vue/cli)

0、安装Vue脚手架

使用下面的命令全局安装 Vue CLI

1
npm install -g @vue/cli

安装完成之后,可以使用下面的命令来检查是否安装正确

1
vue -version

1. 新建一个项目

使用下面的命令新建一个名为 vue-playlist 的项目

1
vue create vue-playlist

创建成功之后会提示安装的组件,这里可以选择默认

选择默认

也可以手动选择组件

手动选择组件

安装成功之后,使用下面的命令进入目录

1
cd vue-playlist

然后运行下面的命令启动程序

1
npm run serve

启动成功后,在 http://localhost:8080 即可看到

访问成功

Vuex基础

Vuex 是一个专门为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件状态。

也就是将 Vue.js 程序中各个页面公用的数据和获取、改变这些数据的方法抽离出来,方便各个页面调用,以及页面之间的数据传输。

下面通过一个例子来讲解Vuex

我们首先创建一个Vue工程

我们假设有两个富豪榜,这两个富豪榜分属两个界面,通过组件注册,在一个主界面。

一、使用 props 属性传递参数

页面结构如下:

目录结构

我们在父页面 App.vuedata 属性中加入人员列表,并引入两个子页面,通过 v-bind 指令将 data 传递给子页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div id="app">
<!-- 将 data 元素传递给子页面 -->
<salary-list-one v-bind:sendedSalaryList="salaryList"></salary-list-one>
<salary-list-two v-bind:sendedSalaryList="salaryList"></salary-list-two>
</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
export default {
name: "app",
data() {
return {
salaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
};
},
components: {
'salary-list-one': salarylist1,
'salary-list-two': salarylist2
}
};
</script>
<style scoped>
</style>

子页面通过 props 属性接收父页面传递过来的参数,并展示出来。

salarylist1.vue 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
<div id="salary-list-fisrt">
<h2>财富榜</h2>
<ol>
// 通过 v-for 命令将其展示出来

<li v-for="salary in sendedSalaryList">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
</div>
</template>
<script>
export default {
name: "salary-listfirst",
// 通过 props 属性接收父页面传来的参数

props: {
sendedSalaryList: {
type: Array,
required: true
}
}

}
</script>
<style>

</style>

salarylist2.vue 代码和上面的代码基本相似

运行结果如下:

运行结果

二、使用 Vuex 简化数据传递

虽然页面之间可以使用 props, $emit 等传递参数,但是这种参数的传递会面临以下问题

问题一 :多个视图依赖于同一状态。

问题二 :来自不同视图的行为需要变更同一状态。

对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。

对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?

在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!

另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护

如果之前没有安装 vuex,使用下面的命令安装

1
npm install vuex --save

在项目根目录下新建 store/store.js 文件,这个文件中保存的就是这个应用中需要共享的内容, 而且整个应用中只有一个。

main.js 文件中引入 vuex

1
2
3
4
5
6
7
8
9
10
11
import Vue from 'vue'
import App from './App.vue'
import {store} from './store/store'


Vue.config.productionTip = false

new Vue({
store:store,
render: h => h(App),
}).$mount('#app')

1. State

state 类似于 Vue 实例中的 data 属性,不同的是 state 是共享的。

现在将刚才 App.vue 中的 data 保存在store.js 中,将 App.vue 中保存的数据移除。

现在,两个财富榜都没有了数据,如图:

没有数据

现在改为从 store 请求数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
state: {
storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
}
});

在 财富榜2 中引入获取 store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<!--salarylist2.vue -->
<div id="salary-list-fisrt">
<h2>财富榜2</h2>
<ol>
<li v-for="salary in salaryList ">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
</div>
</template>
<script>
export default {
name: "salary-list-first",
computed: {
salaryList() {
// 通过 computed 属性,获取到 store.js 中的数据,并返回

return this.$store.state.storeSalaryList;
}
}
}
</script>
<style>

</style>

在 App.vue 中去掉 v-bind 指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<template>
<div id="app">
<salary-list-one ></salary-list-one>
<salary-list-two ></salary-list-two>
</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
export default {
name: "app",
data() {
return {

};
},
components:{
'salary-list-one':salarylist1,
'salary-list-two':salarylist2
}
};
</script>
<style scoped>
</style>

运行结果如下:

财富榜2有数据

如果在 salarylist1.vue 中也加入上面的 store 引用,就可以连个财富榜就可以全部展示。

2.getter

在一些情况下,当获取到 state 的数据之后,我们希望进行一些加工处理再进行展示。

现在,我们将上面每个人的工资翻倍,再增加 美元($)符号。

修改 salarylist1.vuesalarylist2.vue 代码,在 computed 属性中增加,doubleSalary 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<template>
<div id="salary-list-fisrt">
<h2>财富榜</h2>
<ol>
<li v-for="salary in doubleSalary">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
</div>
</template>
<script>
export default {
computed: {
salaryList() {
return this.$store.state.storeSalaryList;
},
// doubleSalary 属性对每个人 state 的数据加工后进行返回
doubleSalary() {
var afterDoubleSalary =
this.$store.state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
}
},

}
</script>
<style>

</style>

运行结果如下

工资翻倍

以上的代码虽然对 state 属性进行了加工之后返回,但是有一定的局限性,如果有100个页面都要这样处理,是不是就要将 doubleSalary 属性写100遍?这样显然是不合理的,为了解决这个问题,可以 doubleSalary 属性写进 store.js 作为一个 getter 方法。

store.js 中增加一个getter 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
state: {
storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
// 增加一个 getter 方法,用于返回加工后的 工资
doubleSalaryGetter: (state) => {
var afterDoubleSalary =
state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
}
}
});

修改 salarylist1.vuesalarylist2.vue 代码,在 computed 属性中增加,doubleSalaryByGetter 属性,在这个属性中,调用 store.js 中的 getter 返回结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div id="salary-list-fisrt">
<h2>财富榜</h2>
<ol>
<li v-for="salary in doubleSalaryByGetter">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
</div>
</template>
<script>
export default {
computed: {
salaryList() {
return this.$store.state.storeSalaryList;
},
// 在这里调用 store.js 中的方法。
doubleSalaryByGetter() {
return this.$store.getters.doubleSalaryGetter;
}
},

}
</script>
<style>
</style>

工资翻倍

如果我们 还有一个需求:计算工资总额,可以在 getter 新增加一个 totalSalary 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
state: {
storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
doubleSalaryGetter: (state) => {
var afterDoubleSalary = state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
},
// 在这里增加一个 计算工资总额的方法

totalSalary: (state) => {
var sum = 0
state.storeSalaryList.forEach(element => {
sum += element.salaryAmount;
});
return sum*2;
}
}
});

修改 salarylist1.vue 代码,在 computed 属性中增加,totalSalaryByGetter 属性,在这个属性中,调用 store.js 中的 getter 返回结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div id="salary-list-fisrt">
<h2>财富榜</h2>
<ol>
<li v-for="salary in doubleSalaryByGetter">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
<span>工资总额是: {{totalSalaryByGetter}}</span>
</div>
</template>
<script>
export default {
computed: {
salaryList() {
return this.$store.state.storeSalaryList;
},
doubleSalaryByGetter() {
return this.$store.getters.doubleSalaryGetter;
},
// 增加获取工资总额的方法
totalSalaryByGetter() {
return this.$store.getters.totalSalary;
}
},

}
</script>
<style>
</style>

工资总额

我们通过在当前页面调用 store.jsgetter 方法,可以返回想要的结果。但是发现,在每个页面中,都要写调用写一个方法来调用 getter 也不是很方便。

Vuex 为我们提供了一个 mapGetters 辅助函数,可以用来获取getter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<template>
<div id="salary-list-fisrt">
<h2>财富榜2</h2>
<!--
<ol>
<li v-for="salary in doubleSalaryGetter ">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
<span>工资总额是:{{totalSalary}}</span>
-->
<ol>
<li v-for="salary in myDoubleSalaryGetter ">
{{salary.name}}的工资是:{{salary.salaryAmount}}
</li>
</ol>
<span>工资总额是:{{myTotalSalary}}</span>
</div>
</template>
<script>
import {
mapGetters
} from 'vuex';
export default {
name: "salary-list-two",

computed: {
salaryList() {
return this.$store.state.storeSalaryList;
},
doubleSalaryByGetter() {
return this.$store.getters.doubleSalaryGetter;
},
/**
...mapGetters(
// 注意这里是个数组
[
'doubleSalaryGetter','totalSalary'
]
)*/

// ...mapGetters的另一种写法,通过这种方法可以给 getter 起别名
...mapGetters(
// 注意这里是一个对象
{
myDoubleSalaryGetter: 'doubleSalaryGetter',
myTotalSalary: 'totalSalary'

})
}
}
</script>
<style>
</style>

运行结果如下:

运行结果

3.mutations

现在我们添加一个按钮,这个按钮的作用是,给 state 中的 storeSalaryList 增加工资,首先可以使用一个方法来改变 state

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<template>
<div id="app">
<salary-list-one></salary-list-one>
<salary-list-two></salary-list-two>
<button @click="moreSalary()">加工资</button>
<button @click="getAmount()">显示工资</button>

</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
export default {
name: "app",
data() {
return {

};
},
components: {
'salary-list-one': salarylist1,
'salary-list-two': salarylist2
},
methods: {
// 这个方法用来只增加工资

moreSalary() {
this.$store.state.storeSalaryList.forEach(element => {
element.salaryAmount += 100;
});
},
// 这个方法用来显示 state 的工资内容

getAmount() {
this.$store.state.storeSalaryList.forEach(element => {
console.log(element.salaryAmount);
})
}
}
};
</script>
<style scoped>

</style>

运行结果:

分别点击 加工资显示工资 按钮

加工资

(注:这里之所以点击一下加工资按钮每个人的工资增加 200 是因为,在两个子页面用的属性是 doubleSalaryGetter),由此可见 state 可见发生了变化。

但是直接调用方法,无法记录 store 中各种属性的变化,如果用 mutatios ,就可以使用 vue 的开发工具 Vue.js devtools,可以直观地观察 store 中的属性值变化。

store.js 增加一个 mutations 节点,并增加一个 moreSalaryMutation 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
state: {
storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
doubleSalaryGetter: (state) => {
var afterDoubleSalary = state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
},
totalSalary: (state) => {
var sum = 0
state.storeSalaryList.forEach(element => {
sum += element.salaryAmount;
});
return sum * 2;
}
},
mutations: {
// 这个方法用来更改 state

moreSalaryMutation: (state) => {
state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})
}
}
});

现在再增加一个按钮,使用mutations增加工资

AppVue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<div id="app">
<salary-list-one></salary-list-one>
<salary-list-two></salary-list-two>
<button @click="moreSalary()">加工资</button>
<button @click="getAmount()">显示工资</button>


<button @click="moreSalaryByMutatios()">使用matatios增加工资</button>

</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
export default {
name: "app",
data() {
return {

};
},
components: {
'salary-list-one': salarylist1,
'salary-list-two': salarylist2
},
methods: {
moreSalary() {
this.$store.state.storeSalaryList.forEach(element => {
element.salaryAmount += 100;
});
},
getAmount() {
this.$store.state.storeSalaryList.forEach(element => {
console.log(element.salaryAmount);
})
},
// 这个方法调用 commit 来更改 state

moreSalaryByMutatios() {
this.$store.commit("moreSalaryMutation");
}
}
};
</script>
<style scoped>

</style>

运行结果如下:

可以使用vue-tools观察store

值得注意的是,使用 commit 来更改 state ,我们可以借助Vue.js devtools很清晰地观测 state 的变化。

在Vuex的官方文档中有一句话

The only way to actually change state in a Vuex store is by committing a mutation.

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

在上面的例子中,我们发现不仅 commit 可以修改 state的值,通过一个普通的函数调用 moreSalary 方法也可以更改 state 的值,这好像和文档描述不相符。但是,如果在 store 创建的时候,申明为严格模式,再次调用moreSalary方法,就会报错。

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
// 在这里增加 严格模式
strict:true,

state: {

storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
doubleSalaryGetter: (state) => {
var afterDoubleSalary = state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
},
totalSalary: (state) => {
var sum = 0
state.storeSalaryList.forEach(element => {
sum += element.salaryAmount;
});
return sum * 2;
}
},
mutations: {
moreSalaryMutation: (state) => {
state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})
}
}
});

再次点击加工资,就会出现报错

严格模式

4. actions

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。

    • Action 可以包含任意异步操作。

现在我们将点击 使用matatios增加工资 改为5秒后产生效果。
store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
strict:true,

state: {

storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
doubleSalaryGetter: (state) => {
var afterDoubleSalary = state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
},
totalSalary: (state) => {
var sum = 0
state.storeSalaryList.forEach(element => {
sum += element.salaryAmount;
});
return sum * 2;
}
},
mutations: {
moreSalaryMutation: state => {
// 五秒之后加工资。

setTimeout(function(){
state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})
},5000)
/*/state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})*/
}
}
});

运行结果如下,等待5秒之后,虽然页面数值发生了变化,但是Vue.js dev-tools 却没有发生变化,而且还报错了。

没有变化

报错如下

报错

对此 Evan You 亲自给出了解释

给出解释

store.js 中增加 actions 节点,并增加一个 moreSalaryAction 方法

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
strict:true,

state: {

storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
doubleSalaryGetter: (state) => {
var afterDoubleSalary = state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
},
totalSalary: (state) => {
var sum = 0
state.storeSalaryList.forEach(element => {
sum += element.salaryAmount;
});
return sum * 2;
}
},
mutations: {
moreSalaryMutation: state => {
// setTimeout(function(){
state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})
// },5000)
/*/state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})*/
}
},
actions:{
// 这个方法调用上面的 mutations 里边的 moreSalaryMutation
// 点击3秒之后,运行mutation

moreSalaryAction:(context)=>{
setTimeout(function() {
context.commit("moreSalaryMutation");

},3000)

}
}
});

在 App.vue 中增加一个按钮 和 方法,点击按钮通过方法访问action

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<template>
<div id="app">
<salary-list-one></salary-list-one>
<salary-list-two></salary-list-two>
<button @click="moreSalary()">加工资</button>
<button @click="getAmount()">显示工资</button>


<button @click="moreSalaryByMutatios()">使用matatios增加工资</button>
<!-- 增加方法来调用 action -->

<button @click="moreSalaryByActions()">使用actions增加工资</button>

</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
export default {
name: "app",
data() {
return {

};
},
components: {
'salary-list-one': salarylist1,
'salary-list-two': salarylist2
},
methods: {
moreSalary() {
this.$store.state.storeSalaryList.forEach(element => {
element.salaryAmount += 100;
});
},
getAmount() {
this.$store.state.storeSalaryList.forEach(element => {
console.log(element.salaryAmount);
})
},
moreSalaryByMutatios() {
this.$store.commit("moreSalaryMutation");
//this.$store.dispatch("moreSalaryAction");
},
moreSalaryByActions() {
// 通过此方法调用action

this.$store.dispatch("moreSalaryAction");
}

}
};
</script>
<style scoped>

</style>

点击后我们发现 dev-tools 左边的方法记录和右边的 state 的值同时 改变,而且没有报错

没有报错

Action中也可以传递参数。

我们设置一个工资增加的数目,通过 playload 来进行传递

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<template>
<div id="app">
<salary-list-one></salary-list-one>
<salary-list-two></salary-list-two>
<button @click="moreSalary()">加工资</button>
<button @click="getAmount()">显示工资</button>


<button @click="moreSalaryByMutatios()">使用matatios增加工资</button>
// 设置每次增加的数量

<button @click="moreSalaryByActions(256)">使用actions增加工资</button>

</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
export default {
name: "app",
data() {
return {

};
},
components: {
'salary-list-one': salarylist1,
'salary-list-two': salarylist2
},
methods: {
moreSalary() {
this.$store.state.storeSalaryList.forEach(element => {
element.salaryAmount += 100;
});
},
getAmount() {
this.$store.state.storeSalaryList.forEach(element => {
console.log(element.salaryAmount);
})
},
moreSalaryByMutatios() {
this.$store.commit("moreSalaryMutation");
//this.$store.dispatch("moreSalaryAction");
},
// 传递参数

moreSalaryByActions(amount) {

this.$store.dispatch("moreSalaryAction", amount);
}

}
};
</script>
<style scoped>

</style>

store.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
strict:true,

state: {

storeSalaryList: [{
name: "马云",
salaryAmount: 1000
},
{
name: "马化腾",
salaryAmount: 900
},
{
name: "李彦宏",
salaryAmount: 800
}
]
},
getters: {
doubleSalaryGetter: (state) => {
var afterDoubleSalary = state.storeSalaryList.map(salary => {
return {
name: salary.name,
salaryAmount: salary.salaryAmount * 2 + " " + "$"

};
});
return afterDoubleSalary;
},
totalSalary: (state) => {
var sum = 0
state.storeSalaryList.forEach(element => {
sum += element.salaryAmount;
});
return sum * 2;
}
},
mutations: {
moreSalaryMutation: (state,amount) => {
// setTimeout(function(){
state.storeSalaryList.forEach(element=>{
element.salaryAmount += amount;
})
// },5000)
/*/state.storeSalaryList.forEach(element=>{
element.salaryAmount += 100;
})*/
}
},
actions:{
// 传递参数

moreSalaryAction:(context,amount)=>{
setTimeout(function() {
context.commit("moreSalaryMutation",amount);

},3000)

}
}
});

运行结果:工资以指定数值增减, 通过vue-tools 可以观测到 playload的变化

指定数值

类似于 mapGetters, 可以调用 mapActions 来应对有很多 action 时的情况

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<template>
<div id="app">
<salary-list-one></salary-list-one>
<salary-list-two></salary-list-two>
<button @click="moreSalary()">加工资</button>
<button @click="getAmount()">显示工资</button>


<button @click="moreSalaryByMutatios()">使用matatios增加工资</button>
<button @click="moreSalaryByActions(256)">使用actions增加工资</button>

<!--
<button @click="moreSalaryAction(256)">使用mapActions增加工资</button>
-->
<button @click="myMoreSalaryAction(256)">使用mapActions增加工资</button>

</div>
</template>
<script>
import salarylist1 from './components/salarylist1';
import salarylist2 from './components/salarylist2';
import {
mapActions
} from 'vuex'

export default {
name: "app",
data() {
return {

};
},

components: {
'salary-list-one': salarylist1,
'salary-list-two': salarylist2
},
methods: {
moreSalary() {
this.$store.state.storeSalaryList.forEach(element => {
element.salaryAmount += 100;
});
},
getAmount() {
this.$store.state.storeSalaryList.forEach(element => {
console.log(element.salaryAmount);
})
},
moreSalaryByMutatios() {
this.$store.commit("moreSalaryMutation");
//this.$store.dispatch("moreSalaryAction");
},
moreSalaryByActions(amount) {
this.$store.dispatch("moreSalaryAction", amount);
},
...mapActions([

// `mapActions` 也支持载荷:
'moreSalaryAction' // 将 `this.moreSalaryAction(amount)` 映射为 `this.$store.dispatch('moreSalaryAction', amount)`
]),
// mapActions 的 第二种写法
...mapActions({
myMoreSalaryAction:'moreSalaryAction'
})

}
};
</script>
<style scoped>

</style>

mapactions

ES6箭头函数

箭头函数是ES6版本的JavaScript新特性,没有自己的this, arguments。箭头函数更适合那些需要匿名函数的地方,并且它们不能用作构造函数。

一、更简洁的函数

下面是一个箭头函数的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 定义一个数组
var carBrands = [
"BMW",
"BENZ",
"REAULT",
"HONDA"
]
/**
* 下面三种调用方式的作用是一样的
*/
carBrands.map(function (carBrand) {
console.log(carBrand.length);
})


carBrands.map((carBrand) => {
console.log(carBrand.length)
});

carBrands.map(carBrand => console.log(carBrand.length))
// 如果函数箭头不需要参数或需要多个参数,就使用圆括号代表参数部分
var f = () => 5;
// 等同于
var f = function() {
return 5;
};


// 多个参数的情况
var sub = (num1, num2) => num1 - num2;
// 等同于
var sub = function(num1, num2) {
return num1 - num2;
}

// 由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加括号
var student = () =>({id:"12312", name:"张三"})

// 箭头函数让判断变得更加简洁
const isEven = n => n % 2 == 0;
const square = n => n * n;

二、不绑定this

箭头函数出现之前,每个新定义的函数都有它自己的 this值(在构造函数的情况下是一个新对象,在严格模式的函数调用中为 undefined,如果该函数被作为“对象方法”调用则为基础对象等)。This被证明是令人厌烦的面向对象风格的编程。

1
2
3
4
5
6
7
8
9
10
11
12
function Person() {
// Person() 构造函数定义 `this`作为它自己的实例.
this.age = 0;

setInterval(function growUp() {
// 在非严格模式, growUp()函数定义 `this`作为全局对象,
// 与在 Person()构造函数中定义的 `this`并不相同.
this.age++;
}, 1000);
}

var p = new Person();

在ECMAScript 3/5中,通过将this值分配给封闭的变量,可以解决this问题。

1
2
3
4
5
6
7
8
9
function Person() {
var that = this;
that.age = 0;

setInterval(function growUp() {
// 回调引用的是`that`变量, 其值是预期的对象.
that.age++;
}, 1000);
}

或者,可以创建绑定函数,以便将预先分配的this值传递到绑定的目标函数(上述示例中的growUp()函数)。

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

1
2
3
4
5
6
7
8
9
function Person(){
this.age = 0;

setInterval(() => {
this.age++; // |this| 正确地指向person 对象
}, 1000);
}

var p = new Person();

vue-vuerouter-basic

VueRouter Basic

一个vuerouter的例子,这里引入了vue,vue-router,app.js需要自己编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>basic</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="../vue.min.js"></script>
<script src="../vue-router.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script src="app.js"></script>
</html>

app.js 文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 1.定义几个component
const Home = {
template: `<div>home</div>`
}
const Foo = {
template: '<div>foo</div>'
}
const Bar = {
template: `<div>bar</div>`
}
const Unicoede = {
template: `<div>unicode</div>`

}
// 2.创建一个 router 实例
const router = new VueRouter({
routes: [
{ path: "/", component: Home },
{ path: "/foo", component: Foo },
{ path: "/bar", component: Bar },
{ path: '/é', component: Unicoede }
]
});


// 3.创建一个Vue实例
new Vue({
// 引入前一步创建的vue实例
router,
template: `
<div id="app-content">
<h1>Basic</h1>
<ul>
<li>
<router-link to="/">/</router-link>
</li>
<li>
<router-link to="/foo">/foo</router-link>
</li>

<li>
<router-link to="/bar">/bar</router-link>
</li>
<!-- router-link 可以渲染成其他的组件,这里就渲染成了li,虽然中间包裹的 <a> 标签指向 /bar,
但实际运行时 依然是连接到foo-->

<router-link tag="li" to="/foo" :event="['mousedown','touchstart']">
<a>/bar</a>
</router-link>
</ul>
<router-view class="view"></router-view>
</div>
`
}).$mount('#app');

head first 设计模式读书笔记-观察者模式

观察者模式

需求

有一个气象站,会随时更新气象信息。同时,有各种显示器,会展示这些气象信息。现在需要气象站每次更新数据时可以将新的数据及时推送到显示屏。

代码实现

我们现在有一个 WeatherData(气象站)对象,负责产生新的天气数据,还有一个 CurrentConditionsDisplay(显示屏)对象,用来显示最新的气象数据,这个对象也就是观察者。观察者在气象站注册 (registerObserver) 之后,气象站如果有最新的数据就会及时提醒 ( notifyObservers ) 已经注册的观察者,及时更新显示。如果这个显示屏不想再接收到这个最新的气象数据,气象站可以将这个显示屏从气象站的通知列表中删除 ( removeObserver ) ,下次气象站有数据更新时,将不会通知这个显示屏。

  1. 定义一个借口,规定气象站应该有的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 这个接口规定,气象站有哪些功能
*/
public interface Subject {
/**
* 注册观察者
*
* @param observer
*/
void registerObserver(Observer observer);

/**
* 移除观察者
*
* @param observer
*/
void removeObserver(Observer observer);

/**
* 通知观察者
*/
void notifyObservers();

}

  1. 实现一个气象站
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* 定义这个气象站
*/
public class WeatherData implements Subject {
/**
* 注册的观察者列表
*/
private ArrayList<Observer> observers;
/**
* 温度
*/
private float temperature;
/**
* 湿度
*/
private float humidity;
/**
* 气压
*/
private float pressure;

public WeatherData() {

this.observers = new ArrayList<>();

}
/**
* 注册观察者
*
* @param observer
*/
@Override
public void registerObserver(Observer observer) {
observers.add(observer);

}

/**
* 移除观察者
*
* @param observer
*/
@Override
public void removeObserver(Observer observer) {
observers.remove(observers.indexOf(observer));
}


/**
* 提醒观察者
*/
@Override
public void notifyObservers() {
if (observers != null && observers.size() > 0) {
observers.stream().forEach(o -> o.update(temperature, humidity, pressure));
}

}

/**
* 调用提醒方法
*/
public void measurementsChanged() {
notifyObservers();
}

/**
* 气象站设置新的数据,并通知观察者(显示屏)
*
* @param temperature
* @param humidity
* @param pressure
*/
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
  1. 定义两个接口,规定一个显示屏应该有的功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /**
    * 规定观察者应该有更新自身数据的功能
    */
    public interface Observer {
    void update(float temperature, float humidity, float pressure);
    }
    /**
    * 规定观察者应该有显示的功能
    */
    public interface DisplayElement {
    void display();
    }

  2. 定义两个显示屏,分别显示现在的天气状况和明天的天气状况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    /**
    * 实时气温显示屏
    */
    public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private float temperature;
    private float humidity;
    private float pressure;
    WeatherData weatherData;

    /**
    * 每次生成一个显示屏,就向气象站注册
    *
    * @param weatherData
    */
    public CurrentConditionsDisplay(WeatherData weatherData) {
    this.weatherData = weatherData;
    weatherData.registerObserver(this);
    }

    @Override
    public void display() {
    System.out.println("现在的天气是: " + temperature + " ℃,相对湿度是:
    " + humidity + "%,大气压是:" + pressure + "kPa");
    }


    /**
    * 更新显示屏显示的数据
    *
    * @param temperature
    * @param humidity
    * @param pressure
    */
    @Override
    public void update(float temperature, float humidity, float pressure) {
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    display();
    }
    }

    /**
    * 天气预报显示屏
    */
    public class ForecastDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private float pressure;
    WeatherData weatherData;

    public ForecastDisplay(WeatherData weatherData) {
    this.weatherData = weatherData;
    weatherData.registerObserver(this);
    }

    @Override
    public void display() {
    System.out.println("现在的天气是: " + temperature +
    " ℃,相对湿度是: " + humidity + "%,大气压是:" + pressure + "kPa");
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    display();
    }
    }
  3. 代码测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class WeatherStationTest {

    @Test
    public void runWeatherStation() {
    // 定义一个气象站
    WeatherData weatherData = new WeatherData();
    // 生成一个 实时温度 显示屏
    CurrentConditionsDisplay currentConditionsDisplay =
    new CurrentConditionsDisplay(weatherData);
    // 生成一个 天气预报显示屏
    ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
    // 气象站更新数据两个显示屏都会显示
    weatherData.setMeasurements(25, 60, 101.3f);
    System.out.println("我现在只想看天气预报-----------");
    // 现在将实时气温显示屏移除,以后气象站更新数据,只会通知天气预报显示屏
    weatherData.removeObserver(currentConditionsDisplay);
    weatherData.setMeasurements(26, 55, 101.4f);

    }
    }
  4. 运行效果

    1
    2
    3
    4
    现在的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.3kPa
    明天的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.3kPa
    我现在只想看天气预报-----------
    明天的天气是: 26.0 ℃,相对湿度是: 55.0%,大气压是:101.4kPa

使用jdk自带的类来实现上述功能

java.util 包中有两个类 ObservableObserver,可以帮助我们实现上面的功能

  1. 定义气象站的类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    import java.util.Observable;


    public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;


    public WeatherData() {
    }

    /**
    * 调用提醒方法
    */
    public void measurementsChanged() {
    /* 设置 Observable 类中的 changed 属性为 true,只有当 changed 属性为 true 时,
    * notifyObservers 方法内部才会调用各个显示屏的update的方法
    */
    setChanged();
    notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    measurementsChanged();
    }

    public float getTemperature() {
    return temperature;
    }

    public float getHumidity() {
    return humidity;
    }

    public float getPressure() {
    return pressure;
    }
    }
  2. 定义两个显示屏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    /**
    * 当前气温显示屏
    * DisplayElement 代码同上

    */
    public class CurrentConditionsDisplay implements Observer, DisplayElement {

    Observable observable;
    private float temperature;
    private float humidity;
    private float pressure;


    // 构建一个显示屏时,向气象站注册
    public CurrentConditionsDisplay(Observable observable) {
    this.observable = observable;
    observable.addObserver(this);
    }

    @Override
    public void display() {
    System.out.println("今天的天气是: " + temperature +
    " ℃,相对湿度是: " + humidity + "%,大气压是:" + pressure + "kPa");
    }

    @Override
    public void update(Observable o, Object arg) {
    if (o instanceof WeatherData) {
    WeatherData weatherData = (WeatherData) o;
    this.temperature = weatherData.getTemperature();
    this.humidity = weatherData.getHumidity();
    this.pressure = weatherData.getPressure();
    display();
    }

    }
    }
    import java.util.Observable;
    import java.util.Observer;

    /**
    * 天气预报显示屏
    */
    public class ForecastDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private float pressure;
    Observable observable;

    @Override
    public void display() {
    System.out.println("明天的天气是: " + temperature +
    " ℃,相对湿度是: " + humidity + "%,大气压是:" + pressure + "kPa");
    }


    public ForecastDisplay(Observable observable) {
    this.observable = observable;
    observable.addObserver(this);
    }


    @Override
    public void update(Observable o, Object arg) {
    if (o instanceof WeatherData) {
    WeatherData weatherData = (WeatherData) o;
    humidity = weatherData.getHumidity();
    temperature = weatherData.getTemperature();
    pressure = weatherData.getPressure();
    display();
    }

    }
    }

  1. 测试代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class WeatherStation {

    @Test
    public void runWeatherStation2() {
    WeatherData weatherData = new WeatherData();
    CurrentConditionsDisplay currentConditionsDisplay =
    new CurrentConditionsDisplay(weatherData);
    ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
    weatherData.setMeasurements(25, 60, 101.1f);
    System.out.println("------现在我们把当前温度移除--------");
    weatherData.deleteObserver(currentConditionsDisplay);
    weatherData.setMeasurements(32, 71, 101.6f);

    }
    }

  2. 运行结果

    1
    2
    3
    4
    明天的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.1kPa
    今天的天气是: 25.0 ℃,相对湿度是: 60.0%,大气压是:101.1kPa
    ------现在我们把当前温度移除--------
    明天的天气是: 32.0 ℃,相对湿度是: 71.0%,大气压是:101.6kPa

Vue子组件向父组件传值

我们的目的是 :通过子组件传递值给父组件,改变父组件的属性值,并通过父组件改变另一个子组件的值

父组件的的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
// 子组件绑定一个方法 changeTitle
<div id ="appheader" v-on:click="changeTitle">
<h1>{{this.title}}</h1>
</div>
</template>

<script>
export default {
name: 'Header',
data () {
return {
title:"hello vue! nice to meet you "
}
},
methods:{
// 这个方法将在父组件中寻找 titleChanged标记的元素

changeTitle:function(){
// 第二个参数是需要传递的新的title的值

this.$emit("titleChanged","子向父组件传值");
}
}
}
</script>

父组件的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<template>
<div id="app">
<h1>{{title}}</h1>
// 在这里注册了标记 将调用改变标题的方法

<appheader v-on:titleChanged="updateTitle($event)"></appheader>
// 在这里给另一个子组件也绑定了父组件的title

<appfooter v-bind:title=title></appfooter>
</div>
</template>
<script>
import appheader from './components/Header'
import footer from './components/footer'
export default {
name: 'App',
data() {
return {
title:"这是我的第一个vue程序",
theuser:[{name:"zhangsan",position:"java开发",show:false},
{name:"zhangsan",position:"java开发",show:false},
{name:"zhangsan",position:"java开发",show:false},
{name:"zhangsan",position:"java开发",show:false}],
}
},
components:{
"appheader":appheader,
"appfooter":footer,
},
methods:{
updateTitle(title){
this.title = title;
}
}
}
</script>
<style>
h1 {
color:red;
}
</style>

另一个子组件,这个子组件的title也会改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
<footer>
<h1>{{copyright}}</h1>
<p>{{title}}</p>
</footer>
</template>

<script>
export default {
name: 'app-footer',
props:["title"],
data () {
return {
copyright:"copyright 2018 Vue Demo "
}
}
}
</script>

<style scoped >
footer {
background: #222;
padding: 6px;
}
h1 {
color: lightgreen;
text-align: center;
}
p{
color: lightgreen;
text-align: center;

}
</style>

演示效果
点击之前
点击之前

点击之后
点击之后

Vue父页面向子页面传值

父页面通过v-bind 命令,将数据绑定在子页面调用时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<template>
<div id="app">
<h1>rdgd</h1>
<appheader></appheader>
// 在这里将数据绑定到子页面

<users v-bind:theuser="theuser"></users>
<appfooter></appfooter>
</div>
</template>

<script>
import Users from './components/Users';
import appheader from './components/Header'
import footer from './components/footer'

export default {
name: 'App',
data(){
return {
title:"这是我的第一个vue程序",
// 这是需要绑定的数据

theuser:[{name:"zhangsan",position:"java开发",show:false},
{name:"zhangsan",position:"java开发",show:false},
{name:"zhangsan",position:"java开发",show:false},
{name:"zhangsan",position:"java开发",show:false}]
}

},
// 这里不能使用 p div 等html元素名称
components:{
"appheader":appheader,
"appfooter":footer,
"users":Users
}
}
</script>

子页面通过props属性访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
<div class="users">
<h1>Hello Users</h1>
<ul>
<li v-for="user in theuser" @click="user.show = !user.show">
<h2>{{user.name}}</h2>
<h3 v-show="user.show">{{user.position}}</h3>
</li>
</ul>
</div>
</template>

<script>
export default {
name: 'users',
// 这种方法不推荐
// props:['theuser'],
// 这是官方推荐的写法
props:{
theuser:{
type:Array,
required:true
}
},
data () {
return {

}
}
}
</script>