Vue2 "胡乱式"总结
时维九月,序属三秋。啊不对,走错片场了,今天不是滕王阁序的场子。今天是Vue2的场子,本小白学习了几个月的Vue,是时候给自己总结一波了。学习的不深,不过感觉还是学到了很多东西。
话不多说,开始!
文章目录
一、什么是Vue
按照官网的话:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。
后面还有一段话,什么巴拉巴拉的,大概就是介绍vue的特点,说一下他的核心,基于什么结构等等,在此我们不去深究。
按照小白(我) 的话:Vue是目前Web前端三大框架之一。
科普小知识:
前端三大框架:Vue.js、Angular.js、React.js
Vue的作者是尤雨溪,Angular来自Google,React来自Facebook。
Vue目前更新到了第三代Vue3,截止到我写这篇博客,vue3的中文文档已经在前两天正式发布,大家有兴趣可以去查看。本文还是主要以vue2的知识为主,更多的关注,提及的是vue2的文档和语法,在此就不在说vue3的相关语法。
给有兴趣玩家的——Vue3官方文档
大家根据实际情况选择食用~~~
二、vue的使用方式
vue的使用方式主要有两种:
- 通过在项目引用Vue.js文件
- 直接创建vue-cli(脚手架),在脚手架中构建项目
第一种方式适合在刚开始学习的阶段,了解vue的相关功能,理解功能的实现
第二种方式适合生产开发阶段,要求使用者有一定的vue基础
本文主要将的是第二种方式,用来对vue2的总结,回顾、复习(当然,语法是一样的,零基础也可以跳过部分内容,直接去语法部分往下食用)
三、vue脚手架的结构
如果你还没有安装npm,vue,那请出门左转百度(bushi,大哥我错了,来人给大哥上教程!)
来了来了:npm,vue简易安装教程
1、创建vue项目
输入指令:
vue create 项目名
项目名最好是英文的,回车后如下图所示,选择项目的模板
- Default ([Vue 3] babel, eslint) --> vue3的默认模板,包含bable和eslint
- Default ([Vue 2] babel, eslint) --> vue2的默认模板,包含bable和eslint
- Manually select features -> 自定义模板
此处不懂babel和eslint没关系,后面应该会讲到,嗯,应该
3、选择配置项
为了讲解配置项,上面选择第三个自定义模板,如下图:
- Babel //转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。
- TypeScript // TypeScript是一个JavaScript(后缀.js)的超集(后缀.ts)包含并扩展了 JavaScript 的语法,需要被编译输出为 JavaScript在浏览器运行
- Progressive Web App (PWA) Support // 渐进式Web应用程序
- Router // 路由
- Vuex // 状态管理(全局变量管理)
- CSS Pre-processors // css预处理器 :sass 和 less 使用较多
- Linter / Formatter // 代码风格检查和格式化 : ESLint + Prettier 使用较多,
- Unit Testing // 单元测试
- E2E Testing // e2e(end to end) 测试
回车后选择版本,选择2.x即可
后面配置就统一说明了,不放图了,太多了
? Pick a linter / formatter config: (Use arrow keys) // 选择语法检测规范
> ESLint with error prevention only // 只进行报错提醒
ESLint + Airbnb config // 不严谨模式
ESLint + Standard config // 标准模式
ESLint + Prettier // 严格模式 使用较多
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Lint on save // 使用较多 建议保存即检测
( ) Lint and fix on commit // 提交才检测,此时可能问题已多,事倍功半
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) // 选择配置信息存放位置
> In dedicated config files // 独立文件放置,项目会有单独的几件文件
In package.json // 统一放置放置
? Save this as a preset for future projects? (y/N)
// 是否保存此配置,方便在以后创建项目中选择使用以上配置
这些选项根据自己的需要来选择即可,选择完之后会进行创建vue项目。如下图所示就是创建成功了
2、分析结构
用vs code打开创建好的项目
其中:
node_modules文件夹
存放npm install时根据package.json配置生成的npm安装包的文件夹
public
存放外部静态文件存放目录,如index.html,favicon.ico图标
src
自己写的代码之类的
路径 | 作用 |
---|---|
src/assets | 内部静态文件存放目录,如font字体图标源文件、项目可能用到的图片素材等。 |
src/components | 项目公共组件存放目录,用来存放写的vue组件,已经组件相关的内容 |
src/store | vuex状态管理目录(简而言之,vuex是一个’仓库’) |
src/utils | 自建目录,主要存放一些公共的js方法 |
src/views | 页面存放目录 |
src/App.vue | vue的根组件 |
src/mani.js | vue入口文件,引入vue框架,根组件及路由设置,创建vue实例等 |
.gitignore
这是默认生成的git仓库忽略文件
babel.config.js
Babel的配置文件,作用于整个项目
jsconfig.json
指定了JavaScript 语言服务提供的性能的根文件和选项
package-lock.json
在 npm install
时候生成一份文件,用来记录当前状态下实际安装的各个npm package的具体来源和版本号
package.json
项目描述文件, 里面记录了当前项目的信息,项目名称、版本、作者、gitHub地址、当前项目依赖哪些第三方模块等。
README.md
项目说明文档
vueconfig.js
vue.js针对该项目的各种配置
以上就是vue脚手架里一般的结构信息
四、vue语法
打开一个vue为后缀的文件,它是vue里面独有的一个文件格式。一般来说,里面的结构大概分成三份。一份是<template></template>
标签里面包裹的内容,我们称之为模板,里面大部分是html的结构。一份是<script></script>
包裹的内容,里面写的是vue相关的东西。一份是<style></style>
标签包裹的内容,里面写样式相关内容。
下面,我们主要研究第二份,模板和样式可能会涉及一些。话不多说,走你!
先上代码:
<template>
<div>
<div>HelloWorld</div>
<button @click="dec"> - </button>
<span class="number">{{ number }}</span>
<button @click="add"> + </button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
number: 0,
};
},
methods: {
add() {
this.number++;
},
dec() {
this.number--;
},
},
};
</script>
<style scoped>
.number {
padding: 0 5px;
}
</style>
再上效果图:
麻雀虽小,五章俱全,我们一点一点来分析。先看中间的js那部分。
4.1 基础认识
- name:当前组件的名字,理论上随便取,不过般采用大驼峰,或者都小写用短横线连接。eg:
HelloWord
hello-word
- data:Vue 的数据属性区,在此区域中定义 VUE 中要使用的相关属性数据。也可以看成是变量定义区域。注意脚手架中是函数形式,要返回出来。同时注意在中显示data的数据要用插值语法,eg:{{ number }}
- method:Vue的方法定义区,可以用来写操作data里面数据的各种方法
4.2 vue指令
- v-bind:单向数据绑定
<template>
<div>
<h1>基本写法</h1>
<!--标准形式 这里的content就是变量名-->
<!--input里的内容为:动态的内容-->
绑定文本框:<input type="text" v-bind:value="content" /><br />
<!--简写(语法糖)形式-->
<!--input里的内容为:动态的内容-->
绑定文本框:<input type="text" :value="content" /><br />
<!--原封不动的显示content文字-->
<!--input里的内容为:content-->
非绑定文本框:<input type="text" value="content" />
<hr />
<h1>动态绑定对象</h1>
<span>{{ i }}</span
><br />
<input type="text" :value="i" /><br />
<button @click="i++">点击我改变i的值</button>
<hr />
<h2 v-bind:class="{ active: isActive, line: isLine }">{{ content }}</h2>
<h2 :class="{ active: isActive, line: isLine }">{{ content }}</h2>
<!--这里的url就是变量名,在data中定义的变量-->
<a v-bind:href="url">动态连接</a><br />
<a :href="url">动态连接</a>
<button @click="changeColor">改变class</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
content: "动态的内容",
i: 1,
isActive: true,
isLine: true,
url: "https://www.baidu.com",
};
},
methods: {
changeColor() {
this.isActive = !this.isActive;
},
},
};
</script>
用v-bind指令将data里的数据拿到模板中,简写形式:(就是一个英文冒号)
特点:数据只能从data流向界面
- v-model:双向数据绑定
<template>
<div>
<!--双向绑定实现原理-->
<!--绑定了遍历val,如果val发生改变这里也发生改变,这里发生改变也会影响到遍历val的内容从而影响到下边文本框的内容,上下功能一样-->
<input type="text" v-model="val" />
<input type="text" :value="val" @input="changeValue" />
{{ val }}
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
val: "hello",
};
},
methods: {
changeValue(e) {
// e.target获得事件源对象
this.val = e.target.value;
},
},
};
</script>
用v-model指令将数据渲染到界面,同时界面中的输入的数据又返回来可以更新data里的值。简写形式:v-model=“变量名”
特点:数据不仅能从 data 流向页面,还能从页面流向 data
v-bind 和 v-model 的区别?
v-bind是单向绑定,用来绑定数据和属性以及表达式,只能将vue中的数据同步到页面。
v-model是双向绑定,不只能将vue中的数据同步到页面,而且可以将用户数据的数据赋值给vue中的属性。
v-bind可以给任何属性赋值,v-model只能给具备value属性的元素进行数据双向绑定。
- v-on:事件绑定
<template>
<div>
姓名:{{ name }}<br />
年龄:{{ age }}
<hr />
<!--注意:必须写在被绑定的div中-->
<button @click="funA()">缩写函数调用</button>
<button v-on:click="funB()">标准函数调用</button>
<button @click="age++">操纵属性</button>
<button @click="funC()">操纵属性</button>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
id: 1,
name: "关为",
age: 19,
};
},
methods: {
funA() {
console.log(this.name + "输出了一段内容!");
},
funB() {
console.log(this.name);
},
// 函数的复杂写法
funC: function () {
this.name = "关老师";
},
},
};
</script>
vue里用v-on指令给dom节点绑定事件,语法:v-on:事件=“函数()”,简写形式:@事件=”函数()“,在没有形参的情况,()可以省略。
- v-for:循环遍历
<template>
<div>
<!--遍历1-10-->
<span v-for="i in 10" :key="i">
<b>{{ i }}</b
>
</span>
<hr />
<!--遍历数组中的元素-->
<span v-for="name in names" :key="name">
<b>{{ name }}</b
>
</span>
<hr />
<!--遍历数组中的元素 带索引号-->
<span v-for="(name, index) in names" :key="index">
<b>{{ index }}->{{ name }}</b
>
</span>
<hr />
<!--遍历对象的属性值-->
<span v-for="value in users" :key="value">
<b>{{ value }}</b
>
</span>
<hr />
<!--遍历对象的属性值 (值,键)-->
<span v-for="(value, key) in users" :key="value">
<b>{{ key }}--->{{ value }}</b
>
</span>
<hr />
<!--遍历对象的属性值 (值,键,索引号)-->
<span v-for="(value, key, index) in users" :key="index">
<b>{{ key }}--->{{ value }}--->{{ index }}</b
>
</span>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
names: ["张三", "李四", "王五", "关为", "马六", "刘德华"],
users: {
userId: 1,
userName: "张三",
userSex: "男",
userAge: 19,
},
};
},
};
</script>
v-for为vue中循环遍历指令,主要用于遍历集合、数组或对象中的属性,一般都需要唯一的key值来渲染更新界面,特别是遍历有输入的地方,一定要用唯一的key值标识。
- v-if、v-else-if、v-else:选择渲染
<!--当value是字符串,显示第一个,是数字类型显示第二个,其他显示第三个-->
<div>
<span v-if="typeof(value) === 'string'"> {{ value }}是字符串 </span>
<span v-else-if="typeof(value) === 'number'"> {{ value }}是数字 </span>
<span v-else> {{ value }}不是字符串也不是数字 </span>
</div>
相当于js里面的判断语句,当哪个条件为真就渲染显示哪个,为假的不渲染。
- v-show:选择显示
<span v-show="number>60">
{{number}}大于60!
</span>
和v-if的效果类似,当值为true时显示内容,为false时不显示,但底层实现有区别。
v-if 和 v-show 的区别?
v-if是"真正"的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做,直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show就简单多了,它不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换(通过修改display样式来进行显示或隐藏)。
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。
- v-text:文本插入
<!--name是data中定义的一个变量名-->
<!--上下效果一样-->
<div id="app" v-text="name"></div>
<div id="app">{{ name }}</div>
等同于 DOM 中的 innerText 属性,用于向标签体中写入文本,该指令和{{}}的功能一样,使用较少(注:该指令不会对 HTML 元素进行解释执行,而是原样输出)。
- v-html:节点插入
<!--name是data中定义的一个变量名-->
<div id="app" v-html="name"></div>
等同于 DOM 中的 innerHTML 属性,用于向标签体中写入文本(注:该指令会对HTML元素进行解释执行)。
v-text和v-html的区别?
v-text:是把变量里的内容全部当作普通文字处理,不会对html的元素进行解析
v-html:区分变量里的文字和html元素,将文字正常显示,将html元素进行解析
- 自定义指令
除了上面10个比较常用的vue指令之外,还有一些其他的指令,并且可以自定义指令,由于用的比较少,此处就不再赘述,有需要可以百度,或者进官网查看。
4.3 过滤器
有时候需要对要显示的数据进行特定的格式化处理,之后再显示。(不改变原数据,产生新的数据)这时就可以选择使用过滤器来格式化文本,过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“|”符号指示。
<template>
<div>
<!-- 过滤器的使用 -->
<!-- 变量名 | 过滤器 -->
<!-- 在双花括号中 -->
{{ content | toUpper }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="content | toUpper"></div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
content: "Hello,World!",
};
},
// 过滤器的定义,和data同级,里面写过滤器方法
filters: {
// 一个大写的过滤器
toUpper(value) {
return value.toUpperCase()
},
},
};
</script>
过滤器那个函数接收的值总是在使用时前面那个参数。
tips:
- 由于过滤器可以被用户使用方法、计算属性等方法替代,使用频率不高,在vue3中已经被删除。
- 在此处举例了一种过滤器,过滤器分为局部过滤器(示例),全局过滤器,并且可以自定义的传入多个参数,本文没有介绍。
4.4 watch监听器
VUE 中的监听器 watch 用于监听 data 中的各个属性,当所监听的属性值发生改变时,监听器就会被自动执行。
- 简写形式(常用)
<script>
export default {
name: "HelloWorld",
data() {
return {
content: "Hello,World!",
};
},
// 和data平级,里面写监听函数
watch:{
content(newValue,oldValue){
console.log(newValue,oldValue);
}
}
};
</script>
简写形式为函数形式,函数名为要监听的属性名称,第一个形参为新值,第二个形参为旧值,函数里实现要进行的操作。
- 完整写法
<script>
export default {
name: "HelloWorld",
data() {
return {
content: "Hello,World!",
};
},
// 和data平级,里面写监听函数
watch: {
content: {
handler(newValue, oldValue) {
console.log(newValue, oldValue);
},
// 是否立即监听(上来就执行一下hangder函数)
immediate: true,
// 是否开深度监听,深度监听对象的每一项,不管多深
deep: true,
},
},
};
</script>
完整写法为对象形式,里面一个handler处理函数,两个配置项,handler函数和简写形式的函数一样,immediate为是否开启立即监听,即上来就调用一下handler函数,deep配置项为开启深度监听可以监听复杂类型的每一项。
4.5 computed计算属性
我感觉计算属性也属于监听的一种,单独的监听器只能监听一个属性,当我们在一个功能中需要监听多个属性时,我们就可以使用计算属性
来实现,计算属性中可以监听多个属性,当所监听的属性中任意一个被修改时,计算属性就会自动执行,计算出最新的值。
<template>
<div>
<img :src="'../img/' + getSrc" width="800" height="600" />
{{ getName }}
<ul>
<li
v-for="(item, index) in imageData"
:key="index"
@click="clickHandler(index)"
>
<h3>编号:{{ item.id }}-介绍:{{ item.name }}</h3>
<p>路径:{{ item.src }}</p>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
imageData: [
{ id: 1, name: "家门口的大湖", src: "1.png" },
{ id: 2, name: "河对岸树下的猴子", src: "2.png" },
{ id: 3, name: "下雪天的景色", src: "3.png" },
{ id: 4, name: "家里养的宠物", src: "4.png" },
{ id: 5, name: "额 (⊙o⊙)… 这个?", src: "5.png" },
],
imgIndex: 0,
};
},
methods: {
clickHandler(index) {
this.imgIndex = index;
},
},
/**定义计算属性*/
computed: {
/*
* 计算属性中默认使用的是getter(获取数据)
* 当前函数监控imgData属性和imgIndex属性,当这两个属性任一个
* 发生改变时,都会被computed监控到,并执行对应的函数
*/
getSrc: function () {
return this.imageData[this.imgIndex].src;
},
getName: function () {
return this.imageData[this.imgIndex].name;
},
},
};
</script>
4.6 组件
组件是vue一个重要的概念,它是一种抽象,将界面中的一部分内容抽象成一个组件,哪里需要哪里搬。它将界面中的部分功能,界面,逻辑样式等等都封装成一个整体,当哪里需要这个组件的时候,就直接将它引用过去使用,当多个页面中有同一个相同的部分时,大大提高了代码的复用率,同时当功能出现问题时,也可以直接在组件中定位问题,修复。
最开始说的vue文件,都可以看作一个vue组件,它的结构就不再说了。
- 组件注册
-
全局注册
全局注册在整个vue项目中都可以使用
首先找到main.js,在里面引入需要注册的组件,如下所示,引入
import HelloWord from '@/compoments/HelloWord.vue'
接着在vue实例上注册组件
// main.js import Vue from 'vue' import App from './App.vue' // 引入组件 import HelloWorld from '@/components/HelloWorld' Vue.config.productionTip = false // 注册全局组件 Vue.component('HelloWorld',HelloWorld) new Vue({ render: h => h(App), }).$mount('#app')
tips:
- 你也可以不引入组件,在Vue.component(‘组件名’, { /* 组件内容*/ })注册(强烈不推荐
- 组件命名规范,官方推荐两种,一种是PascalCase(大驼峰),首字母都大写,eg:,一种是 kebab-case,全小写,短横连接,eg:
-
局部注册
局部注册只能在当前注册的地方使用
首先需要将要注册的组件进行引入
import HelloWord from '@/compoments/HelloWord.vue'
然后在script标签中进行注册,注意:组件注册的名字和引入的名字需要保持一致即可进行简写
<script> import HelloWorld from './components/HelloWorld.vue' export default { name: 'App', components: { HelloWorld } } </script>
- 组件通信
-
props传值
<!-- 其中name为发送的变量名,您好为普通字符串,nihao为data里的变量 --> <!-- 发送 --> <HelloWorld name="你好"/> <!-- 发送动态内容 --> <HelloWorld :name="nihao"/>
// 接收 // 不限制类型 props:['name'] // 限制类型 props: { // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true, }, // 带有默认值的数字 propD: { type: Number, default: 100, }, // 数组写法 propK: { type: Array, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return ["张三"]; }, }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return { message: "hello" }; }, }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ["success", "warning", "danger"].indexOf(value) !== -1; }, }, 函数写法 demoFunction: { type: Function, default: function () { } // default: ()=>{} } }
props一般用于父子组件传参,不推荐接收后修改值。
-
自定义事件
也一般用于父子组件通信,在父组件中绑定,在子组件中用emit触发。
-
消息订阅与发布
适用于多种情况,类似于
公众号
,发布推文,关注的人都可以接收。 -
全局事件总线
将事件绑定在vue实例或组件上,大家都能访问调用,但是事件名不能重复。
-
vuex仓库
vue所有组件都共享的一个大仓库,数据方法,大家都能使用。
tips: 由于篇幅问题,以及这几种方法不太好解释,大家可以参考我之前发的博客:子组件向父组件传参的几种方法_
-
组件插槽
每个组件不可能都被完整的的一模一样的使用,组件插槽可以快捷的设置组件内的内容。
<div> <!--组件--> <HelloWorld> <span>我是一段内容</span> </HelloWorld> </div>
-
单个插槽
<!-- HelloWorld组件 --> <template> <div> <b>我是组件的内容</b> <!-- 接收调用组件时,里面的内容 --> <slot>我是插槽的默认值</slot> </div> </template>
代表的是组件的内容区域, 标签内部书写的内容会自动替换 位置的内容,这样在多次使用 自定义标签时,可以传递不同的内容来达到快速传值的目的。有点像我们在 Java 中学习的占位符效果, 就是占位符,自定义中的内容就是要传递的值。
-
具名插槽
<div> <!--组件--> <HelloWorld> <!--template标记没有其他作用就是包裹起来内容,少一个div。v-slot:名字--> <template v-slot:one> <span>我是一段内容1</span> </template> <template v-slot:two> <span>我是一段内容2</span> </template> </HelloWorld> </div>
<!-- HelloWorld组件 --> <template> <div> <b>我是组件的内容</b> <!-- 接收调用组件时,里面的内容 --> <slot name="one">我是插槽的默认值</slot> <slot name="two">我是插槽的默认值</slot> </div> </template>
如果组件中有多个位置需要设置插槽,需要给 设置name,这种具有名称的插槽,称为具名插槽。
-
作用域插槽
// 父组件 <template> <div> <B :todos="todos"> // 通过v-slot的语法 将插槽的值赋值给scopeData // 由于子组件没有给slot命名,默认值就为default // 如果是具名插槽 使用:v-slot:name="scoprData" <template v-slot:default="scopeData"> <span>{{ scopeData.todo }}</span> </template> </B> </div> </template> import B from './B.vue' // 子组件 export default { name: 'A', components: {B} data() { return { todos: [ {name: '张三', age: 18}, {name: '李四', age: 20}} ] } } }
// 子组件 <template> <div> <ul> <li v-for="(item, index) in todos" > <slot :todo="item"></slot> // 子组件回传数据给父组件 </li> </ul> </div> </template> export default { name: 'B', props: ['todos'] }
- 子组件的数据来源于父组件(通过props传递)
- 子组件无法决定自身结构
- 子组件将数据回传给父组件(
<slot :item='value'></slot>
)
-
-
内置组件
动态组件适用于多个组件频繁切换的处理。
用于将一个“元组件”渲染为动态组件,以 is 属性值决定渲染哪个组件,类似于 v-if 或 v-show 的效果。
<div id="app"> <!--注意这里组件名如果是常量字符串 必须加入''--> <component :is="组件名"></component> </div>
用于实现多个组件的快速切换,例如题目样式,不同的题目渲染不同的样式。is 属性会在每次切换组件时,Vue 都会创建一个新的组件实例。在组件进行切换时都会销毁原有组件,在新建(重新渲染)新的组件。
-
其他事项
keep-alive
用来保留组件的状态,避免被销毁重新渲染,有两个属性:
include
exclude
<!--keep-alive 可以使得在切换组件时 避免重新渲染--> <keep-alive> <component :is="name">{{name}}</component> </keep-alive> <!--include 属性可以指定哪些组件会被缓存--> <keep-alive include="guanwei01,guanwei02"> <component :is="name">{{name}}</component> </keep-alive> <!--exclude 属性指定哪些组件不会被缓存。--> <keep-alive exclude="guanwei01,guanwei02"> <component :is="name">{{name}}</component> </keep-alive>
4.7 生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
如图所示,图中红色圈圈的就是生命周期函数。别的就看图吧,咱也不多解释。
4.8 路由
Vue-Router 路由是 VUE 中的一个核心插件,该插件用于组件间的切换,在 VUE 中路由是用于选择或指定组件。换用白话文说,就是用于界面的跳转,比如点击一个按钮切换界面。
-
下载路由插件vue-router
由于 vue-router 是 Vue 的插件,可以在创建vue项目的时候选择,也可以单独下载 vue-router。在项目里打开一个终端,输入
npm i vue-router@3
注意版本,vue2使用的是3版本的,vue3使用的是4版本,目前默认是4版本的。 -
创建路由实例
在src目录下创建一个router目录,里面创建一个index.js来配置路由
// 引入vue和vue-router import Vue from "vue"; import VueRouter from "vue-router"; // 引入组件 import Login from "../views/Login.vue"; // 将vue-router挂载到vue上 Vue.use(VueRouter); // 配置路由映射关系 const routes = [ { path: "/login", // 路径 name: "login", // 名称 component: Login, // 组件 }, { path: "/dengru", // 路径 name: "dengru", // 名称 redirect: "/login", // 重定向,当访问/dengru时,跳转到/login }, ]; // 创建路由器实例 const router = new VueRouter({ mode: "history", // 模式,一般时hash和history两种 base: process.env.BASE_URL, // 基础路径 routes, // 上面的路由映射关系 }); // 对外暴露路由器 export default router;
-
路由导航方式
-
声明式导航
<router-link to="/login"></router-link>
-
编程式导航
this.$router.push() (函数里面调用) this.$router.replace() (用法同push) this.$router.go(n)
push、replace函数的参数有两种,一种是字符串形式,一种是对象形式
this.$router.push('/login') // 传query参数path和name都行 this.$router.push({ path:'/login', // 传过去的参数 query:{ 对象名:内容 } }) // 传params参数只能用name this.$router.push({ name:'login', // 传过去的参数 params:{ 对象名:内容 } })
-
-
路由出口
// 接收组件显示的地方 <router-view></router-view>
-
路由传参
// 声明式 <router-link to="{ path:'/login',query:{ 对象名:内容 }"></router-link> <router-link to="{ name:'login',params:{ 对象名:内容 }"></router-link> // 编程式 // 传query参数path和name都行 this.$router.push({ path:'/login', // 传过去的参数 query:{ 对象名:内容 } }) // 传params参数只能用name this.$router.push({ name:'login', // 传过去的参数 params:{ 对象名:内容 } })
-
路由嵌套
// 引入vue和vue-router import Vue from "vue"; import VueRouter from "vue-router"; // 将vue-router挂载到vue上 Vue.use(VueRouter); // 配置路由映射关系 const routes = [ { path: '/index', name: 'index', component: () => import('../views/FormDetail.vue'), children: [ { path: 'analysis', component: () => import('../components/analysis.vue'), }, { path: 'questions', component: () => import('../components/question.vue'), }, { path: 'share', component: () => import('../components/share.vue'), } ] }, ]; // 创建路由器实例 const router = new VueRouter({ mode: "history", // 模式,一般时hash和history两种 base: process.env.BASE_URL, // 基础路径 routes, // 上面的路由映射关系 }); // 对外暴露路由器 export default router;
-
路由守卫
路由导航守卫分三种
分别是:全局路由守卫、路由独享守卫、组件级的路由守卫
全局路由守卫又分三种
- 全局前置守卫 router.beforeEach 进入路由之前
- 全局解析守卫 router.beforeResolve
- 全局后置守卫 router.afterEach 进入路由之后就没有next参数
每个守卫都有三个参数:
-
to: Route: 即将要进入的目标路由对象
-
from: Route: 当前导航正要离开的路由
-
next: Function: 钩子函数,里面定义参数,确认下一步路由要做什么
-
next(’/’)或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,next({name: ‘home’}) 。
-
全局前置守卫
你可以使用 router.beforeEach 注册一个全局前置守卫:
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
-
全局解析守卫
在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
-
全局后置守卫
守卫不同的是,后置钩子不会接受 next 函数也不会改变导航本身:
//全局后置钩子函数 router.afterEach((to, from) => { // ... })
-
路由独享守卫
你可以在路由配置上直接定义 beforeEnter 守卫:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, //路由独享守卫 beforeEnter: (to, from, next) => { // ... } } ] })
-
组件内守卫
可以在路由组件内直接定义以下路由导航守卫:
- 进入组件前的守卫 beforeRouteEnter
- 路由更新时的守卫 beforeRouteUpdate (2.2 新增)
- 离开组件时的守卫 beforeRouteLeave
- 下面请看代码实例:
const Foo = { template: `...`, beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不能获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
4.9 vuex“仓库”
vuex是什么?
官网:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
白话文:vuex是vue所有组件共享的一个仓库。
后面又不好解释了,上个图吧!
上图为vuex各部分的关系、运行流程图。
安装这些就不说了,和vue-router基本一样。建议初学者直接跳过这部分。
vuex,主要分为五个部分
store/index.js
// 引入vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 在vue身上使用vuex
Vue.use(Vuex)
// 新建一个store仓库实例对象,并将其暴露出去
export default new Vuex.Store({
// vuex存储数据的地方
state: {
msg:'',
},
// 计算属性,可以理解成vuex的computed
getters: {
},
// 对state中的数据修改
mutations: {
updateMsg(state,msg){
state.msg = msg
}
},
// 对数据进行预处理,或者是异步处理
actions: {
},
// 可以将仓库分解成小仓库
modules: {
}
})
上面是对vuex的粗略的说明,想详细说一下的,但是感觉功夫还没到家,东西挺多,挺杂的,自己不知道从哪儿说起,从哪儿结束,没有好的想法来讲。
END
友友们对不住,就这样吧,以后再继续改进,回头来看,第一次写这么长的东西,写的感觉有点乱,想到哪说哪儿,文笔也不好,写到一大半才感觉到:写文章前一定要构思好文章的结构,内容
,这样才会条理清楚,写的完善,后面越写越乱,写的越来越差。尽管如此,还是忍着写完了,如果有友友看到这,十分感谢!!!