Vue2入门学习笔记

Vue2入门必备!

⭐关注我查看更多配套笔记

学习视频:https://www.bilibili.com/video/BV1Zy4y1K7SH/

【尚硅谷Vue全家桶】

本博客是对该视频内容的整理以及加入自己的理解 想全面学习的推荐大家去看原视频

1.Vue动画

自己使用 Css 也能实现

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
<!-- 使用标签transition包裹 -->
// apper属性可以让动画加载时出现 简写 apper 属性直接添加
<transition name="hello" :apper="true" apper>
<div>
<button @click="isShow = !isShow">
显示/隐藏
</button>
<h1 v-show="isShow">
我是动画元素
</h1>
</div>
</transition>


<!-- 必须使用 vue 规定的名称识别 -->
<style>

/* .之后的名称与name一致 不加name默认为v */
.hello-enter-active {
animation: 动画名 持续时间;
}
.hello-leave-active {
animation: 动画名 持续时间 everse;
}


.v-enter-active {
animation: 动画名 持续时间;
}
.v-leave-active {
animation: 动画名 持续时间 everse;
}

@keyfarm 动画名{
...
}
</style>

2.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
<!-- 使用标签transition包裹 -->
// apper属性可以让动画加载时出现 简写 apper 属性直接添加
<transition name="hello" :apper="true" apper>
<div>
<button @click="isShow = !isShow">
显示/隐藏
</button>
<h1 v-show="isShow">
我是动画元素
</h1>
</div>
</transition>


<!-- 必须使用 vue 规定的名称识别 -->
<style>

/* .之后的名称与name一致 不加name默认为v */
/* 给所需动画添加过度属性 */
h1 {
transition: all 0.5s linear;
}

/* 初始效果 离开的终点 */
.v-enter,.v-leave-to {
animation: 动画名 持续时间;
}

/* 过渡效果中 */
.v-enter-active,.v-leave-active {
transition: all 0.5s linear;
}

/* 结束效果 结束的起点 */
.v-leave-enter-to,.v-leave {
animation: 动画名 持续时间 everse;
}

@keyfarm 动画名{
...
}
</style>

3.多个元素过渡

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
<!-- 使用标签transition包裹 -->
// apper属性可以让动画加载时出现 简写 apper 属性直接添加
<button @click="isShow = !isShow">
显示/隐藏
</button>
<!-- 多个动画添加需要使用transition-group -->
<transition-group group name="hello" apper>
<div>
<h1 v-show="isShow">
我是动画元素
</h1>
<h1 v-show="isShow">
我是动画元素
</h1>
</div>
</transition-group>


<!-- 必须使用 vue 规定的名称识别 -->
<style>

/* .之后的名称与name一致 不加name默认为v */
/* 给所需动画添加过度属性 */
h1 {
transition: all 0.5s linear;
}

/* 初始效果 离开的终点 */
.v-enter,.v-leave-to {
animation: 动画名 持续时间;
}

/* 过渡效果中 */
.v-enter-active,.v-leave-active {
transition: all 0.5s linear;
}

/* 结束效果 结束的起点 */
.v-leave-enter-to,.v-leave {
animation: 动画名 持续时间 everse;
}

@keyfarm 动画名{
...
}
</style>

image-20220419164137507

4.超级好用的动画库

animate.css

1
2
3
4
5
6
<transition
enter-active-class="animate__fadeIn"
leave-active-class="animate__fadeOut"
>
<h1 v-show="visible" class="animate__animated">Animate.css</h1>
</transition>
1
2
3
4
5
6
7
8
9
10
11
12
// 使用方法
// name="animate__animated animate__bounce" 在 transition中添加该属性

// 在官网找到喜欢的属性配置 复制添加到
// enter-active-class="" leave-active-class=""

// npm安装
// npm install animate.css

// 引用 animate.css 动画库
import animate from 'animate.css'
Vue.use(animate)

官网:Animate.css | A cross-browser library of CSS animations.

5.Http请求 代理

1
2
3
4
5
6
7
// 对 xhr 进行封装
// xhr new XMLHttpRequest() xhr.open() xhr.send()
// jQuery $.get $.post
// axios

// 与 xhr平级
// fetch

Vue 项目中 推荐使用 axios

解决跨域问题

1.CORS

2.Jsonp script src 只能使用 get

3.代理服务器 代理服务器默认端口号 8080

1.– nginx

2.– vue-cli

5.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
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 在配置文件中添加以下配置 开启代理服务器 代理服务器开启在 8080
devServer: {
// 需要转发给谁
proxy:'http://后端服务器地址',
}
})

/*
注意
8080端口服务器 的根目录为 public 其中有的东西直接回返回
不会转发请求
*/

// 在axios中请求
axios.get('http://localhost:8080/后端路由地址').then(
response =>{

},
errror =>{

},
)

5.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
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 在配置文件中添加以下配置 开启代理服务器 代理服务器开启在 8080
devServer: {
proxy:{
// 配置 转发服务器的前缀
'/api':{
// 转发地址
target:'http://后端服务器地址',
//加入此配置项 转发地址为 /api/student 替换为 /student 不然会请求原路径
pathRewrite:{
'^/api':''
},
ws:true, // 用于支持 websocket
changeOrigin:true, // 说谎(伪装请求地址) 默认为 true
},
// 可配置多个
'/cas':{
target:'http://后端服务器地址',
pathRewrite:{
'^/cas':''
},
ws:true,
changeOrigin:true,
}
}
}
})

axios.get('http://localhost:8080/配置的前缀/后端路由地址')

6.静态组件

1
2
import '....' // vue 会进行严格的语法检查 放在assat进行引入
// 推荐放入 public 文件夹 在 index.html 中使用 link 引入 bootstrap.. 等

ES6 合并对象语法 Obj = {…对象1名称,…对象2名称}

7.vue-resource vue的插件库

对 xhr 进行封装

Vue.use(vueResource) 在main.js中进行全局配置

在 vm 中会出现 $http

使用 this.$http 代替 axios api完全一致 vue1.0广泛使用

8.slot 插槽

8.1默认插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 正常自闭和组件 / 正常组件 -->
<Student/>
<Student></Student>

<!-- 相同组件需要展示不同的元素时使用 -->
<!-- 默认插槽写法 -->
<!-- 父组件 -->
<Student>
<!-- 需要插入的内容 -->
<img src="">
</Student>

<!-- 子组件 -->
<div>
<!-- 父组件传入插槽的内容 -->
<slot>使用者没有传入插槽 会将我展示</slot>
</div>

<!-- style 可以在 父/子 组件书写 -->

8.2(具名插槽)多个插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 多个插槽写法 -->
<!-- 父组件 -->
<Student>
<!-- 需要插入的内容 -->
<img src="" slot="slot名称1">
<vido src="" slot="slot名称2">

<!-- template写法 template标签 不影响结构-->
<!-- slot:slot名称1 为 vue2.7 更新的写法 只能在 template标签中使用 -->
<template slot="slot名称1" slot:slot名称1>
<h1>我是h1</h1>
<div>我是div</viv>
</template>
</Student>

<!-- 子组件 -->
<div>
<!-- 父组件传入插槽的内容 -->
<slot name="slot名称1">使用者没有传入插槽 会将我展示</slot>
<slot name="slot名称2">使用者没有传入插槽 会将我展示</slot>
</div>

<!-- style 可以在 父/子 组件书写 -->

8.3作用域插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 作用域插槽写法 -->
<!-- 父组件 -->
<Student>
<!-- 作用域必须使用 template 标签 传参 作用域 -->
<template scop="Obj">
<!-- games msg 在Obj中 -->
<h1>{{Obj.games}}</h1>
<h1>{{Obj.msg}}</h1>
</template>
</Student>

<!-- 子组件 -->
<div>
<!-- 子组件插槽中给父组件传参 -->
<slot :games="games" msg="这里是msg信息">使用者没有传入插槽 会将我展示</slot>
</div>

<!-- style 可以在 父/子 组件书写 -->

9.Vuex

image-20220421151212172

多组件共享数据 状态 = 数据

  1. 多个组件依赖于同一个状态
  2. 来自不同组件的行为需要修改同一状态
1
2
3
4
5
6
7
8
9
10
11
12
1.npm i vuex

2.import Vuex from 'vuex' // 在 index.js 中 引入
// vue2 -> vuex3
// vue3 -> vuex4
3.Vue.use(Vuex)

Vue({
store:"hello",
})

// 在 vm 中 出现 $store 保存传入的数据

在components同级文件夹下添加 store 文件夹

添加 index.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
// 该文件用于创建 Vuex 中最为核心的store

// 引入
import Vue from 'vue'
import Vuex from 'vuex'
// 应用Vuex插件
Vue.use(Vuex)
// 准备 actions
const actions = {
// 需要dispatch的函数
"函数名"(context,value){
console.log('actions 中的函数被调用了',context,value);

// 分配给 其他 dispatch 分段处理 便于维护代码
context.dispatch("函数2",value);

context.commit("函数名(使用大写与actions进行区分)",value);
}
}
// 准备 mutations 操作 data
// 开发者工具 检测 mutations
const mutations = {
"大写函数名"(state,value){
state.value += value;
}
}
// 准备 state 用于存储数据 全局 data
const state = {
// 准备数据
"value":0,
// 改变后会替代 vc 里的 data
}

// 实现全局的 计算属性 computed
const getters = {
// 对 state 进行加工
bigSum(state){
return state.sum*10;
}
}

// 创建并暴露 store
export default new Vuex.Store({
actions,
mutations,
state,
getters,
})

main.js

1
2
3
4
5
import store from './store/index.js'
// 配置项中添加store
new Vue({
store
})

js 执行 import 全部 import 会被提升到最高层

vue 规定必须 先 ues(vuex) 再 创建 store 实例

使用2.import Vuex from ‘vuex’
// vue2 -> vuex3
// vue3 -> vuex4
3.Vue.use(Vuex)

1
2
3
4
5
6
7
methds:{
this.$store.dispatch("事件名",传入的数据);
// 直接跨过action
this.$store.commit("事件名",传入的数据);
// 获得计算属性
this.$store.getters.bigSum;
}

可直接夸过 Actions 进行 Commit 调用 mutation 的函数

vuex 开发者工具 历史记录符号

回到该次数据 历史记录符号

可以删除历史记录 禁用符号

合并记录 下载符号

底部分 可以 导入导出 / 粘贴复制

ES6 语法

1
2
3
4
5
6
let Obj1 = {x:1,y:2}
let Obj2 ={
z:3,
...Obj1, // 直接将Obj1的键值对插入
m:7,
}

9.1 **mapState **mapGetters

1
2
3
4
5
6
7
8
9
10
11
12
13
import {mapState} from 'vue'
// 映射 State 中的数据
computed:{
// 借助mapState生成计算属性 从state中读取数据
...mapState({sum:'sum',adress:'adress'}) // 可直接在计算属性中添加
// 不可简写 对象简写方式为 {sum:sum} === {sum} !== {sum:"sum"}

// Vue 可识别 简写方法 与上述方法用途一致
...mapState(['sum','subject'])

// 全局计算属性获取
...mapGeters(['bigSum'])
}

9.2 mapAction mapMutations

1
2
3
4
5
6
7
8
9
10
11
12
import {mapState} from 'vue'
// 映射 State 中的数据
methods:{

// 数组 / 对象 形式默认生成方法 需要在调用时传参
/*add(value){
this.$store.commit('add',value)
}*/

...mapActions(['add']),
...mapMutations(['add'])
}

9.3Vuex模块化

index.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
import Vuex from 'vuex'

// 计数相关属性
const countOptions = {
// 配置该项可在 组件 中使用更简洁的写法
namespaced:true,

// 与正常 vuex 配置完全一致
action:{},
mutation:{},
state:{},
getter:{},
}

// 人员相关属性
const personOptions = {
action:{},
mutation:{},
state:{},
getter:{},
}

export default new Vuex.Store({
modules:{
countAbout:countOptions,
personAbout:personOptions
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 组件中简写使用
computed:{
// 普通简写
// 调用 state时 需要使用 countAbout.data
...mapState(['countAbout','personAbout']),

// 需要在 vuex 中 开启 namespaced
// 调用时 直接使用 data 就可以
...mapState('countAbout',['data']),
...mapState('personAbout',['data']),

// 其他 map 同理使用

// getter 模块化之后 值为 countAbout/bigSum countAbout不再为对象
}

10.路由

10.1 路由基础

单页面应用 路由改变 页面局部刷新 (没有全部刷新)

使用 vue 的插件库 vue-router

npm install -g vue-router

1
2
3
4
5
6
/*
vue-router 3 版本对应 vue 2
vue-router 4 版本对应 vue 3
*/

// npm install vue-router@3

components 同级文件夹下创建 router 文件夹

index.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
// 引入 vue-router
import VueRouter from 'vue-router'
// 引入组件
import TheList from '../components/TheList.vue';
import AboutSnowman from '../components/AboutSnowman.vue';

// 创建 并 暴露 一个路由器
export default new VueRouter({
routes: [
{
path:"/TodoList",
component:TheList,
},
{
path:"/about",
component:AboutSnowman,
},
// path 为 * 表示匹配全部 可以匹配全部路径 路径匹配为从上至下
{
path:"*",
component:AboutSnowman,
},

]
})

main.js

1
2
3
4
5
6
7
8
// 引入 路由器
import router from './router'

new Vue({
render: h => h(App),
// 设置 router
router:router,
}).$mount('#app')
1
2
3
4
5
6
7
8
<!-- 最终 在 html 页面中转化为 a 标签 -->
<!-- to 为跳转到的路由 -->
<!-- active-class 为在该路由时应用的 样式 -->
<router-link to="/TodoList" active-class="active">每日清单</router-link>
<router-link to="/about" active-class="active">关于我的主页</router-link>

<!-- 视图展示 对应路由的位置 -->
<router-view></router-view>

components 同级文件夹下创建 pages 文件夹

便于分类 pages存放 路由组件 components文件夹存放 一般组件

原理 : {不断销毁与挂在组件}

  • 每个组件都有自己的$route属性,里面存储着自己的路由信息
  • 整个应用只有一个router, 可以通过组件的$router属性获取到

10.2 多级路由 (嵌套路由)

index.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
// 引入 vue-router
import VueRouter from 'vue-router'
// 使用插件
import Vue from 'vue'
Vue.use(VueRouter)
// 引入组件
import TheList from '../components/TheList.vue';
import AboutSnowman from '../components/AboutSnowman.vue';

// 创建 并 暴露 一个路由器
export default new VueRouter({
routes: [
// 一级路由
{
path:"/TodoList",
component:TheList,
// 路由嵌套从这里开始
// 二级路由
children:[{
// 第二级不需要加 / 会出问题
path:"new",
component:TheList,
}]
},
// 一级路由
{
path:"/about",
component:AboutSnowman,
},

]
})
1
2
3
4
5
6
7
8
9
10
<!-- 最终 在 html 页面中转化为 a 标签 -->
<!-- to 为跳转到的路由 -->
<!-- active-class 为在该路由时应用的 样式 -->

<!-- 二级路由必须携带父亲级路由的路径 -->
<router-link to="/TodoList/new" active-class="active">每日清单</router-link>
<router-link to="/about/new" active-class="active">关于我的主页</router-link>

<!-- 视图展示 对应路由的位置 -->
<router-view></router-view>

10.3 路由传参

query参数 get传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<router-link to="/TodoList/new?name=雪人&age=18" active-class="active">每日清单</router-link>

<!-- 加 v-bind + ES6 `` 动态传参 -->
<router-link :to="`/TodoList/new?name=${name}&age=${age}`" active-class="active">每日清单</router-link>

<!-- 对象式 传参 -->
<router-link :to="`{
path="/TodoList/new",
query:{
name:name,
age:age,
}
}
`" active-class="active">每日清单</router-link>

<router-link to="/about/new" active-class="active">关于我的主页</router-link>
1
2
3
// 组件中获取
this.$route.query.name
this.$route.query.age

10.4 命名路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default new VueRouter({
routes: [
{
// 配置姓名 简化传参
name:'ListName',
path:"/TodoList",
component:TheList,
children:[{
// 配置姓名 简化传参
name:'new',
path:"new",
component:TheList,
}]
},
]
})
1
2
3
4
5
6
7
8
9
10
11
<!-- 对象式 传参 -->
<!-- 使用 name 必须使用对象式 -->
<router-link :to="`{
// 此处直接传入 路由器 定义的名字
name:"ListName",
query:{
name:name,
age:age,
}
}
`" active-class="active">每日清单</router-link>

10.5 params参数

1
2
3
4
5
6
7
8
9
10
11
12
<!-- params参数 传参 需要配置占位符 -->
<router-link :to="`/TodoList/new/11/王二`" active-class="active">每日清单</router-link>
<!-- params参数 对象式 -->
<router-link :to="`{
// params 只能使用name path会报错!!!
name:"ListName",
params:{
id:11,
name:"王二",
}
}
`" active-class="active">每日清单</router-link>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default new VueRouter({
routes: [
{
// 添加占位符设置参数
name:'ListName',
path:"/TodoList/:id/:name",
component:TheList,
children:[{
// 添加占位符设置参数
name:'new/:id/:name',
path:"new",
component:TheList,
}]
},
]
})
1
2
3
// 组件中获取
this.$route.params.name
this.$route.params.age

10.6 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
32
33
export default new VueRouter({
routes: [
{
name:'ListName',
path:"/TodoList/:id/:name",
component:TheList,
children:[{
name:'new/:id/:name',
path:"new",
component:TheList,
// props 写法一
// 该对象中的所有 key-value 都会以props的形式传给 组件 TheList中
props:{id:1,name:'hello'},

// props 写法二
// props值为布尔值,若布尔值为真,就会把该参数的 params值当做 props 值传递给组件
props:true,

// props 写法三
// 值为函数 返回值 以props 传递给组件
// $route 被回调传入 真好
props($route){
return {id:$route.query.id,name:'hello'}
}

// 结构赋值写法
props({query}){
return {id:query.id,name:query.name}
}
}]
},
]
})

10.7 replace 记录

默认为push记录 栈的不断添加

replace 替换当前记录 不能返回

1
2
3
4
<!-- 开启replace :replace="true" -->
<router-link to="/TodoList/new" active-class="active" :replace="true">每日清单</router-link>
<!-- 开启replace 简写方式 -->
<router-link to="/about/new" active-class="active" replace>关于我的主页</router-link>

10.8 编程式路由导航

在 $router 中 直接操作 不借助 router-link

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>
<button @click="showPush">
push查看
</button>
<button @click="showReplace">
replace查看
</button>
<button @click="back">
后退
</button>
<button @click="forward">
前进
</button>
<button @click="go">
前进
</button>
</template>

<script>
export default {
name:'Message',
methods:{
showPush(){
// 调用 $router 上的API
this.$router.push({
name:"xiangqing",
query:{
id:'11',
name:'王二',
}
})
},
showReplace(){
// 调用 $router 上的API
this.$router.replace({
name:"xiangqing",
query:{
id:'11',
name:'王二',
}
})
},
back(){
this.$router.back
},
forward(){
this.$router.forward
},
go(){
// 正数 前进 n 次
// 复数 后退 n 次
this.$router.go(n)
},
}
}
</script>

10.8 缓存路由组件

组件切走时会被销毁 内容消失 如何保存?

需要保存数据的去缓存

1
2
3
4
5
6
7
8
9
10
<!-- inlude="" 配置需要缓存的组件 否则缓存全部组件 -->
<!-- 防止组件被销毁 数据丢失 -->
<keep-alive inlude="组件名">
<router-view></router-view>
</keep-alive>

<!-- 缓存多个组件 -->
<keep-alive :inlude="['组件名1','组件名2','组件名3']">
<router-view></router-view>
</keep-alive>

10.9激活与失活声明周期

用于路由组件的 开启定时器 比 mounted更高效

1
2
3
4
5
6
7
8
methods:{
activated(){
// 开启定时器
},
deactivated(){
// 定时器自动关闭
}
}

10.10路由守卫

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
export default new VueRouter({
routes: [
{
path:"/TodoList",
component:TheList,
// 用于存放用户需要的特殊数据
// 可以在判断中进行索引 不指定默认为 undefined 为 false
meta:{isAuth:true,title:"每日清单"},
}
]
})



// 全局前置路由守卫
// to 路由去向 路由对象
// from 路由由来 路由对象
// next 回调函数 使用 next()才能切换路由
router.beforeEach((to,from,next)=>{
if(to.path === '/home'){
// 利用meta判断
if(from.meta.isAuth){
next()
}
next()
}
next()
})
export default router
1
2
3
4
5
6
// 全局后置路由守卫
// 无 next 路由跳转已经完成后触发
router.afterEach((to,from)=>{
// 可在跳转完成后更改路由
doucment.title = to.meta.title || '网页标题' // 短路判断
})

2.独享路由守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default new VueRouter({
routes: [
{
path:"/TodoList",
component:TheList,
// 用于存放用户需要的特殊数据
// 可以在判断中进行索引 不指定默认为 undefined 为 false
meta:{isAuth:true,title:"每日清单"},

// 独享路由守卫 仅有前置 无后置
beforeEnter:(to,from,next)=>{
if(...){
next()
}
}
}
]
})

3.组件内路由守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
mounted(){
// 通过路由器规则 进该组件时被调用
// 在beforeEnter 之前
// to 一定是该组件路由
beforeRouteEnter(to,from,next){

},
// 通过路由器规则 离开该组件时被调用
// from 一定是该组件路由
beforeRouteLeave(to,from,next){

}
}
</script>

11.浏览器路由模式

main.js

1
2
3
4
5
6
7
// hash 带 # 兼容性好 不美观 
// history 不带 # 兼容性差(相对) 美观 会寻找服务器路径资源 容易出错(后端解决)

new VueRouter({
// 设置模式
mode:history,
})

12.打包 上传服务器

1
2
3
4
>>> npm run build
// 生成 dist 文件夹
// 为打包后的 css js html 文件
// 直接点击 index.html 无法运行必须在服务器部署

如何部署服务器

node.js express 框架

->npm init

->text_serve 包名

->npm i express

中间件解决 history 模式 404问题

->npm i connect-history-api-fallback

// 在 server.js 同级目录下 新建 js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const express = require('express')
const history = require('connect-history-api-fallback')

const app = express()

// 解决history 404 问题
app.use(history)
// 默认选择 index.html
app.use(express.static(__dirname+"./static"))

app.get('/person',(req,res)=>{
res.send({
name:'tom',
age:18
})
})

app.listen(5005,(err)=>{
if(!err) console.log('服务器启动成功了!')
})

13.Vue UI 组件库

7.1 移动端常用组件库

7.2PC端常用UI组件库

直接用就行

此处介绍Element UI

->npm i element-ui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Vue from 'vue';
import ElementUI from 'element-ui';
// 引入全部样式
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

// 此处use 后 会注册全部组件为全局组件
// 引入的 js 非常大 7.2M(别用)
Vue.use(ElementUI);

new Vue({
el: '#app',
render: h => h(App)
});

按需引入

-> npm install babel-plugin-component -D 按需引入的库 -D为开发依赖(开发环境)

->npm install babel-preset-es2015 –save

->npm install –save-dev @babel/cli

需要修改 babel.config.js 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
['es2015', { modules: false }],
],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk',
},
],
],
}

main.js

1
2
3
4
5
6
7
8
// 按需引入 
import {Button,Row,...} from 'element-ui'
// 配置之后会引入需要的 css 而不是全部css
import 'element-ui/lib/theme-chalk/index.css';

// Button 的组件名 可以自定义
// 注册全局组件
VUe.component(Button.name,Button)