vue
目录
- 简介:
- vue.js是什么
- vue.js目的
- vue.js的核心思想
- vue.js优势
- 什么是框架
- 框架的优势
- MVC框架
- MVVM思想
- MVP思想
- 编写第一个 Vue.js 程序 – – ‘hello,Vue.js’
- Vue声明式渲染
- Vue数据驱动
- {{}}-----插值表达式(模板语法)
- 事件对象
- 事件修饰符
- 计算属性
- 计算属性和方法有什么区别
- 侦听/监听watch
- 什么时候使用watch
- 计算属性和侦听器的区别:
- 虚拟DOM
- 为什么使用虚拟DOM
- 真实DOM和虚拟DOM的区别
- DOM diff
- Vue请求数据交互
- Axios
- 过滤器
- 实例的生命周期
- 生命周期钩子函数的用途
- 钩子函数(位置:data与methods同级)
- 生命周期扩展问题
- 简述生命周期
- 组件的基本概念
- 组件的类型
- 全局组件
- 局部组件
- props(正向传值)
- props验证
- slot(槽口)
- 具名slot
- 父子组件
- 子组件的调用
- 父子组件传值
- 自定义事件
- 项目环境配置vue.config.js
- 单文件组件
- v-for key的使用
- vue路由
- 二级路由
- 在路由页面配置
- 路由懒加载
- promise是什么
- 动态组件
- keep-alive
- include与exclude
- keep-alive 的钩子函数
- 自定义指令
- ref和$refs
- Axios
- Axios发送请求
- mock模拟数据
- 同级/兄弟组件传值——中央事件总线
- VUEX
- 安装VUEX
- vuex单一状态树
- vuex--使用数据源state
- vuex----Getters属性
- Getter特性
- VUEX----Mutations
- vuex--Mutations 提交载荷(Payload)
- VUEX中页面刷新数据丢失问题
- vuex--Actions
- vuex-modules
- vuex----表单处理
- Mixins(混入)
- 自定义验证
- eslint代码验证问题
- axios拦截器
简介:
概念:Vue.js是目前最流行的前端MVVM框架
作者:尤雨溪(中国人) 前google员工
vue.js是什么
是一套构建用户界面的渐进式的自底向上增量开发MVVM框架,Vue的核心库只关注视图层,它不仅容易上手,还便于与第三方或既有项目整合。通过尽可能简单的API实现响应的数据绑定和组合的视图组件。
对于Vue是一套渐进式框架的理解
每个框架都会有自己的一些特点,会对开发者有一定的要求,这些要求就是主张,主张有强有弱,他的强弱程度会影响在业务开发中的使用方式。
可以在原油大系统的上面,把一两个组件改用vue实现,也可以整个用vue全家桶开发不会做职责之外的事情
对于Vue自底向上增量开发的设计的理解
先写一个基础的页面,把基础的东西写好,在逐一去添加功能和效果,有简单到繁琐的这么一个过程
vue.js目的
Vue.js的产生是为了解决如下三个问题
1. 解决数据绑定问题
2. Vue.js主要是为了开发大型单页面应用。
3. 支持组件化,也就是可以吧页面封装为若干个组件,吧组件进行拼装,这样让页面的附庸性达到最高
vue.js的核心思想
vue.js的核心思想包括:数据驱动和组件化
vue.js优势
简洁:HTML模板 + vue实例 + JSON数据
轻量:17kb,性能好
设计思想:视图与数据分离,无序操作DOM
社区:大量的中文资料和开源案例
什么是框架
封装与业务无关的重复代码
框架的优势
使用框架提升开发效率(虽然使用框架要遵循框架的语法 但是使用框架可以大大提高对于业务逻辑的操作)
MVC框架
MVC表示软件可分成三部分
1.模型(Model)数据的储存和处理,在传递个视图层响应或展示
2.视图(View)前端的数据展示
3.控制器(Controller)对数据的接受和触发事件的接受和传递
为什么要是用MVC
1.MVC是一种专注业务逻辑,而非显示的设计思想
2.MVC中没有DOM操作
3.将数据独立出来,方便管理
4.业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑
MVVM思想
Vue.js是一套构建用户界面的MVVM框架
MVVM分为三个部分:分别是(Model,模型层),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看做是控制器MVC的c层)
1.M:模型层,主要负责业务数据相关
2.V:视图层,顾名思义,负责视图相关,细分下来就是html+css层
3.VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;因此开发者只需要关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全有MVVM来统一管理
MVP思想
MVP的全称为Model-View-Presenter,Model提供数据,View负责显示,Presenter表示器
MVP与MVC有着一个重大的区别:MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控View与Model之间的间接交互。
小结
什么是框架:封装与业务逻辑无关的重复代码形成框架
MVC 思想:一种将数据层与视图层进行分离的设计思想
MVVM思想:意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之相同
MVP思想:MVP的全称为Model-View-Presenter,Model提供数据,View负责显示,Presenter负责逻辑的处理
编写第一个 Vue.js 程序 – – ‘hello,Vue.js’
套用 MVC思想,逐步创建出控制器,视图和数据
第一步 创建 View 视图
应用程序的界面将显示在这里
第二步 创建 vm
控制器也就是 Vue.js 的实例
第三步 创建 Model 数据
data 为 Vue.js 实例的固定属性,存储数据
第四步 使用数据
将 data 中变量 message 放在 #app内的双花括号内
修改 data 中的 message,会同步显示在页面中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<script scr="https://lib.baomitu.com/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<h1>{{message}}</h1>
</div>
<script>
let vm = new Vue({
data(){
return {
message:"hello world"
}
}
})
</script>
</body>
</html>
Vue声明式渲染
Vue.js的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进DOM,也就是将模板中的文本数据携进DOM
命令式渲染:命令我们的程序去做什么,程序就会跟着你的命令区域一步步执行
声明式渲染:我们只需要告诉程序我们想要什么效果,其他的交给程序来做
Vue数据驱动
通过控制数据的变化来显示vue的数据驱动是视图的内容随着数据的改变而改变
{{}}-----插值表达式(模板语法)
将双大括号中的数据替换成对应属性值进行响应式的展示
模板语法中可以写入哪些内容
数字
字符串
计算 mvc设计思想,是为了使页面和数据进行很好的分离;如果在表达式中写入过多的逻辑代码,那么违背了最初的设计思想;也就使代码看起来很复杂,难以维护
事件对象
语法:<div @click="fn($event)"></div>中$event为事件对象
作用:记录事件相关的信息
事件修饰符
概念:v-on指令提供了事件修饰符来处理DOM事件细节
按键修饰符:.up .down .ctrl .enter .space
语法: @click.修饰符='fn()'
prevent修饰符:阻止事件的默认行为(submit提交表单)
stop修饰符:阻止事件冒泡
capture修饰符:与事件冒泡的方向相反,事件捕获由外到内
self修饰符:只触发自己范围内的事件,不包含子元素
once:只触发一次
注意:修饰符可以串联使用
计算属性
为什么使用计算属性:
模板内的表达式非常便利,但是设计他们的初衷是用于简单运算的,在模板中刚入太多的逻辑会让模板过重且难以维护
概念:
顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了 data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行
语法:
computed:{
需要返回的数据:function(){
return 处理操作
}
}
例子: computed:{
demotext:function(){
return this.text.toUpperCase().substr(2,1);
}
}
计算属性和方法有什么区别
上面的例子也可以使用方法来完成
methods:{
textfun(){
return this.text.toUpperCase().substr(2,2)
}
}
1.计算属性是基于它们的依赖进行缓存。计算属性只有在他的相关依赖发生改变时才会重新求值
2.方法绑定数据只有被调用,方法将总会再次执行函数
3.计算属性相对于方法在处理特定场合下节省资源性能
侦听/监听watch
watch:可以监听模型数据 当模型数据改变时就会触发
watch:{
监听的data数据(newval,oldval){
console.log(newval+"------"+oldval)
}
}
watch初始化的时候不会运行,只有数据被改变之后才会运行
什么时候使用watch
当需要在数据变化时执行异步或开销较大的操作时,watch这个方式是最有用的
计算属性和侦听器的区别:
当watch监听的值发生改变就会被调用,watch可以在数据变化时左一些异步处理或开销大的操作
计算属性是计算依赖的值,当一来的值发生改变才会触发
虚拟DOM
所谓的虚拟DOM,也就是我们常说的虚拟节点,它是通过JS的Object对象模拟DOM中的节点,然后在通过特定的render(渲染)方法将其渲染成真实的DOM的节点
为什么使用虚拟DOM
使用JQuery的时候,会大量操作DOM,那么DOM元素的变化自然会引起页面的回流或者重绘,页面的DOM重绘自然会导致页面性能下降,那么如何尽可能的去减少DOM的操作是框架需要考虑的一个重要问题!
真实DOM和虚拟DOM的区别
1.虚拟DOM不会进行排版与重绘操作
2.真实DOM频繁排版与重回的效率是相当低
3.虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分,最后在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
4.虚拟DOM又降低的重回与排版,因为最终于真实DOM比较差异,可以只渲染局部
DOM diff
虚拟DOM,是一种为了尽可能减少页面DOM频繁操作DOM的方式,那么在虚拟DOM中,通过什么方式才能做到呢?
就是Diff算法
原理:
逐步解析newdom的节点,找到它在olddom中的位置,如果找到了就移动对应的DOM元素,如果没找到说明是新增节点,则新建一个节点插入。遍历完成之后如果oldVdom中还有没处理过的节点,则说明这些节点在newVdom中被删除了,删除它们即可
Vue请求数据交互
vue请求数据有Vue-resource、Axios、fetch三种方式。Vue-resource是Vue官方提供的插件,axios是第三方插件,fetch es6原生
Vue-resource2.0停止更新了
Axios
下载 npm install --save axios
语法:
axios.get('/路径?key-=value&key=value')
.then(ok=>{})
.catch(err=>{})
axios.post('/user',{k:v,k:v})
.then(ok=>{})
.catch(err=>{})
post交互
//实例化对象:
let param = new URLSrarchParams();
//添加发送数据参数
param.append("key","value");
axios(utl:'请求地址',method:'请求方式',data/params:{k:v}).then((ok)=>{})
使用get发送数据的时候 使用params:{key:val}发送数据
使用post发送数据需要使用 var param=new URLSearchParams();修改传参方法
使用param.append("uname","xixi")添加数据并且使用data发送数据
过滤器
全局过滤器的定义方法
位置:创建实例之前
Vue.filter('过滤器的名称',function(val){ //val 需要处理的值
代码块
return 处理后的数据
})
局部过滤器
位置:在vue实例中与el属性data属性同级定义
filters:{
过滤器的名字:function(val){
return 输出内容
}
}
Vue.filter('sum',function(val){
return val+4;
})
过滤器的调用方法 {{msg | sum}}
注意事项
定义全局过滤器,必须放在Vue实例化前面
在没有冲突的前提下,过滤器可以串联
实例的生命周期
什么是实例的生命周期
实例在创建到销毁经过一系列过程叫生命周期
什么是生命周期钩子
在生命周期中被自动调用的函数叫做生命周期钩子
生命周期钩子函数的用途
每个Vue实例在被创建时都要经过一系列的初始化过程————例如,需要设置数据监听、编译模板、实力挂在到DOM并在数据变化时更新DOM等。同事在这个过程中也会运行一些叫做生命周期钩子函数,这给了用户在不同阶段添加自己的代码的机会。
钩子函数(位置:data与methods同级)
beforeCreate(创建实例)
created(创建完成)
beforeMount(开始创建模板)
mounted(创建完成)
beforeUpdate(开始更新)
updated(更新完成)
beforeDestroy(开始销毁)
destroyed(销毁完成)
生命周期扩展问题
什么是vue生命周期?
vue生命周期的作用是什么?
vue生命周期总共有几个阶段?
第一次页面加载会触发哪几个钩子?
DOM 渲染在 哪个周期中就已经完成?
1.Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
2.生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易完成指定逻辑。
3.它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
4.第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
5.DOM 渲染在 mounted 中就已经完成了。
简述生命周期
beforeCreate(创建前) 在数据观测和初始化事件还未开始
created(创建后) 完成数据观测,属性和方法的运算,初始化事件,实例中的el属性还没有显示出来
beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
mounted(载入后) 在el 被新创建的 vue.el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用
组件的基本概念
组件的概念:组件即自定义控件,是Vue.js最强大的功能之一
组件的用途:组件能够封装可重用代码,扩展HTML标签功能
组件的本质:自定义标签
组件的类型
1、页面级别的组件:页面级别的组件,通常是views目录下的.vue组件,是组成整个项目的一个大的页面。一般不会有对外的接口。
2、业务上可复用的基础组件:在业务中被各个页面复用的组件,这一类组件通常都写到components目录下,然后通过import在各个页面中使用。
3、与业务无关的独立组件:与业务功能无关的独立组件。这类组件通常是作为基础组件,在各个业务组件或者页面组件中被使用。目前市面上比较流行的ElementUI和iview等中包含的组件都是独立组件。如果是自己定义的独立组件,比如富文本编辑器等,通常写在utils目录中
全局组件
Vue.component('name',{
template:'<div></div>'
})
位置:创建实例前定义全局组件
template的设置:
HTML代码
'#ID' 引用tempplate内容
组件的调用: <组件名></组件名>
局部组件
语法:定义在vue实例中只能在当前实例范围内生效
var vm = new Vue({
el:"#demo",
components:{
"son-name"{
template:"<div><span @click="fun()">子组件</span></div>",
data:function(){
return num;
},
methods:{
fun(){
this.num--
}
}
}
}
})
组件的数据的定义:
data:function(){
return {
a:1,
b:b
}
}
需以函数返回值的形式定义数据
props(正向传值)
作用:props选项用来声明它期待获取的数据
本质:props为元素属性
语法:如果是驼峰命名法需要把大写转小写前面加-
js中:
props:['message1','messAge2']
html中:
<组件 message='val' mess-age2='val'></组件>
使用:与data一样,props可以用在模板中
props验证
props:{
//可以验证 String,Number,Boolean,Array,Object,Date,Function
ziaprop:Number,
//传入数组验证多个类型
zibprop:[String,Number],
//必填内容
zicprop:{
type:String,
require:true
},
//带有默认值得数字
zidprop:{
type:Number,
default:100
}
}
slot(槽口)
作用:用来混合父组件的内容与子组件自己的模板
语法:
声明组件模板:定义组件的时候留下slot等待调用的时候插入内容
<div>
<h2>我是子组件的标题</h2>
<slot>只有在没有要分发的内容是才会显示</slot>
</div>
使用: 调用组件模板:调用的时候直接插入
<div>
<h1>我是父组件的标题</h1>
<my-component>
<p>知识一些初始内容</p>
</my-component>
</div>
具名slot
<slot>元素可以用一个特殊属性name来配置如何奋发内容
多个slot可以有不同的名字
具名slot将匹配内容片段中对应slot特性的元素
父子组件
语法:components:{
'parent':{
template:"<div></div>",
components:{
'child':{
template:'<div></div>'
}
}
}
}
组件相当于完整的vue实例
组件与vue实例减作用域独立(组件与vue实例中data数据不互通)
父子组件间作用域相互独立
子组件的调用
子组件只能在父组件的模板中进行调用
<!-- 父模板 -->
<template id="fu">
<div class="topbar">
<!-- 子组件必须放在父组件模板中 -->
<zi context="neirong"></zi>
</div>
</template>
父子组件传值
父子组件间作用域相互独立所以没有办法直接调用,必须借助于自定义事件来进行传值
子组件传值给父组件叫逆向传值(是不允许的 必须要有事件触发才能传值)
父组件传值给子组件叫正向传值(不需要事件触发)
自定义事件
抛出自定义事件监听
要传值必须要先抛出,在接受
语法:
this.$emit('event',val)
event:自定义事件名
val:通过自定义事件传递的值
$emit:vue实例方法,用来触发事件监听、
接受自定义事件
语法: <component @抛出事件名 = '函数不加()'></component>
<!-- 父模板 -->
<template id="fu">
<div >
<!-- 调用子组件 -->
<zi @chuanzhi="fun"></zi>
</div>
</template>
fun(val){
//val:自定义时间传递出的值
}
事件触发及接收原则:谁触发的监听,由谁接收监听
项目环境配置vue.config.js
module.exports={
//自动打开页面
devServer:{
open:true,//自动开启
port:8080,//端口号
hotOnly:true,//热更新
//代理跨域
proxy: {
'/api': {
target: 'http://localhost:3000/', //对应自己的接口
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
}
}
},
//路径设置别名
configureWebpack:{
resolve:{
alias:{
//"别名":"对应的文件夹"
"com":"@/components",
"api":"@/api",
"util":"@/util"
}
}
}
}
打包配置项(路由模式改为hash模式--解决刷新404页面)
module.exports={
//自动打开页面
devServer:{
open:true,
port:8080,
//代理跨域
proxy: {
'/api': {
target: 'http://localhost:3000/', //对应自己的接口
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
}
}
},
//路径设置别名
configureWebpack:{
resolve:{
alias:{
"com":"@/components",
"api":"@/api",
"util":"@/util"
}
}
}
}
打包配置项(路由模式改为hash模式)
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
// 基本路径
publicPath: './', //部署应用包时的基本 URL
outputDir: 'dist', // 输出文件目录
assetsDir: '',//放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
runtimeCompiler: false, //是否使用包含运行时编译器的 Vue 构建版本。设置为true可以使用template
productionSourceMap: process.env.NODE_ENV === 'development',//生产环境是否生成 是用来报错时定位到代码位置 文件
lintOnSave: true,
chainWebpack: config => {
},
configureWebpack: (config) => {
// ============去除console============
if(process.env.NODE_ENV === 'production'){
config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
}
// ============去除console end============
},
// css相关配置
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
loaderOptions: {},
// 启用 CSS modules for all css / pre-processor files.
modules: false
},
parallel: require('os').cpus().length > 1,//是否为 Babel 或 TypeScript 使用 thread-loader
// PWA 插件相关配置
// see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
pwa: {},
// webpack-dev-server 相关配置
devServer: {
open: process.platform === 'darwin',
host: '0.0.0.0',
port: 8888,
https: false,
hotOnly: false,
// 设置代理
proxy: {
'/api': {
target: 'http://localhost:3000/', //对应自己的接口
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
}
},
},
// 第三方插件配置
pluginOptions: {
// ...
}
}
单文件组件
通过一个.vue为后缀的文件来完成一个组件的封装
<template>
</template>
<script>
export default {
}
</script>
<style>
</style>
v-for key的使用
为遍历数组或元素中的唯一标识,增加或删除元素时,通过这个唯一标识key判断是否是之前的元素,vue会直接对已有的耳标钳进行复用,不会整个的将所有的标签全部重新删除或创建,只会重新渲染数据,然后在创建新的元素知道数据渲染完为止
vue路由
下载 npm install vue-router --save
引入路由,在src下创建一个router的文件夹用来存放路由
在router文件夹下创建一个index.js用来配置路由,相当于路由的一个入口
在index.js中写入如下内容进行路由配置
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../pages/home.vue'
import About from '../pages/index.vue'
Vue.use(Router)
export default new Router({
routes: [
{ path: '/home', component: Home },
{ path: '/index', component: About },
{ path: '/', redirect: '/home' }
]
}
)
在main.js文件中配置路由器
import router from './router'
new Vue({
router,
render:h=>h(App)
}).$mount('#app';)//手动挂载到id为app的dom中的意思
使用<router-link to="/home">Home</router-link>配置路由跳转
路由出口 <router-view></router-view>
二级路由
配置二级路由路径参数中使用children配置
routers:[
{path:'/hot',coomponents:Hot,children:[
//二级路由中,路径不要加载
{path:'01',component:{template:'<p>020202</p>'}},
{path:'03,component:'<p>33333</p>'},
]},
{path:'/mine',component:Mine}
]
在路由页面配置
<!-- 设置路由跳转 -->
<router-link to="/home/era">era</router-link>
<router-link to="/home/erb">erb</router-link>
<!-- 设置路由规则 -->
<router-view></router-view>
路由懒加载
懒加载简单来说就是延迟加载或按需加载,记载需要的时候进行加载。
为了给客户更好的客户体验,首屏组件加载速度更快,解决白屏问题。做一下项目越来越大,vue打包后的js文件也越来越大,这回事影响加载时间的重要因素。当构建的项目比较大的时候,懒加载可以分割代码块,提高页面的初始加载效率
懒加载方式:
ES 提出的import
const HelloWorld = ()=>import('需要加载的模块地址')
vue异步组件懒加载-- resolve
component:resolve=>(require(["引用的组件路径"],resolve))
promise是什么
Promise是一种异步操作额解决方案,将写法复杂的传统的回调函数和监听事件的异步操作,用同步代码的形式表达出来。避免了多级异步操作的回调函数嵌套
1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列
Promise是一个对象,它的内部其实有三种状态。
初始状态( pending )。
已完成( fulfilled ): resolve 方法可以使 Promise 对象的状态改变成成功
已拒绝( rejected ): reject 方法则是将 Promise 对象的状态改变为失败
动态组件
让多个组件使用同一个挂载点,并动态切换,这就是动态组件。
使用is特性来切换不同的组件
<component :is="com"><component>
keep-alive
在上一个demo中我们布丁的切换两个标签页的内容时候,会发现在联系我们选择好的内容,切换路由之后会恢复初始化。
也是就说之前的状态丢失。原因是每次切换路由的时候,Vue都创建了一个新的组件实例
解决这个问题,我们可以用一个 <keep-alive> 元素将其路由出口包裹起来。在切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性
<router-link to="/home">home</router-link>
<router-link to="/index">index</router-link>
<keep-alive>
<router-view></router-view>
</keep-alive>
include与exclude
include 包含的组件缓存
exclude 排除的组件不缓存,优先级大于include
<keep-alive include="bara,barb">
<component :is="text"></component>
</keep-alive>
keep-alive 的钩子函数
activated 类型:function 触发时机:keep-alive组件即或是使用
deactivated 类型:function 触发时机:keep-alive组件停用时调用
这两个生命周期函数一定是要在使用了keep-alive组件之上
自定义指令
语法:
dirctives:{
自定义指令的名字:{
自定义指令钩子函数(el){
操作逻辑
}
}
}
例子:
<script>
// 创建根实例
new Vue({
el: '#app',
directives: {
// 注册一个局部的自定义指令 v-focus
focus: {
// 指令的定义
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
}
})
</script>
钩子
bind:绑定指令到元素上,只执行一次
inserted:绑定了指令的元素插入到页面中展示时调用,基本上都是操作这个钩子函数
update:所有组件节点更新时调用
componentUpdated:指令所在组件的节点及其子节点全部更新完成后调用
unbind:解除指令和元素的绑定,只执行一次
ref和$refs
ref被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的$refs对象上,如果在普通的DOM元素上使用,引用指向的就是DOM元素,如果实在子组件上,引用就指向组件的实例
$refs 是一个对象,持有已注册过 ref 的所有的子组件
可以获取DOM对象
绑定: <p ref="demo">我是ref</p>
获取: this.$refs.demo
ref绑定到组件上可以快速访问到组件实例,及其相关属性方法
<Home ref="comHome"></Home>
<button @click="fun()">点击获取home组件相关内容</button>
获取子组件的data数据/方法:
fun(){
window.console.log(this.$refs.comHome.hometext)
this.$refs.comHome.funb()
}
Axios
npm install --save axios //下载axios
//在src文件加下的main.js中添加
import axios from 'axios'
Vue.prototype.axios = axios
Axios发送请求
this.axios(utl:'请求地址',method:'请求方式',data/params:{k:v}).then((ok)=>{})
使用get发送数据的时候 使用params:{key:val}发送数据
使用post发送数据需要使用 var param=new URLSearchParams();修改传参方法
使用param.append("uname","xixi")添加数据并且使用data发送数据
//get请求
this.axios({
method:"get",
url:"http://localhost:8080/get",
params:{
name:"cwl"
}
}).then(ok=>{
console.log(ok)
})
//post请求
var param = new URLSearchParams
param.append("name","cwl")
this.axios({
method:"post",
url:"http://localhost:8888/post",
data:param
}).then(ok=>{
console.log(ok)
})
mock模拟数据
在前端开发过程中,有后台配合是很必要的。但是如果自己测试开发,或者后台很忙,没时间,那么我们需要自己提供或修改接口。
npm install --save mockjs 下载
在src文件夹下创建相关问价与文件夹
设置请求文件index.js
const Mock = require('mockjs');
//格式 : Mock.mock(设置的请求地址,post/get,返回的数据)
Mock.mock('home','get',require(./json/data));
Mock.mock('about','get',require(./json/data));
引用mock在main.js
require('./mock');//main.js引用模拟数据
请求
axios({
url:"/home",
methods:"get"
}).then((data)=>{
console.log(data)
})
同级/兄弟组件传值——中央事件总线
1、创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁
import Vue from "vue"
export default new Vue
2、在需要传值的组件中用eventBus.emit触发一个自定义事件,并传递参数(emit前加美元符)
创建一个A组件,引入事件总线的js文件,接着添加一个按钮并绑定一个点击事件,进行自定义事件抛出
<template>
<div>
<button @click="fun()">点我兄弟组件传值</button>
</div>
</template>
<script>
import eventBus from "@/assets/Bus.js"
export default {
methods:{
fun(){
eventBus.$emit("pao","我是要传递的数据")
}
}
}
</script>
3、在需要接收数据的组件中用bus.$on监听自定义事件,并在回调函数中处理传递过来的参数
再创建一个B组件,引入eventBus事件总线,在mounted钩子,监听了自定义事件,并把传递过来的字符串参数传递给了on监听器的回调函数
$on:监听当前实例上的自定义事件
<template>
<div>
{text}
</div>
</template>
<script>
import eventBus from "@/assets/Bus.js"
export default {
data(){
return{
text:"默认值"
}
},
mounted(){
eventBus.$on("pao",(msg)=>{
this.text=msg
})
}
}
</script>
VUEX
Vuex是一个专为Vue.js应用程序开发中管理的一个模式
通过创建一个集中的数据存储,方便程序中的所有组件进行访问
vuex只能用于单个页面中不同组件(例如兄弟组件)的数据流通
安装VUEX
npm install vuex --save
配置vuex文件创建在src中创建store文件夹-->与store.js
要使用首先在main.js引入vuex
vuex单一状态树
Vuex 使用单一状态——用一个对象就包含了全部的应用层级状态。至此它便作为一个"唯一数据源"而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
export const store = new Vuex.Store({
state:{
arr:[1,2,3,4,5,6,7,8,9]
}
})
vuex--使用数据源state
使用$store.state.text 调用
例子:
{this.$store.state.text}
一、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于与一般Vue对象里面的data
二、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
三、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中
vuex----Getters属性
getters相当于之前组件中学习的计算属性,getters属性主要是对于state中数据的一种过滤
使用场景:在项目开发中,有时候希望对state中的某个属性在多个组件中展示不同状态
getters:{
//state作为参数
newarr(state){
var newarr=state.arr.filter((v,i)=>{
//过滤出id大于3的内容
if(v.id>3){
return v
}
})
return newarr
}
}
使用 与使用state相同在组件中的计算属性当中使用 this.$store.getters.xxx来进行调用
newtextobj(){
return this.$store.getters.newdataobj
}
Getter特性
一、getters 可以对State进行计算操作,它就是Store的计算属性
二、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
三、 如果一个状态只在一个组件内使用一次或者使用了多次但是展示的形态相同,是可以不用getters
VUEX----Mutations
mutations,里面装着一些改变数据方法的集合,计时把处理数据逻辑方法全放在mutation里面(当触发事件的时候想改变state数据的时候使用mutations)
mutations:{
up(state){
state.arr.forEach((v,i)=>{v.id++})
}
}
注意:不能直接调用一个mutations中的处理函数 要使用this.$storecommit()来进行调用
vuex--Mutations 提交载荷(Payload)
在实际项目中往往会有值传递给mutations 给store。commit传一个附加参数,他就叫做mutation的载荷
多个参数也可以传递一个对象
this.$store.commit('add', { 'num': 20 } )
<button @click="fun(i)">点击修改</button>
fun(num){
this.$store.commit("up",num)
}
mutations:{
up(state,payload){
state.arr.forEach((v,i)=>{
if(i=payload){
state.arr[i].title="已经修改了"
}
})
}
}
VUEX中页面刷新数据丢失问题
使用vue进行开发的过程中,状态管理工具一般使用vuex进行管理。但是修改后的vuex数据存储在内存中,所以当前页面刷新数据会产生丢失现象
使用H5特性 本地存储
created () {
//在页面加载时读取localStorage里的状态信息
if (localStorage.getItem("data") ) {
//replaceState替换数据 Object.assign合并对象
this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(localStorage.getItem("data"))))
}
//在页面刷新时将vuex里的信息保存到localStorage里
window.addEventListener("beforeunload",()=>{
localStorage.setItem("data",JSON.stringify(this.$store.state))
})
},
vuex--Actions
Actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据(但是还是通过mutation来操作,因为只有它能操作)
actions进行操作,使用actions进行异步操作(异步请求)
actions:{
actfun(context){
//调用mutations中的方法
context.commit('dataup')
}
},
mutations:{
dataup(state,payload){
state.arr = payload
}
}
分发action:action通过this.$store.dispatch('xxx');方法触发
vuex-modules
在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。
module:可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
创建文件容纳模块
export let home={
namespaced:true,//namespaced这是属性用于解决不同模块的命名冲突问题
state:{text:"vuex数据"},
mutations:{},
actions:{}
}
在vuex中引用模块
import {a} from "./module/a.js"
export default new Vuex。Store({
modules:{a}
})
使用数据:$store.state.模块名.xxx
vuex----表单处理
当在严格模式中使用vuex时,在属于vuex的state上使用v-model会比较棘手。在用户输入时,v-model会试图直接修改state数据。在严格模式中,由于这个修改不是在mutation函数中执行,这里会抛出一个错误
表单处理解决方式
vuex的思维解决,给<input>中绑定value,然后侦听input或者change事件,在事件回调中调用action
<input type="text" name"uname" :value="arr[0].age" @input="inputfun"/>
调用函数
//绑定事件对象通过e.target.value得到输入框的值并且传入并调用vuex actions
inputfun(e){
this.#store.dispatch("actfun",e.target.value)
}
创建actions调用mutations并接收数据
actfun(context,payload){
context.commit("updata",payload)
}
使用mutations来进行修改
updata(state,payload){
state.arr[0].age=payload
}
Mixins(混入)
Mixins是一种奋发Vue组件中可复用功能的非常灵活的一种方式。
创建
在项目的components新建一个Mixin文件夹内部创建index.js
const myMixin = {
data(){
return {
text:"我是数据"
texta:"我是另一个数据"
}
},
methods:{
fun(){
window.console.log(this.text)
}
}
}
export default myMixin
引用
在你需要引入的页面中注册这个mixins,并且使用
import Mixin from "@/components/Minxin/index.js"
export default{
mixins:[Mixin],
}
使用
页面中可以正常的使用mixins中的数据
{{text}}
全局混入
在任何组件都可以使用
在main中引用 并且使用
import Mixin from "@/components/Mixins/index.js"
Vue.mixin(Mixin)
自定义验证
尝试修改验证规则
验证邮箱 var reg=/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/
字母+数字 let reg=/^(?!\D+$)(?![^a-zA-Z]+$)\S{6,20}$/
字母或数字 let reg = /^[a-z0-9]{6}$/
过滤特殊字符:
function stripscript(s){
var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()&;—|{}[]‘;:”“'。,、?]")
var rs=""
for(var i=0;i <s.length;i++){
rs = rs +s.substr(i,1).replace(pattern,'')
}
return rs
}
eslint代码验证问题
取消lintOnSave:false;
module.exports={
lintOnSave:false,
configreWebpack:{
resolve:{
alias:{
//"别名":"对应的文件夹"
"com":"@/components"
}
}
}
}
axios拦截器
1. 请求拦截器
请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易。
2. 响应拦截器
响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
import axios from "axios"
// 创建axios 赋值给常量service
const service = axios.create();
// 添加请求拦截器(Interceptors)
service.interceptors.request.use(function (config) {
// 发送请求之前做写什么
return config;
}, function (error) {
// 请求错误的时候做些什么
return Promise.reject(error);
});
// 添加响应拦截器
service.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default service

浙公网安备 33010602011771号