vue项目开发(一)

ES6

let和const命令

  • let

    块级作用域

    变量作用域不会提前声明

    相同作用域内不能重复声明同一个变量
    for循环中的父子作用域

  • const(内存地址不变,所以是常量)

    与let的作用域相同

    const一单声明常量就立即被初始化。

    只声明不赋值也会报错

注意
const一般用在定义模块中的常量
let限制了变量的作用域,保证变量不去影响全局变量,所以尽量用let代替var

变量的解构赋值

数组的解构赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//传统赋值
let a=1;
let b=2;
let c=3;

//es6中解构赋值
let [a,b,c]=[1,2,3]

//允许使用默认值

let [foo=true]=[];
let [boo=1]=[undefined]; // 1
console.log(foo) // true

let [x,y='123']=['a']
console.log(x)// a
console.log(y) // 123

这种写法属于模式匹配,只要等号左右的模式相同,就会对号入座

对象的解构赋值

数组的元素是按次序排列的,变量的取值由特德位置决定的,而对象的属性没有次序,变量必须与属性同名,才能取到正确的值

1
2
3
let {bar,foo}={foo:"123",bar:"222222"};
console.log(bar) //123
console.log(foo) //222222

如果变量名和属性名不一致就应该这样书写(类似重命名属性)

1
2
3
4
5
6
7
8
9
10
11
12
let obj = {less01:"00001",less02:"00002"};
console.log(obj) //{ less01: '00001', less02: '00002' }

let {less01:l1,less02:l2}=obj
console.log(l1) //00001
console.log(l2) //00002

//简写如下形式
let {rightNumber:R,leftNumber:L}=
{rightNumber:"r00001",leftNumber:"l00001"};
console.log(R)
console.log(L)

经验:对象的解构赋值的内部机制,是先找到同名属性 再赋给对应的变量 真正被赋值的是后者,而不是前者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 示例:
let {foo:baz}={foo:"aaa",bar:"bbb"};
console.log(baz); //aaa
console.log(foo) //foo is not defined

foo是匹配的模式
baz才是变量,真正被赋值的是变量baz,而不是模式foo


//对象的结构也可以使用默认值
let {x:y=1234}={};
console.log(y) //1234

let {x:y=1234}={x:5678};
console.log(y) //5678

上机训练

箭头函数

箭头函数起因
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
//setInterval函数是在全局作用域window下执行的,window上找不到属性username和age
const Person={
username:"小陈",
age:"23",
sayHello:function(){
setInterval(function(){
console.log('这是'+this.username+"他今年"+this.age+"岁");
},1000)
}
}

Person.sayHello() //这是undefined他今年undefined岁

// 缓存this进行使用(问题:明明写在对象里面的方法,为什么还要使用缓存对象才能使用呢?)
const Person={
username:"小陈",
age:"23",
sayHello:function(){
let that=this;
setInterval(function(){
console.log('这是'+that.username+"他今年"+that.age+"岁");
},1000)
}
}
Person.sayHello() //这是小陈他今年23岁

//es6中箭头函数
箭头函数的定义
箭头函数和普通函数相比的优势
  • 不绑定this和arguments
  • 更简洁的代码语法

说明:不绑定this

1
2
3
4
5
6
7
8
9
10
11
//箭头函数的this在定义的时候就已经确定了,之后不管什么时候调用,this都是之前定义时的this,

function Person(name,age){
this.name=name;
this.age=age;
setInterval(()=>{
console.log(`我的名字叫${this.name}我今年${this.age}岁`)
},3000)

}
let p=new Person('chenhang',20);

说明:不绑定arguments

1
2
3
4
5
//所以在箭头函数中不能直接使用arguments对象,
//如果需要获得函的参数又该怎么办呢?可以使用余参数来取代arguments

let func=(...args)=>console.log(args.length);
func(1,2,3,4,5,6) // 显示打印 6

箭头函数不适应的场景
  • 对象的方法中不建议使用箭头函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const Person={
    username:"陈子",
    age:20,
    say:()=>{
    console.log('111') //111
    setInterval(()=>{
    console.log(this.username+'----'+this.age)
    },2000) //undefined----undefined
    }

    }
    Person.say()

    /*
    输出结果有问题,因为方法 在了对象里,而对象的括号是不能封闭作用域的,所
    以此时的 this 还是指向全局对象,而全局对象下没有 usemame age 属性,所以会出现
    问题
    */
  • 不能作为构造函数

    1
    2
    3
    4
    /*
    由于箭头函数的 this 具有不绑定的特点,不能使用箭头函数作为构造函数,如果这
    样做了,也会报错。
    */
  • 定义原型方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    function Student(){
    this.username="成成"
    }

    Student.prototype.sayName=()=>{
    console.log(this.username) //报undefined
    }
    var p=new Student();
    p.sayName()
    /*
    出现问题的原因是 his 指向 window 象,这和使用箭头函数在对象中定义方法十
    分类似
    */

Map数据结构

js中的对象是键值对形式的集合(Hash结构),键只能是字符串类型

对象提供了’字符串-值’,Map提供了’值-值’的对应

创建Map
  • Map 可以接受 个数组作为参数,该数组的成员是 个个表示键值对的数组
    1
    2
    3
    4
    5
    const MapTree=new Map([
    ['name','chenhang'],
    ['age',20]
    ]);
    console.log(MapTree) // { 'name' => 'chenhang', 'age' => 20 }
Map常用的属性和方法
  • size返回Map的成员总数

    1
    console.log(MapTree.size)  //2
  • set 方法设置键名 key 对应的键值为 value ,然后返回整个 Map 结构。

  • 如果 key有对应的键值,则键值会被更新,否则就新生成键值。
  • set方法返回的是当前的 Map对象 因此可以采用链式写法。
1
2
3
4
5
6
7
8
9
MapTree.set('address',"上海市闵行区").set('sex','男');
console.log(MapTree)
/*
Map {
'name' => 'chenhang',
'age' => 20,
'address' => '上海市闵行区',
'sex' => '男' }
*/
  • has方法 放回一个布尔值判断某个键是否在当前的Map对象中

    1
    2
    console.log(MapTree.has('sex'))  //true
    console.log(MapTree.has('sex2')) //false
  • delete方法 删除键成功返true,删除失败返回false

    1
    2
    3
    console.log(MapTree.delete("address"))  //true
    console.log(MapTree)
    //Map { 'name' => 'chenhang', 'age' => 20, 'sex' => '男' }
  • 遍历方法

    Map结构提供三个遍历器生成函数和一个遍历方法

    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
    // keys()  返回所有键的遍历器
    const a=MapTree.keys();
    console.log(a) //MapIterator { 'name', 'age', 'sex' }

    for(let key of MapTree.keys()){
    console.log(key+"----这是key")
    }

    // values() 返回所有值的遍历器
    const b=MapTree.values();
    console.log(b) //MapIterator { 'chenhang', 20, '男' }

    for(let value of MapTree.values()){
    console.log(value+"----这是value")
    }
    //entries() 返回所有成员的遍历器
    const c=MapTree.entries();
    console.log(c) //MapIterator { [ 'name', 'chenhang' ], [ 'age', 20 ], [ 'sex', '男' ] }

    for (let [key,value] of MapTree.entries()){
    console.log(key,value)
    }
    /*
    name chenhang
    age 20
    sex 男
    */


    // forEach() 遍历Map所有的成员
    MapTree.forEach((value,index)=>{
    console.log(value+'--'+index);
    })
    /*
    chenhang--name
    20--age
    男--sex
    */

Module语法

es6之前社区使用CommonJS规范(服务器端)和AMD规范(浏览器端),
ES6 模块的设计思想是尽量静态化,使得编译时就能确定模块的依赖关系,以及输
入和输出的变量。

export
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//第1种写法
export var firstName = ’Michael';
export var lastName =’Jackson';
export var year= 1958;

//第2种写法
var firstName =’Michael’,
var lastName =’Jackson';
var year= 1958;
export { firstName, lastName, year } ;

//还可以导出函数
export function multiply(x, y) {
return x * y;
}
导出多个函数
function v1() { }
function v2() { }

export {v1,v2}
import
1
2
3
4
5
6
//main.js
import {firstName, lastName, year} from ./rofile js

function setName(element) {
element.textContent = firstName +’’+ lastName;
}
export default

使用 import 命令时,用户需要知道所要加载的变量名或函数名,否则将无法加载

1
2
3
4
5
6
7
// export-default.js
export default function () {
console.log('foo');
}
// import-default.js
import customName from './export-default
customName(); //foo

import 可以为匿名函数指定任意名字
,这时就不需要知道
原模块输出的函数名。需要注意的是,这时 import 令后面不使用大括号。

使用 export default 时,对 import
语句不需要使用大括号:不使用 export default 时,对应的 import 语句需要使用大括号。
export default 令用于指定模块的默认输出。显然 模块只能有 个默认输出,因此
expo default 令只能使用 所以 import 命令后面才不用加大括号,因为只能唯
对应 export default 命令

Promise对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const promise=new Promise(function(resolve,reject){
var value="成功值";
if(true){
resolve(value)
}else{
reject(error)
}
})

promise.then(function(value){
console.log(value)
})

/*
resolve 函数的作用是将 Promise 象的状态从“未完成”变为“成功”(即从 pending
变为 resolved ),在异步操作成功时调用,并将异步操作的结果作为参数传递出去。
reject 函数的作用是将 romise 象的状态从“未完成”变为“失败”(即从 pending
变为 ected ), 在异步操作失败时调用,并将异步操作的报错作为参数传递出去
*/

项目的路由配置

在 HTML5 history
API 出现之前,前端路由都通过 hash 实现, hash 能够兼容低版本的浏览器 如果把
节的 阳例子用 hash 来实现的话,它的 URI 规则中需要带上呀”。

什么是前端路由

1
2
3
4
/*
前端路由通过配置js文件,将这个工作拿到前端来完成。
路由就是根据不用的url来展示对应的内容和页面
*/

前端路由的使用场景

1
主要适用于单页面,spa基本是前后端分离,所以后端不会提供路由

前端路由优缺点

1
2
3
4
5
6
7
优点
1.没有网路延迟,用户体验提升,后端路由每次都会请求服务器然后响应
2.在某些场合中,用 JAX 请求,可以让页面无刷新,页面变了,但 URL 没变,
时不能复山时址阳路由支阳面应用叫地解二

缺点
使用浏览器的前进、后退按钮的时候会 新发送请求,没有合理地利用缓存

Vue-Router的使用

1.安装路由

1
2
3
4
5
6
7
8
9
10
cnpm install vue-router --save

//index.js

import Vue from 'vue';
import VueRouter from 'vue-router'
Vue.use(VueRouter);

// main.js
import router from "./router"

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
// index.js
import Vue from 'vue';
import VueRouter from 'vue-router'

import Login from "@/components/Login"
import Home from "@/components/Home"

Vue.use(VueRouter);

export default new VueRouter({
routes:[
{
path:"/home",
name:"Home",
component:Home,
},{
path:"/login",
name:"Login",
component:Login
}

//.....
]
})

3.启动路由器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
在main.js入口文件中启用路由器,创建和挂载根实例,通过
router配置参数注入路由,从而让整个应用都有路由功能
*/

import Vue from "vue";
import App from "./App";
import router from "./router/index.js"
new Vue({
el:"#app",
router,
template:"<App/>",
components:{App}
})


// App.vue中对用的router-view会渲染

4.路由重定向

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
export default new VueRouter({
routes:[
{
path:"/",
redirect:"/home"
}
]
})

//重定向的目标也可以是一个命名的路由

export default new VueRouter({
routes:[
{
path:"/",
redirect:{name:'home'}
}
]
})


//重定向的目标甚至可以是一个方法,动态的返回重定向的目标

export default new VueRouter({
routes:[
{
path:"/",
redirect:to=>{
//方法接收“目标路由”作为参数
return //重定向的“字符串路径/路径对象”
}
}
]
})

5.路由懒加载

结合 Vue 的异步组件和 Webpack 的代码分割功能,可以轻松实现路由组件的懒加载

6.router-link

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<router-link :to="home">Home</route-link>

<!-- 同上--->
<router-link :to="{path:'home'}">HOme</router-link>

<!-- 命名的路由--->

<routet-link :to="{name:'user',params:{userID:123}}">User</router-link>

<!--带参数的查询--->
<router-link :to="{name:'register',query:{plan:'private'}}">Register</router-link>

<!--结果为/register?plan=private-->

7.路由的对象属性

  • $router.path

    字符串,对应当前路由的路径 总是解析为绝对路径,如“/foo/bar “

  • $router.params

    一个key/value对象,包含了动态片段和全匹配片段,如果没有路由参数 就为空对象

  • $router.query

    一个key/value对象,表示url的查询参数,/foo?id=1 表示$router.query.id==1,如果没有查询参数就为空对象

  • $router.hash

    当前路由的hash值(不带#),如果没有hash值则为空字符串

  • $router.fullPath

    完成解析后的 URL ,包含查询参数 hash 完整路径

  • $router.matched

    一个数组,包含当前路由的所有嵌套路径片段的路由记录

页面之间的导航

借助router实例的一些方法实现编程路由

$router.push
1
2
3
4
5
6
7
8
9
10
11
//参数可以是字符串路径
this.$router.push("user")

//参数可以是描述地址的对象
this.$router.push({path:"user"})

//命名的路由 #/user/123
this.$router.push({name:"User",params:{Id:123}})

//带参数的查询 页面跳转另一个页面需要携带数据可以使用此方法
this.$router.push({path:"user",query:{userAddress:'上海市'}})
$router.replace
1
2
3
4
5
6
7
/*
和push方法不同的是,他不会像history栈中添加新的记录,
而是跟他的方法名一样只替换掉当前的历史记录
*/
this.$router.replace("/user") //等价如下

<router-link :to="user" replace></router-link>
$router.go
1
2
3
4
this.$router.go(1) ==>  history.forward()
this.$router.go(-1) ==> history.back()

//如果记录不够就会失败

Vue.js 知识点

特点

解耦视图和数据

前端路由

可复用的组件

状态管理

Virtual DOM

MVVM特点

  • 低耦合
  • 可重用视图逻辑
  • 独立开发 专注于业务逻辑和数据的开发

Vue实例的生命周期

实例对象从构造函数时开始执行(被创建)到被GC回收销毁的整个存在的时期,在生命周期中被自动调用的函数称之为生命周期函数,也形象的称之为生命周期钩子函数

生命周期函数 含义
beforeCreate(创建前) 组件实例刚被创建,组件属性计算之前 比如data属性
created (创建后) 组件实例刚刚创建完成,属性已经绑定,此时DOM尚未生成,$el属性还不存在
beforeMount(载入前) 模板编译、挂载之前
mounted(挂载后) 模板编译、挂载之后
beforeUpdate(更新前) 组件更新之前
updated(更新后) 组件更新之后
beforeDestroy(销毁前) 组件销毁前调用
destroyed(销毁后) 组件销毁后调用
beforeCreate在组件刚刚被创建的时候增加一些loading事件
created调用时结束loading事件,完成一些初始化,实现函数自执行等
mounted是比较重要的函数,可以发起后端请求数据,接受页面之间传递的参数,由子组件向父组件传递参数等

class和style的绑定

当:class的表达式过长或逻辑复杂的时候,可以绑定一个计算属性,这是一种很友好和常见的做法

  1. 对象语法
    1
    2
    3
    4
    5
    6
    7
    <div :class="{active:isActive,....}"></div>

    data(){
    return{
    isActive:true
    }
    }
  1. 数组语法

    1
    2
    3
    4
    5
    6
    7
    8
    <div :class="[activeClass,errorClass]"></div>

    data(){
    return{
    activeClass:"active",
    errorClass:"static"
    }
    }
  2. 绑定内联样式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <div :style="{border:activeColor,fontSize:fontSize+'px'}"></div>


    data(){
    return{
    activeColor:"1px solid #ffc",
    fontSize:22
    }
    }

    //实际开发中写在data或者计算属性中

    <div :style="styleList"></div>

    data(){
    return{
    styleList:{
    border:"1px solid #fff",
    fontSize:22+"px"
    }
    }
    }

项目中与服务端通信

1.connect-mock-middleware工具的使用

  • config中的index.js中添加middleware,实际项目会换成后台提供的地址

    1
    2
    3
    4
    5
    6
    7
    proxyTable:{
    "/api":{
    target:"http://127.0.0.1:3721",
    changeOrigin:true,
    secure:false
    }
    }
  • 写mock文件

    1
    2
    3
    4
    5
    6
    7
    /*
    mock文件支持两种请求
    1.get/api/xxx
    2.post/api/<id>/123

    <id>代表路由链接表达式 如/api/:id/123 id的值会发生变化
    */

2.Mock.js语法

  • 优点
  1. 根据数据模板生成模拟数据
  2. 模拟Ajax请求返回模拟数据
  3. 基于html模板生成模拟数据
  • 语法规范
  1. 数据模板定义规范 (Data Template Definition—– DTD)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /*
    属性名 name
    生成规则 rule
    属性值 value
    'name|rule':value

    rule包括七种格式
    'name|min-max'
    'name|count'
    'name|min-max.dmin-dmax'
    'name|min-max.dcount'
    'name|count.dmin-dmax'
    'name|count.dcount'
    'name|+step'

    生成规则是可选的
    */
  2. 数据占位符定义规范(Data Placeholder Definition —–DPD)

3.snail mock工具的使用

  • 上面定义好了模拟的后台数据,现在需要通过生成的url来调用这些数据,snail mock可以模拟服务器的功能。生成的url

安装 cnpm isntall snail-cline -g

开启mock服务(在项目目录下打开cmd执行 ‘snail mock’ 命令会看到之前配置好的api地址)

1
2
3
经验:本地全局安装了snail-cline 其内部实现依赖很多其他的包,打开本地的package.json,
其中很多选项都是依赖于connect-mock-middleware的,依赖内部会自动下载管理依赖的包,同理
connect-mock-middleware中依赖mock,所以只需在本地全局安装snail-cline既可以使用mock语法

4.Axios安装和配置

项目服务端通信配置

1
2