Vue相关

组件

流程

  • 创建组件构造器
1
2
3
const cpN = Vue.extend({
template:'HTMLCODE'
})
  • 注册组件
1
Vue.component('cpn',cpN)
  • 组件使用
1
<cpn></cpn>

全局组件和局部组件

  • Vue实例外注册的组件是全局组件
  • Vue实例内注册的组件为局部组件
1
2
3
4
//局部组件注册
component:{
cpn: cpN
}

父子组件

1
2
3
4
5
6
7
8
9
10
11
12
const cpn2 = Vue.extend({
template:`HTML CODE`,
})//子组件

const cpn1 = Vue.extend({
template:`HTML CODE
<cpn></cpn>`,
//这里的cpn是cpn2在cpn1内注册的组件
components:{
cpn: cpn2
},
})//父组件

注意:**cpn2因未在全局注册,所以仅能在cpn1中调用,不能在Vue挂载的部分使用**


更推荐的组件创建方式

1
2
3
Vue.component('cpn1',{
template: `HTML CODE`
})

HTML CODE分离写法

1
2
3
4
5
6
7
8
<scriprt type='text/x-template' id='cpn'>
SOME HTML CODE
</scriprt>

Vue.component('cpn'{
template: '#cpn',
//这里的template的内容即是<script></script>标签里的'SOME HTML CODE'
})

OR

1
2
3
4
5
6
7
8
<template id='cpn  '>
SOME HTML CODE
</template>

Vue.component('cpn'{
template: '#cpn',
//这里的template的内容即是<template>标签里的'SOME HTML CODE'
})

组件访问数据的范围

  • 组件不能直接访问Vue实例的data

component内也有data选项,但是data选项应该是一个返回对象的函数而不是对象

1
2
3
4
5
6
7
8
Vue.component('cpn',{
template: `HTML CODE`,
data(){
return {
message: 2,
}
}
})

为什么data不能是对象??

​ 因为当有多个组件实例时,若data是对象则多个实例会共享data里的值,而将data设计为函数,每次实例化组件时都会为当前组件调用data函数返回一个对象,与其余实例不共享。所以在设计Vue的时候才会这样设计,强行写为对象会报错。

1
2
3
4
5
6
7
8
9
10
example(){
return {
value:1,
}
}

const a = example();
const b = example(); //每次实例化都创建一个新的对象,a,b地址不同
b.value = 2;
//此时a.value = 1; b.value = 2
1
2
3
4
5
6
7
8
9
10
const obj = {
value:1,
}
example(){
return obj; //return的是obj的地址
}
const a = example();
const b = example();
b.value = 2;
a.value == b.value //true

父子组件的通信

父传子

通过props属性传递,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
<cpn :Cmessage='message'></cpn><!--绑定VM实例下的message到cpn的props下的Cmessage-->
<template id='cpn'>{{Cmessage}}</template>
<script>
//子组件
const cpn = {
template: '#cpn',
//props:['Cmessage'] //数组写法
props:{
//Cmessage: String, //这里的String是对Cmessage进行类型限制,必须为String
//这是完整写法,为一个对象
Cmessage:{
type: String,
default: 'default value'
require: //这里填一个Boolean,表示组件创建时此值是不是必须的
}
}
data(){
return {};
},
}
//父组件
const VM = new Vue(){
el:'',
data:{
message: 'this is a message'
},
components: {
cpn: cpn
}
}
</script>

注意:**props的验证还可以自定义**

子传父

通过自定义事件

$emit(‘event-name’,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
34
35
36
37
38
39
40
41
42
43
44
<cpn :Cmessage='message'></cpn>
<template id='cpn'>
<button @click='clicked(Cmessage)'> //点击事件发生主席那个clicked并以Cmessage作为参数
emit click
</button>
</template>
<script>
//子组件
const cpn = {
template: '#cpn',
props:{
Cmessage:{
type: String,
default: 'Cmessage '
}
}
data(){
return {

};
},
methods:{
clicked(Cmessage){
this.$emit('cpn-click'Cmessage)//发射cpn-click事件到父组件,并传Cmessage
}
}
}
}
//父组件
const VM = new Vue(){
el:'',
data:{
message: 'this is a message'
},
components: {
cpn: cpn
},
methods:{
cpn-click(Cmessage){
console.log(Cmessage);
}
}
}
</script>

关键字

this.$children可以获取this(Vue实例)的子组件数组通过下标来查询具体某一项组件(不推荐这种方式)

$refs

1
2
3
<cpn ref='a'></cpn>//若有一个组件像这样添加了refs属性

this.$refs.a//则可以这样来获取此组件

$parent可以获取组件的父组件

$root可以访问根组件

插槽slot

流程

  • slot定义
1
2
3
4
5
6
<template id='cpn'>
HTMLCODE
<slot></slot>
<!--<slot><p>default value</p></slot>-->
<!--插槽还可以具有默认值,手动赋值会覆盖此默认值-->
</template>

这里为cpn组件预留了一个slot插槽

  • 插槽使用
1
2
<cpn><button>click</button></cpn>
//这里把slot替换为了一个button

slot的name

默认替换的是无name属性的插槽

若要选定某name的插槽,则需要

1
2
3
4
5
6
7
8
9
10
11
12
例如:
<template id="cpn">
<div>
<h2>组件</h2>
<p>组件组件</p>
<slot name="left"><span>left</span></slot>
<slot name="center"><span>center</span></slot>
<slot name="right"><span>right</span></slot>
</div>
</template>

<cpn><span slot='left'>left will be cover</span></cpn>

作用域插槽

想要把子组件的数据传到父组件进行显示,如下

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
<!--以下方式是无法取到cpn里的things的-->
<template>
<slot>

</slot>
</template>
<cpn>
<ul >
<li v-for='item in things'>{{item}}</li>
</ul>
</cpn>
<!--------------------------------------------->
<!--要想完成上述目标则需要如下-->
<template>
<slot :things = 'things'>
<!--这里的:things可以是任何自定标识符-->

</slot>
</template>

<cpn>
<div slot-scope = 'slot'>
<!--这里的'slot'也是可以自定义的-->
<ul>
<li v-for='item in slot.things'>{{item}}</li>
</ul>
</div>
</cpn>
<script>
const app = new Vue({
el:'',
data:{},
components:{
cpn:{
template:
data(){
things:['thing1','thing2'].
}
}
}
})
</script>

作用域

看下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>app.isShow</div>
<div v-show='isShow'>cpn.isShow</div>
</template>
<cpn v-show='isShow'/>
<script>
const app = new Vue({
el:'',
data:{
isShow:true,
},
components:{
tempalte: ,
data(){
return{
isShow:false,
}
}
}
})
</script>
//cpn的v-show会绑定到Vue实例app的isShow
//cpn内的div的v-show会绑定到cpn的isShow

模块化

为什么需要模块化?

为了避免同一个项目下各个文件中变量作用域冲突造成的奇怪问题和节省开发成本

老旧的做法是使用匿名函数和模块导出

1
2
3
4
5
6
7
8
9
10
11
12
var mouduleA = (function(){
var obj = {};
var flag = true;
function sum(num1,num2){
return num1+num2;
}
obj.flag = flag;
obj.sum = sum;
return obj
})
//现在mouduleA为obj,可以在其他js文件中通过mouduleA.flag和moduleA.sum(num1,num2)来调用

常用的模块化规范:

  • CommonJS(node.js)
  • AMD
  • CMD
  • Modules

CommonJS做法

node环境下

  • 导出
1
2
3
4
5
6
7
8
9
//这是一个名为moduleA.js的文件
var flag = true;
function sum(num1,num2){
return num1+num2;
}
module.exports={
flag, //也可以写成flag:flag,
sum,
}
  • 导入
1
2
var moduleA = require('moduleA.js')
//现在可以通过mouduleA.flag和moduleA.sum()来获取

ES6做法

1
2
<script src="moduleA.js" type="module></script>
<!--规定type="module"后,每个js文件都有单独的空间,其余js文件不得直接访问,需要导出-->
  • 导出
1
2
3
4
5
6
7
8
//这是一个名叫moduleA.js的文件
var flag = true;
function sum(num1,num2){
return num1+num2;
}
//导出
export{flag,sum};

  • 导入
1
2
3
4
import {flag,sum} from "moduleA.js"
//或者
import * as mouduleA(别名) from 'moduleA.js'
//这样可以通过mouduleA.flag来取得变量

PS(export default)

  • 导出
1
2
3
//moduleA.js
export default flag
//export default 只能导出一项
  • 导入
1
2
import f from 'moduleA.js'
//这里的f就是moduleA.js中的flag

Webpack与node

前端模块化打包工具

webpack依赖node环境

1
2
3
4
//安装webpack
npm init
npm install (--save-dev) webpack@版本号 -g
//--save-dev 是本地安装webpack命令

webpack配置文件

创建一个**webpack.config.js**文件

1
2
3
4
5
6
7
8
9
10
11
//webpack.config.js内容
const path = require('path') //导入node中的path

moudule.exports={
//表示打包的入口文件
entry: './src/main.js'
//表示打包形成的目标文件
output:{
path: path.reslove(__dirname,'dist'), //path必须是绝对路径,这里动态获取__dirname是node里获取当前路径的常量
filename:'bundle.js'
}

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
//创建npm run bulid 和webpack命令的映射
"bulid": "webpack"
},
"author": "",
"license": "ISC"
}
//若在命令行键入npm run bulid则等效于键入webpack命令
//并且优先在本地webpack中(./node_modules/bin)找命令

loader

npm安装loader(以css为例)

  • 安装
1
2
npm install --save-dev css-loader
npm install --save-dev style-loader
  • 配置

在webpack.config.js中配置

1
2
3
4
5
6
7
8
9
10
11
//新添加module对象,如下
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
//css-loader负责解析加载css
//style-loader负责提交css到DOM上
}
]
}

**注意:**有时候css-loader与style-loader的版本过高或者过低会出现问题,这时候在package.json里手动调低或者调高版本号即可

图片loader

  • 安装url-loader
1
npm install --save-dev url-loader
  • webpack.config.js配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
//当加载的图片小于limit的字节数,图片url会被编译称base64字符串形式
//如果大于limt则会通过file-loader来编译,file-loader不需要特别配置
limit: 8192,
//name是指通过file-loader生成的图片打包在dist下的img文件夹且命名为:原文件名+8位hash值+扩展名
name: 'img/[name].[hash:8].[ext]'
}
}
]
}
]
}
}
1
2
//file-loader安装
npm install --save-dev file-loader@版本号

注:**通过file-loader加载图片,路径会在output中path所指的文件夹中,

​ 若html入口程序不在dist则浏览器无法正确找到

​ 需要在webpack.config.js的output中修改配置

1
publicPath: 'dist/'

ES6转ES5

  • 工具: babel
1
2
//安装,这是一个旧版的babel
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
  • 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module: {
rules: [
{
test: /\.js$/,
// exclude是写入不进行转换操作的文件夹
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]
}

wepack配置Vue

  • 安装
1
npm install vue
  • 引入
1
2
3
//main.js
import Vue from 'vue'
//这里会直接在node_modules里找vue

注意:需要在webpack.config.js中配置下面这一段代码来处理runtime-only和runtime-compiler的问题

1
2
3
4
5
6
resolve: {
alias: {
//这里设置了import Vue from 'vue'时vue的寻找路径,包含了runtime-compiler
'vue$': 'vue/dist/vue.esm.js'
}
}

runtime-only不能编译vue模板

runtime-compiler可以编译

Vue如何简化开发

1
2
3
4
5
6
7
8
9
10
const app = new Vue({
el:'#app',
template:`
<div>{{message}}</div>
`,
data{
message:'hello',
},
//这里Vue会把template的内容直接拷贝到挂载的html文档上
})
  • 第一种开发方式

在vue实例内写html模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const app = new Vue({
el: '#app',
template: `
<div>
<h2>{{message}}</h2>
<h3>{{name}}</h3>
<button @click='btnclick'>click</button>
</div>
`,
data: {
message: 'hello',
name: 'EE'
},
methods: {
btnClick() {
alert('click??');
}
}
})
  • 第二种开发方式

在组件内写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
25
26
27
28

import Vue from 'vue'

const App = {
template: `
<div>
<h2>{{message}}</h2>
<h3>{{name}}</h3>
<button @click='btnClick'>click</button>
</div>
`,
data: {
message: 'hello',
name: 'EE'
},
methods: {
btnClick() {
alert('click??');
}
}
}
const app = new Vue({
el: '#app',
template: `<App/>`,
components: {
App,
}
})
  • 第三种方式

把组件抽离成一个单独的js文件后导出,再在main.js中引入此组件即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//app.js
const App = {
template: `
<div>
<h2>{{message}}</h2>
<h3>{{name}}</h3>
<button @click='btnClick'>click</button>
</div>
`,
data() {
return {
message: 'hello',
name: 'EE'
}
},
methods: {
btnClick() {
alert('click??');
}
}
}
export default App
1
2
3
4
5
6
7
8
9
10
//main.js
import App from './src/js/vue/app.js'

const app = new Vue({
el: '#app',
template: `<App/>`,
components: {
App,
}
})
  • 第四种开发方式

创建.vue文件,将组件的模板,js代码,样式整合到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
//app.vue

<template>
<div>
<h2 class='title'>{{message}}</h2>
<h3>{{name}}</h3>
<button @click='btnClick'>click</button>
</div>
</template>

<script>
export default {
name:'App',
data() {
return {
message: 'hello',
name: 'EE'
}
},
methods: {
btnClick() {
alert('click??');
}
}
}
</script>

<style scoped>
.title{
color: blue;
}
</style>
1
2
3
4
5
6
7
8
9
10
//main.js
import App from './src/js/vue/app.vue'

const app = new Vue({
el: '#app',
template: `<App/>`,
components: {
App,
}
})

注意:需要安装vue-loader vue-template-compiler

  • 安装
1
npm install vue-loader@15.4.2 vue-template-compiler@2.5.21 --save-dev
  • 配置
1
2
3
4
5
//webpack.config.js
{
test: /\.vue$/,
use: ['vue-loader']
}

plugin

添加一个版权提示插件

BannerPlugin是webpack自带的所以不用另外下载

1
2
3
4
5
6
7
//webpack.config.js
const webpack = require('webpack')
module.exports={
plugins:[
new webpack.BannerPlugin("最终解释权归EE所有")
]
}

HtmlWebpackPlugin

生成index.html到dist

  • 安装
1
npm install html-webpack-plugin --save-dev
  • 配置
1
2
3
4
5
6
7
8
//webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

plugins:[
new HtmlWebpackPlugin({
template:'index.html'//根据index.html为模板生成
})
]

JS压缩插件

  • 安装
1
npm install uglifyjs-webpack-plugin --save-dev
  • 配置
1
2
3
4
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
plugins:{
new UgilifyjsWebpackPlugin()
}

本地node服务器

本地内存启用服务器,加快调试速度

  • 安装
1
npn install webpack-dev-server --save-dev
  • 配置
1
2
3
4
5
6
//webpack.config.js
devServer:{
contentBase:'./dist',//选定服务dist文件夹
inline:true,//实时监听
port://端口号
}
1
2
3
4
//package.json
"script":{
"dev":"webpack-dev-server --open"//映射到dev
}
  • 启动
1
npm run dev

webpack开发时配置和发布时配置分离

生产和开发时的配置大多数时都不相同,把不同时期的配置文件分开管理是一个比较好的做法

项目根目录下建立文件夹config,包含一下三个文件

**base.config.js:**基础配置

dev.config.js开发时配置

prod.config.js生产打包配置

  • 安装webpack-merge
1
npm install webpack-merge --save-dev
  • 配置
1
2
3
4
5
6
7
8
9
10
//dev.config.js

const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config.js')//拿到base.config.js的内容

module.exports = webpackMerge(baseConfig,{
plugins:[
...//开发时需要的plugins
]
})
1
2
3
4
5
6
7
8
9
10
//prod.config.js

const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config.js')//拿到base.config.js的内容

module.exports = webpackMerge(baseConfig,{
plugins:[
...//生产打包需要的plugins
]
})

我们需要重新指定package.json里的script项才能使得命令绑定且使用我们想要的配置文件

1
2
3
4
5
//package.json
"script":{
"bulid": "webpack --config ./bulid/prod.config.js",
"dev":"webpack-dev-server --open --config ./bulid/dev.config.js"
}

执行打包

​ 发现打包的文件夹dist放在了当前config目录下

修改base.config.js下

1
path: path.resolve(__dirname, '../dist'),

Vue CLI(version-3)

快速生成Vue开发环境,自动配置webpack

cnpm

  • 安装
1
npm install -g cnpm --registry=https://registry.npm.taobao.org

CLI安装

1
npm install -g @vue/cli@版本号vue -v

VueCLI(version-2)

  • 创建项目
1
vue init webpack 项目名
  • 流程
1
2
3
4
5
6
7
8
9
10
11
Project name (项目名)
Project description //项目描述
Author //作者

Runtime + Compiler:
Runtime-only:

Install vue-router?
Use ESlint to lint your code? //检查代码规范
Set up unit tests //单元测试
Setup e2e tests with Nightwatch //依赖Nightwatch的端到端测试

runtimeonly

此版下vue工作流程

render -> virtual dom ->DOM

render

template会被解析为render

.vue文件会被解析为render可处理的对象

1
2
3
4
5
6
7
8
//函数原型
render: function (creatElement){
return createElement('h2',
{class:'box'},
['content',createElement('button',[button])] )
}
//这个render将创建一个
//<h2 class='box'>content<button>button</button></h2>

传入组件对象

1
2
3
4
5
6
7
8
9
10
11
12
const cpn = {
template:'<div>hello {{message}}</div>',
data(){
return{
message:ee
}
}
}

render:function(creatElement){
return creatElement(cpn)
}

runtime + compiler

此版下vue工作流程

template -> ast -> render -> virtual dom ->DOM

ES6箭头函数

多用于将函数作为参数传入时

1
2
3
4
5
6
7
8
//传统函数
const f = function(num){

}
//箭头函数
const f = (num) =>{

}

单个参数简写

1
2
3
4
5
6
7
8
//一般箭头函数
const f = (num) =>{
return num*num
}
//省略后
const f = num =>{
return num*num
}

仅一行代码时简写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//一般写法
const f = (num) =>{
return num*num
}
//省略写法
const f = (num) => num*num


//-----------无返回值时--------------//

//一般写法
const f = (num) =>{
console.log(num)
}
//简写
const f = (num) => console.log(num)

箭头函数中this的指向问题

VUE-router

后端路由

由后端处理URL和HTML文档的映射关系

前后端分离

后端只提供数据,前端请求后端数据并展示

前端路由

SPA页面

仅一个静态资源(html css js) 页面

根据用户意愿来抽离出静态资源的某部分来展示

vue-router

  • 安装
1
npm install --save vue-router

**PS:**CLI创建时可自动安装

配置

  • src下创建router文件夹

  • 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
26
27
//index.js

//引入
import VueRouter from 'vue-router'
import Vue from 'vue'

//安装插件
Vue.use(VueRouter)

//创建路由对象
const router = new VueRouter({
//配置路径和组件的映射关系
routes: [
{
path:'',
//重定向默认网页到首页home
redirect:'/home'
},
{
path:' ',
component:
}
],
//将路由模式选择为history模式
mode:'history'
})
export default router
1
2
3
4
5
//main.js
import router from './router/index.js'
new Vue({
router: router
})

使用

  • router-link
  • router-view

在根vue组件的template中添加

1
2
3
4
5
6
7
<!--router-link会渲染为通向to的<a></a>标签-->
<router-link to='/home1'></router-link>
<router-link to='/home2'></router-link>
<router-link to='/home3'></router-link>

<!--router-view用来显示所指向的组件内容-->
<router-view></router-view>

router-link详解

1
2
3
4
5
6
7
<router-link to='' tag='' replace></router-link>
<!--
to属性:指明路由到的地址
tag属性:指明router-link渲染为什么标签,默认为<a>
replace:有此属性表示为replace模式路由
-->
<!--被点击后,渲染后的标签会添加一个class-->

通过监听点击事件,执行this.$router.push('/home')或者this.$router.replace('/home')

$router是vue默认添加的一个数据

动态路由

案例

例:一个用户名为EE,userID:EE9696

我们要进入这个user的页面 即:(/user/EE96966)就需要动态路由

并且我们需要把此user 的ID:EE展示在其页面上

1
2
3
4
5
6
7
8
9
//router/index.js
route:[
{
//动态绑定userid router-link的to会覆盖此属性
path:user/:userid
//当然使用user.vue前需要import
component: user
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--App.vue-->
<template>
<router-link :to='finalID-path'></router-link>
</template>
<script>
export default {
name:'App',
data(){
return{
name:EE //userName
ID:EE9696, //需要的用户ID
}
},
computed:{
//得到finalID=/user/EE9696
finalID(){
return '/user/'+this.ID
}
},
}
</script>

$route与与展示ID

$route拿到的是当前活跃的路由

​ 注意与**$router区别:$router**拿到的是router对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--user.vue-->
<template>
<div>
<p>
ID:{{userID}}
</p>
</div>
</template>
<script>
export default{
computed:{
userID(){
//this.$route指当前活跃的路由
//params指参数
//userID是配置路由时route的动态path--:userID
return this.$route.params.userID
}
}
}
</script>

路由懒加载

将所有业务代码打包到同一个js文件在网站加载时会非常慢

把不同路由对应的组件封装到不同的js中,这样在需要时再加载会提高效率,即路由的懒加载

使用方法

  • 传统的配置方法
1
2
3
4
5
6
7
8
//router/index.js
import home from '../component/home.vue'
const routes = [
{
path:'/home',
component:'home'
}
]
  • 懒加载配置方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//router/index.js
const routes = [
{
path:'/home',
component:()=> import(../component/home.vue)
}
]

//你也可以这样写
const home = () => import(../component/home.vue)
const routes =[
{
path:'/home',
component" home
}
]

路由嵌套

案例

要在/home页面下设置/home/news/home/message

配置和使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//router/index.js
//使用前引入,安装(省)
const routes:[
{
path:'/home',
component:home,
children:[
{
//嵌套的子组件路径前不加/
path:'news',
component:news,
},
{
path:'message',
component:news
}
]
}
]

因为我们是在home页面下配置的嵌套子路由,所以我们要在home.vue下配置router-linkrouter-view

1
2
3
4
5
6
7
8
9
<!--home.vue-->
<template>
<div>
<!--注意这里to必须是完整的路径,因为to不会切换到当前路径-->
<router-link to='/home/news'>News</router-link>
<router-link to='/home/message'>Message</router-link>
<router-view></router-view>
</div>
</template>

PS:嵌套路由也可以默认重定向

路由传参

params

  • 路径配置格式: path: '/router/:id'=>形成的路径格式/router/id(变值)
  • 获取:直接通过{{$route.params.id(与path中的命名一致)}}获取

query

  • 路由配置格式:普通格式

  • router-link配置:这时的to=''里是一个对象

    • 对象内容:
    1
    2
    3
    4
    5
    6
    7
    {
    path:''//路由的路径
    query:{
    //这里是传入的数据
    data: value
    }
    }
  • 获取:在相应的组件中通过{{$route.query.**}}获得

    • $route会自动传入data中,所以可以直接获取

$router & $route详解

全局导航守卫

​ 用于监听路由跳转的过程。

beforeEach

1
2
3
4
5
6
7
//router/index.js
router.beforeEach((to,from,next) => {
//这里必须调用next()函数,用于跳转到下一个守卫
next()
//这里的CODE会在跳转前执行
CODE
})

afterEach

1
2
3
4
5
//router/index.js
router.beforeEach((to.from) => {
//这里的CODE会在跳转后执行
CODE
})

路由独享守卫

组件内守卫

vue-keepalive

vue组件的状态在跳转后不会被保存,每次会创建一个新的组件。这样不仅消耗资源,并且会带来一些使用上的问题

我们使用vue内置组件<keep-alive>来解决

  • 用法
1
2
<keep-alive><router-view></router-view></keep-alive>
<keep-alive include=''></keep-alive>
  • include和exclude参数
    • include:'':仅’’内的组件套用keep-alive
    • exclude:'':’’外的组件套用keep-alive
    • ''内为正则表达式或字符串

activated()&deactivated

​ 在当前组件活跃(不活跃)时执行的函数

必须在<keep-alive>内包含的组件才能使用这两个函数

TabBar实例

  • **SampleString.indexOf(String)**方法

返回括号内StringSampleString第一次出现的位置,若没有出现则返回-1

ES6 Promise

Promise 用于封装异步操作

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Promise使用时需要new,并且传入一个带resolve, reject两个参数的函数
//而resolve和reject也是两个函数
new Promise((resolve,reject) => {
//成功时调用resolve函数会跳转到当前Promise的then处执行函数func
//data = ajax(url)
resolve(data)

//失败是调用reject函数会跳转到当前Promise的catch处
reject(err)
}).then( (data) => {
//这里的data就是resolve()传入的data
}).catch((err) => {
//这里的err就是reject传入的err
})

若需要嵌套调用异步操作,则需要在then或者catch中返回一个新的Promise对象

Promise的三种状态

PromiseStatus

VUEX(待办)

axios

安装

1
npm install axios

导入

1
import axios from axios

基本使用

  • 基本使用
1
2
3
4
5
axios({
url:'',
params:{}
method:'' //get OR post
})

method省略后也可以简写

​ 例如:

1
2
3
axios.post({
url:''
})

axios.all()发送并发请求

场景:需要发送两个请求,并且两个请求均返回时再进行处理

可以使用

axios.all()

1
2
3
4
5
6
7
8
9
10
axios.all(
[axios({
url:''
}),
axios({
url:''
})
]).then(response =>{
//注意这里的response是一个数组,带有两个请求返回的结果
})

axios的两个常用配置

axios.defaults.baseURL

场景:需要向’http://sample.com'下频繁发送请求

1
2
3
4
5
axios.defaults.baseURL = 'http://sample.com'

axios.get({
url:'/home'//现在自动在前面添加baseURL
})

axios.defaults.timout

设置超时

1
2
//这里设置请求时间超过5000ms为超时
axios.defaults.timout = 5000

axios实例

之前设置的axios配置是全局配置,若需要向不同的服务器发送请求,那么全局配置就不适用了,这就需要axios实例

  • 创建实例
1
2
3
4
const axiosSample = axios.create({
baseURL = '',
timeout = ''
})
  • 使用实例
1
2
3
4
5
6
7
8
//使用方法与原型一模一样
axiosSample.get({
url:'',
params:{
type:
...
}
})

axios封装

设想一下,你的每个程序都是用axios框架发送网络请求,但是某一天axios突然挂掉。那么需要重构的代码量将会非常巨大,为了应对这种情况,我们对框架做一层封装。

基本思路

  • 封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//建立一个request.js文件作为axios封装的文件夹
import axios from 'axios'

export function request(config, success, failure) {
//创建axios实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})

instance(config)
.then(res => { success(res) }) //成功时调用success
.catch(err => { failure(err) })//失败时调用failure
}
  • 使用

    现在我们可以使用我们封装好的request函数

1
2
3
4
5
6
7
8
9
10
11
import {request} from '../network/request.js'
//通过bitcorn提供的api打印bitcorn实时价格
request({
url:'https://api.coindesk.com/v1/bpi/currentprice.json'
},
res =>{
this.info = res.data.bpi
},
err=>{
console.log(err)
})

更好的封装方式

1
2
3
4
5
6
7
8
9
10
11
12
13
import axios from 'axios'

export function request(config) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: '',
timeout: 5000
})
instance(config)
.then(res => resolve(res))
.catch(err => reject(err))
})
}

如此一来我们可以这样使用

1
2
3
4
5
6
7
import {request} from '../network/request.js'

request({
url:''
})
.then(res=>{})
.catch(err=?{})

实际上axios返回的就是一个Promise对象,所以我们完全不用自建Promise

  • 最终的封装方式
1
2
3
4
5
6
7
8
9
import axios from 'axios'

export function request(config) {
const instance = axios.create({
baseURL: '',
timeout: 5000
})
return instance(config)
}

axios拦截器

为上面的封装添加拦截器

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
import axios from 'axios'

export function request(config) {
const instance = axios.create({
baseURL: '',
timeout: 5000
})
//请求拦截器
instance.interceptors.request.use(
req=>{
//请求发送成功时的操作,并且拦截到了请求
//添加一条return req才能继续请求,要不然请求被拦截
return req
},
err=>{
//请求发送失败时的操作
}
);
//响应拦截器
instance.interceptors.response.use(
res=>{
//在这里对拦截到的响应作操作
//同样需要return
return res
},
err=>{

}
)
//发送请求
return instance(config)
}
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 1970-2020 John Doe
  • Visitors: | Views:

请立刻给我钱

支付宝
微信