一、Vue的组件化
1.1 组件化的概念和思想
- 组件化的概念:将一个页面拆分成一个个小的 功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。
- Vue的组件化思想:它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用,任何应用都会抽象成一颗组件树。
1.2 组件注册的基本步骤
- 创建组件构造器:Vue.extend()
- 传入的template代表我们自定义组件的模板,模板就是在使用到组件的地方,要显示的HTML代码
- 事实上,在Vue2.x的文档中几乎已经看不到了,它会直接使用新的语法糖
//1.创建组件构造器语法格式如下
//ES6中可以用``定义字符串,可以包括换行信息
const 组建构造器名称 = Vue.extend({
//该组件的模板信息
template: `
})
- 注册组件(全局注册和局部注册):Vue.component()
- 需要传递两个参数:注册组件的标签名、组件构造器
//要求传递两个参数,第一个是组件的标签名,第二个是组件构造器
Vue.component('标签名', 组件构造器)
- 使用组件:在Vue实例的作用范围内使用组件
<div id="app">
<标签名></标签名>
</div>
1.3 全局组件和局部组件
- 全局组件:如果不在某一个Vue实例里面则为全局组件,任何Vue实例都可以用。
- 局部组件:如果旨在某个实例中注册,则只能在该实例中中使用。
const app = new Vue({
el: '#app',
data: {
message: ''
},
//注册局部组件 只能在app中使用
components: {
标签名: 组件构造器
}
})
Vue.component('标签名',组件构造器)//全局组件
1.4 父组件和子组件
- 概念:组件和组件之间存在层级关系,而其中一种非常重要的关系就是父子组件的关系。
1.4.1创建父子组件的方式
1.4.2 父子组件的通信
- 概念: 在开发中往往一些数据确实需要从上层传递到下层,一般不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件),实现父子组件间的通信:通过props向子组件传递数据/通过事件向父组件发送消息。
- props数据验证
- 验证支持的数据类型:String、Number、Boolean、Array、Object、Date、Function、Symbol、自定义类型。
- 父传子的语法格式
props:{
cmessage:{
//传递的类型
type:String,
//默认值
default:'aaaaa',
//required是布尔类型 若为true则为必传值
required:true
},
//类型是对象或者数组时,默认值必须是一个函数
cmovies:{
type:Array,
default(){
return []
}
}
}
- 子传父的语法格式:自定义事件
1.5 组件中的数据存放
- 组件对象也有一个data属性,也有methods属性,只是这个data属性必须是一个函数(data(){})而且这个函数返回一个对象,对象内部保存着数据。
- data中存放的必须是一个函数,如果不是函数是一个对象的话会造成组件间连锁反应(关联操作)
Vue.component('cpn',{
template:'#cpp',
data(){
return{
title:'' //模板中需要放入的数据内容
}
}
})
1.4.3 父子组件的访问
- 概念:有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者子组件访问跟组件
- 父组件访问子组件:$children / $refs reference(引用)
- this.$children是一个数组类型[VueComponent],包含所有子组件对象
- 通过一个遍历,可以取出所有子组件的message状态
- 一般开发时候,若要取出某个特定组件的信息,一般不用数组下标形式取,一般用refs取
<div id="app">
<cpn ref="aaa"></cpn>
</div>
- 子组件访问父组件:$parent
- 访问根组件:$root
1.5 slot插槽
- 概念:插槽的目的是让我们原来的设备具有更多的扩展性,组件的插槽也是为了让我们封装的组件具有扩展性,让使用者决定我们的组件内部的一些内容到底展示什么。
- 封装插槽的原则:抽取共性,保留不同。最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。一旦我们预留了插槽就可以让使用者根据自己的需求,决定插槽中插入什么内容。如果有多个重复的值都插入的时候就可以给插槽附一个默认值,如果使用者没有传输入的内容,则显示指定的默认值。
<slot><button>按钮</button></slot>
- 具名插槽的使用方式
<template id="cpn">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
1.6 组件间编译的作用域
- 父组件模板的所有东西都会在父级作用域内编译,子组件模板的所有东西都会在子级作用域内编译。
- 作用域的插槽:父组件替换插槽的标签,但是内容由子组件来提供。
二、模板化开发
2.1 模板化思想
- 使用模板作为一个出口:export导出、import导入
//在模板文件中写export
export {
flag, sum
}
//在需要导入的文件中写import
import {num1, height} from "./aaa.js";
2.2 Webpack打包工具
2.2.1 webpack基本介绍
- webpack是一个现代的Javascript应用的镜头模块打包工具,其实就是说webpack有两个核心功能:模块和打包,是一款前端模块化的打包工具。
- 在ES6之前,我们想要进行模块化开发就必须借助于其他的工具,让我们可以进行模块化开发,并且通过开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包。而webpack一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系。而且不仅仅是js文件,我们的css、图片、json文件等在webpack中都可以被当作模块使用。
- 打包:就是将webpack中的各种资源模块进行打包合并成一个或多个包,并且在打包的过程中,对资源进行处理(比如压缩图片,将scss转成css等)
- 和grunt/gulp的对比:
- grunt/gulp的核心是Task,我们可以配置一系列的task,并且定义task要处理的事务之后让grunt/gulp来依次执行这些task,而且让整个流程自动化,所以grunt/gulp也被称为前端自动化任务管理工具。
- 如果你的工程模块依赖简单,深圳没有用到模块化的概念,只需要进行简单的合并、压缩就是用grunt/gulp就可,但是如果整个项目使用了模块化管理,而且相互依赖非常强,我们就可以使用更加强大的webpack。
- grunt/gulp更加强调的是前端流程的自动化,而webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是附带功能。
三、Vue-router
3.1 基本使用
- 创建路由组件
- 配置路由映射:组件和路径映射关系
const routes = [
{
path:'/home',
component:Home
}, //一个组件是一个映射关系
{
path:'/about',
component:About
}
]
- 使用路由
//显示组件
<router-link to="/home">首页</router-link>;
<router-link to="/about">关于</router-link>;
//渲染组件内容 //在link上面则在其上面渲染 否则在下面渲染
<router-view></router-view>
- 默认路由路径
const routers = [
{
path:'',
redirect:'/home1' //重定向
}
]
const router = new VueRouter({
routes,
mode:'history'
})
- router-link补充
- tag=" ":指定渲染成什么组件
- replace:不留history记录,后退键不能返回
- active-class:当link对应路由配置成果时候,会自动个元素设hi一个router-link-active的class设置active-class可以修改默认的名称 统一改的方式:再路由里设置一个linkActiveClass属性
homeClick(){
this.$router.push('/home'); //pushState
this.$router.replace('/about'); //不可以返回
}
3.2 动态路由和懒加载
- 动态路由的概念:某些情况下,一个页面的路径可能是不确定的,当我们进入界面时候,我们希望路径能够是以下的情况,这种path和component的匹配关系,我们称之为动态路由。
<router-link v-bind: to="'/user/'+userId">用户</router-link>
- 路由的懒加载概念:当路由被访问到的时候才加载对应组件
const Home = () => import('../components/Home') //一般都用这个写法
3.3 嵌套路由
- 概念:我们希望通过/home/news和home/message访问一些内容,一个路径映射一个组件,访问这两个路径也会分别渲染两个组件。
- 实现步骤:创建对应的子组件并在路由映射中配置对应的子路由→在组件内部使用标签
/1.配置嵌套子路由
const routes = [
{
path:'/home',
component:Home,
children:[
{
path:'',
redirect:'news'
}
{
path:'news'
componet:HomeNews,
},
{
path:'message'
component:Homemessage,
}
],
}
]
//2.在父路由的vue里面(这里就是Home.vue里)写<router-view>用于决定显示位置
//3.在App.vue里写上router-link
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">信息</router-link>
3.4 vue-router参数传递
params
- 配置路由格式:/router/:id
const routers:[
{
path:'user/:abc',
component:User
}
]
- 传递的方式:在path后面跟视对应的值
<router-link :to="'/user/'+userId">用户</router-link>
- 传递后形参的路径:/router/123
computed:{
userId(){
return this.$router.params.id
}
}
query
- 配置路由格式:/router 也就是普通配置
- 传递的方式:对象中使用query的key作为传递方式
<router-link :to="{path: '/profile',query:{name:'why',age:18,height:1.65}}">档案</router-link>
- 传递后形成的路径:/router?id=123,/router?id=abc
$ router和$ route的区别
3.5 vue-router导航守卫(动态修改网页title)
- 在index.js里面配置
- meta(元数据)
- 前置守卫(guard)导航钩子的三个参数解析
- to:即将要进入的目标的路由对象
- from:当前导航即将要离开的路由对象
- next:调用该方法后,才能进入下一个钩子
- 后置钩子(hook)不需要主动调用next函数
- 前面的两个导航守卫我们使用的导航守卫,称之为全局守卫
- 路由独享守卫
- 组件内的守卫
3.6 keep-alive
- 作用:使被包含的组件保留状态或避免重新渲染;如果router-view直接被包在keep-alive里面,所有路径匹配到视图组件都会被缓存。
- keep-alive有两个属性
- include:字符串或正则表达,只有匹配的组件会被缓存
- exclude:字符和或正则表达式,任何匹配的组件都不会被缓存
四、Promise
4.1 promise的介绍和基本使用
- promise是异步编程的一种解决方案:网络请求的时候
- 语法结构
new Promise((resolve, reject) => {
setTimeout(() => {
// 成功的时候调用resolve
// resolve('Hello World')
// 失败的时候调用reject
reject('error message')
}, 1000)
}).then((data) => { //成功的时候来到then 进行下一步操作
4.2 promise的三种状态
- pending:等待状态,比如正在进行网络请求,或者定时器没有到事件
- fulfill:满足状态,当我们主动回调了resolve的时候,就处于该状态,并且会回调.then()
- reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()
4.3 promise的链式调用
new Promise((resolve, reject) => {
// 第一次网络请求的代码
setTimeout(() => {
resolve() //去到then处理代码
}, 1000)
}).then(() => {
// 第一次拿到结果的处理代码
console.log('Hello World');
return new Promise((resolve, reject) => {
// 第二次网络请求的代码
setTimeout(() => {
resolve()
}, 1000)
})
}).then(() => {
// 第二次处理的代码
console.log('Hello Vuejs');
return new Promise((resolve, reject) => {
// 第三次网络请求的代码
setTimeout(() => {
resolve()
})
})
}).then(() => {
// 第三处理的代码
console.log('Hello Python');
})
五、VueX
5.1 Vuex的概念和作用
- Vuex是一个专为Vuejs应用程序开发的状态管理模式:采用集中式存储管理
- 需要管理的状态:多个界面共享、用户登录状态、商品的收藏、状态信息
- vuex是一个插件,需要安装引用
5.2 VueX的使用过程
- 安装插件
Vue.use(Vuex)
- 创建对象
const store = new Vuex.Store({
state:{ //保存状态
counter: 1000 //可以通过$store.state.counter引用
},
mutations:{},
actions:{},
getters:{},
modules:{}
})
- 导出对象
export store
5.3 Vuex的核心知识
state:单一状态树
- 语法格式:$store.state.信息名
- 用途:用于放置状态的相关信息,单一状态树又称为单一数据源,能够让我们最直接的方式找到某个状态的片段,而且再之后的维护和调试过程中,也可以非常方便的管理和维护
getters
- 类似计算属性 可以用过滤数据
getters:{
powerCounter(state){
return state.counter * state.counter
}
}
- 对经过getter过滤的数据实现其他操作
more20stulength(state, getters){
return getters.more20stu.length
}
- 动态获取用户输入要求的数据项
moreAgeStu(state){
return function(age){
return state.students.filter(s => s.age > age)
}
}
mutation:状态更新
- vuex的store状态更新唯一方式:提交mutation
- 主要包括两部分:字符串的事件类型(type)、一个回调函数(handler)第一个参数就是state
- 定义方式如下:
mutations:{
//方法
increment(state){
state.counter++
},
decrement(state){
state.counter--
}
}
- 更新方式
increment:function(){
this.$store.commit('increment')
}
- 传递参数的方式(payload)
//模板里的内容
<button @click="addCount(5)">+5</button>
<button @click="addCount(10)">+10</button>
//methods定义方法
methods:{
addCount(count){
this.$store.commit('incrementCount',count)
}
}
//在mutation力接受传递的参数
mutations:{
incrementCount(state,count){
state.counter += count
]
}
- 响应规则:vuex的store中的state是响应式的,当state中的数据发生改变的时候,vue组件会自动更新
否则则需要通过下面两个操作来进行响应
action:异步操作
//mutation的action里面
action: {
aUpdateInfo(context, payload){
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('updateInfo');
console.log(payload);
resolve('11111')
},1000)
})
}
}
//在组件内调用时
this.$store.dispatch('aUpdateInfo', '我是携带的信息')
.then(res => {
console.log('里面完成了提交');
console.log(res);
})
module:划分模块,针对不同模块进行核心数据的保存
const moduleA = {
state:{},
mutations:{},
actions:{},
getters:{}
}
const moduleB = {
state:{},
mutations:{},
actions:{},
getters:{}
}
const store = new Vuex.Store({
modules: {
a: moduleA
b: moduleB
}
})
store.state.a
store.state.b
六、网络模块封装axios
6.1 axios框架的基本使用
axios(config)请求单个网站数据
import axios from 'axios'
axios({
//数据链接 默认情况下是get请求
url:'httpbin.org/',
params:{
}
}).then(res => {
console.log(res); //打印数据详情
})
针对get请求的参数拼接
axios({
url:'htttp://123.207.32.32:8000/home/data',
params:{
type:'pop',
page:1
}
}).then(res => {
console.log(res);
})
发送多个并发请求
axios.all([axios({
url:'htttp://123.207.32.32:8000/home/multidata'
}),axios({
url:'htttp://123.207.32.32:8000/home/data',
params:{
type:'sell',
page:4
}
})]).then(axios.spread((res1, res2) => {
console.log(res1);
console.log(res2);
}))
6.2 axios的全局配置
事实上我们开发中很多的参数可能都是固定的,这个时候我们可以进行一些抽取,也可以利用axios的全局配置
baseURL
axios.defaults.baseURL = 'http://123.207.32.32:8000'
//请求超时时间 单位毫秒
axios.defaults.timeout = 5000
常见的配置选项
含义 | 源码 |
---|---|
请求地址 | url:’/user’ |
请求类型 | method:‘get’ |
请根路径 | baseURL:’ http://…’ |
请求前的数据处理 | reansformRequest:[function(data){}] |
请求后的数据处理 | transformResponse:[function(data){}] |
自定义的请求头 | headers{‘x-Requested-With:’:‘XMLHttpRequest’} |
URL查询对象 | params:{id:12} |
axios的实例和模块封装
创建对应的axios的实例
- request.js里面的代码
const instance1 = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
instance1({
url:'/home/multidata'
}).then(res => {
console.log(res);
})
const instance2 = axios.create({
baseURL:'http://222.111.33.33:8000',
timeout:10000,
})
模块封装
export function request(config) {
return new Promise((resolve, reject) => {
//创建axios实例
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
//发生真正的网络请求
instance(config).then(res => {
resolve(res)
})
.catch(err => {
reject(err)
})
})
}
- 调用时候的代码
request({
url:'/home/mutidata'
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})