vue 是一个用户构建用户界面的一个渐进式框架

起步

  • webpack 脚手架
  • 单文件页面引入 vue.min.js

声明式渲染

  • 文本插值
  • 表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
{{ message }} // 文本插值
{{ message+"123" }} // 表达式
</div>
<script>
export default {
data(){
return {
message:"123"
}
}
}
</script>

组件

  • 内置组件
    • v-text 文本输出
    • v-html 解析变量中的 html 标签
    • v-model 绑定表单元素的值
    • v-for
    • v-if
    • v-else-if
    • v-else
    • v-bind 简写: 绑定属性值
    • v-show
    • v-on 简写 @
  • 自定义组件

v-show & v-if

v-show 通过 html 或者组件的 display 属性,css 控制显隐
v-if 通过 html 或者组件的插入节点、移除节点,插入或者移除 dom 来控制显隐
v-show 有更高的初始化消耗
v-if 有更多的切换消耗

事件修饰符

v-on 的事件修饰

1
2
3
4
5
6
7
8
9
.stop
.prevent
.capture
.self
.once
.passive // 滚动时间的默认行为立即触发,不会等待onScroll的完成,有助于提升vue在移动端的性能
.keyup
.keyCode
.exact 按键修饰符精准触发

自定义按键修饰符

1
2
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112;

v-for key 的作用

vue 循环遍历数据渲染时,要求我们添加一个不重复的 key(警告)

由于 vue 的便携借鉴来 react,也使用来 jsx,jsx 是虚拟 dom 树替换真实 dom 树,为了更快的找到需要替换的模版节点,我们需要给元素添加 key,有助于提升 vue 组件的性能。

事件

1
2
3
4
5
6
7
8
9
10
11
new Vue({
el: "#root",
render: h > h(App),
});

new Vue({
components: {
App,
},
template: "<App/>",
}).$mount("#app");

变异方法

由于 vue 使用了发布订阅、观察者模式,同时 object.defineProperty 进行数据的监听,我们直接操作数据可能不会触发视图更新。

vue2.x 使用 object.defineProperty
vue3.0 使用 proxy

1
2
Vue.$set(target, key, val);
this.$set(target, key, val);

vue 允许我们通过$set 来修改我们数据的值,但是用起来不是特别方便,vue 又给我们带了变异方法(说白了就是对数组的原生方法提供了数据监听)

1
2
3
4
5
6
push;
pop;
shift;
unshift;
reverse;
sort;

web 服务器

在 vue 脚手架项目当中,我们可以通过 webpack 的 devServer 来创建一个小型 web 服务器

在 vue-cli@3+的版本中,我们可以在项目根目录创建一个 vue.config.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
module.exports = {
devServer: {
// 域名
host: "localhost",
// 端口
port: "8080",
// 开启gzip压缩
compress: true,
// app是devserver使用expres框架创建的一个小型web服务器
before(app) {
app.get("/getJson", (req, res) => {
res.json({
code: 1,
msg: "",
});
});
},
// 开启项目代码的热更新、热替换
hot: true,
// 显示进度条
// progress: true,
inline: true,
// 不显示编译过程产生的信息
// noInfo: "",
// 除了启动信息,其他都不显示
// quiet: true,
publicPath: "/",
// 静态资源服务器路径
contentBase: ".",
// historyApiFallback: true,
// proxy代理服务器来请求其他服务器的数据
proxy: {
// api是访问代理服务器的标记
"/api": {
// 要代理的服务器资源路径
target: "http://localhost:7002",
// 跨域访问
changeOrigin: true,
// 路径重写
pathRewrite: { "^/api": "" },
},
},
},
};

组件

单文件组件

下面将创建一个 layout 布局容器组件 layout.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div class="wraper">
<Header></Header>
<section>this is content</section>
<Footer></Footer>
</div>
</template>

<script>
import Header from "./header";
import Footer from "./header";

export default {
// 局部注册组件
components: {
Header,
Footer
},
};
</script>

<style></style>

对象组件

在一个组件内部,我们可以通过 components 来创建组件,除了 template 是一个 html 字符串外,其他与.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
<template>
<Footer></Footer>
</template>
<script>
export default {
components: {
Footer: {
template: `<div>
this is footer
</div>`,
data() {
return {};
},
methods: {},
computed:{},
watch:{},
beforeCreate(){}
...
},
},
};
</script>

<style></style>

插槽

插槽的分类

  • 匿名插槽
  • 具名插槽

插槽的作用

创建组件后,希望能够动态向组件传递模版内容,这个时候我们就需要使用插槽。

插槽的使用

父组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<Layout>
<router-view />
</Layout>
</template>
<script>
import Layout from "@/components/layout";

export default {
name: "App",
components: {
Layout,
},
};
</script>

子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div class="wraper">
<Header></Header>
<section>
// 上面父组件传递的路由将会在这里展示到
<slot>this is content</slot>
</section>
<Footer></Footer>
</div>
</template>

<script>
import Header from "./header";
import Footer from "./footer";
export default {
// 局部注册组件
components: {
Header,
Footer,
},
};
</script>

组件通讯

父子通讯:

父组件向子组件 Child 传递参数:

  • attr1 静态传参
  • arr2 动态传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<Child attr1="msg" :attr2="msg">this is header</Child>
</template>
<script>
import Child from "./child";
export default {
name: 'Header',
data(){
return {
msg:"12323"
}
},
components:{
Child
}
};
</script>

子组件:
子组件通过 props 来获得父组件传递的参数

  • 数组 简单
  • 对象 完整
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>这里是子组件</div>
</template>
<script>
export default {
name: 'Child',
// props两种写法
// props:["attr1","attr2"],
props:{
attr1:{
type:"String|Number|Boolean|Null|Undefined|Array|Object|Function",
default:"默认值",
require: true|false
}
}
};
</script>

子父通讯

跨级通讯

  • Vue v2.2 新增 provide/inject

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div></div>
</template>

<script>
export default {
name: "DialogFooot",
provide:{
key:val,
...
}
};
</script>

子组件

1
2
3
4
5
6
7
8
9
10
<template>
<div></div>
</template>

<script>
export default {
name: "DialogFooot",
inject:["key1",...],
};
</script>
  • Vue v2.4 新增 $attrs

祖先组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div>
<Parent :key1="key1" :key2="key2" ...></Parent>
</div>
</template>

<script>
export default {
name: "Origine",
data(){
return {
key1:val1,
key2:val2
}
}
};
</script>

父组件 - Parent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
// 父组件可以通过$attrs获得祖先组件中的数据
// 不需要通过props去接受
{{$attrs}}
<Child v-bind="$attr"></Child>
</div>
</template>

<script>
export default {
name: "Parent",
inheritAttrs: false,
};
</script>

子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
// 子组件需要获得父组件的参数,父组件通过v-bind将$attr绑定
{{$attrs}}
</div>
</template>

<script>
export default {
name: "Child",
inheritAttrs: false,
};
</script>

EventHub&EventBus

由于 vue 原生支持发布、订阅模式,我们通过 new Vue() 创建新的实例。

1
export default new Vue();

main.js

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
Vue.config.productionTip = false;
import EventHub form "@/utils/events"

Vue.prototype.$eventHub = EventHub;

new Vue({
router,
render: h => h(App),
}).$mount("#app");
1
2
3
组件内部:
子:this.$eventhub.emit('eventname',callback);
父:this.$on('event',callback)

Vuex