1.前端代码化雏形和CommonJS
JavaScript原始功能
在网页开发的早期,js制作作为一种脚本语言,做一些简单的表单验证或者动画实现,代码量比较少,只要写在script标签里面就可以了
随着ajax异步请求的出现,慢慢形成了前后端分离,客户端需要完成的事情越来越多,代码量也越来越多。为了应对代码量的剧增,我们通常会把代码组织在多个js文件中,进行维护
但会出现一些问题:比如全局变量同名的问题
使用函数闭包可以解决变量冲突的问题,但是使用不了其他文件定义的变量
模块化有两个核心:导出和导入
CommonJS的导出
module.exports = {flag:true,test(a, b){return a + b},demo(a, b){return a + b}
}
CommonJS的导入
let { test , demo } = required('module')
2.ES模块化的导入和导出
关键字export(导出) import(导入)
导出export
//aaa.jslet name ='jjj'
let age = 18
let height = 1.22
function sum(sum1,sum2){return sum1+sum2}//导出方式一
export {name,age,height,sum} //导出方式二
export var num1 = 1000
//在定义的时候直接导出//导出函数/类
export function mul(num1,num2){return num1 + num2
}
某些情况下,一个模块中包含某个功能,我们并不希望给这个功能命名,要让导入者来自己命名
就可以使用export default
只能默认导出一个,而且其他文件导入的时候可以自定义名称,不需要用{}括起来
const address = 'ss'
export default address
//只能默认一个import jjj from "./aaa.js"
//可以自己命名,不要加{}
导入 import
//mmm.jsimport { flag, sum } from "./aaa.js"//统一全部导入
import * from "./aaa.js"
console.log(aaa.flag);
2021.11.4
2.webpack
从本质来讲,webpack是一个现代的js应用的静态模块打包工具
webpack让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系
2.1.webpack的安装
webpack依赖node环境,node的工具npm( Node Packages Manager )
3.Vue CLI脚手架
开发大型项目的时候才需要使用Vue CLI,Vue.js需要考虑代码目录结构,项目结构和部署,热加载,代码单元测试等事情,脚手架工具会帮助我们完成这些事情
CLI是command-Line-Interface,命令行界面,vue-cli可以快速搭建Vue开发环境以及对应的webpack配置
3.1.安装脚手架
npm install -g @vue/cli
安装脚手架不成功的话
使用指令
npm clean cache -force
打开终端的时候使用管理员身份执行
如果仍然需要使用旧版本的vue init 功能,可以全局安装一个桥接工具
npm install -g @vue/cli-init
3.2.脚手架CLI2初始化项目指令
//cli2
vue init webpack 项目名称
vue cli2
每个指令的作用
3.3.runtime-compiler和runtime-only的区别
只有main.js有区别
//runtime-compiler
import Vue from 'vue'
import App from './App'Vue.config.productionTip = false/* eslint-disable no-new */
new Vue({el: '#app',components: { App },template: '<App/>'
})
//runtime-only
import Vue from 'vue'
import App from './App'Vue.config.productionTip = false/* eslint-disable no-new */
new Vue({el: '#app',render: h = > h(App)
})
runtime-compiler
先把template解析成ast(抽象语法树),编译成render函数,翻译成虚拟dom树,在生成真实dom
template -> ast -> render -> vdom -> UI
runtime-only
render -> vdom -> UI
-
runtime-only:将template在打包的时候,就已经编译为render函数
-
runtime-compiler:在运行的时候才去编译template
3.4.vue-cli3
设计原则 0配置,移除了配置文件根目录下的,build和config等目录
提供了vue ui命令,提供了可视化配置
//cli3
vue create 项目名称
使用空格选择取消
可以使用vue ui指令进行配置
箭头函数this如何查找,向外层作用域一层层查找this,指到有this的定义
4.vue-router前端路由
路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动
网站开发发展
早期的网站开发html页面是由服务器来渲染的(后端渲染),返回给客户端来展示
一个页面有对应的网址(url),url发送到服务器,进行匹配,controller进行处理,最终生成html或者数据,返回给前端,这就是后端路由
前后端分离阶段
随着Ajax的出现,有了前后端分离的开发模式
后端只提供API来返回数据,前端根据Ajax来获取数据,并且可以通过js将数据渲染到页面中
前后端的责任清晰,后端专注于数据,前端专注于交互和可视化上
SPA页面
单页面富应用,整个页面就只有一个html,不需要刷新页面
最主要的特点在前后端分离的基础上加了一层前端路由
由前端来维护这一套路由规则
//url的hash
location.hash='aaa'//html
//类似于栈
history.pushState({},'','about')
history.replaceState({},'','replace')
history.go()
history.back()
history.forward()
4.1.v-router安装和配置
步骤一:安装vue-router
npm install vue-router --save
步骤二:在模块化工程中使用它(因为是一个插件,所以可以通过Vue.use()安装路由功能)
1.导入路由对象,并且调用Vue.use(VueRouter)
2.创建路由实例,并且传入路由映射配置
3.在Vue实例中挂载创建的路由实例
//index.js
//配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'import Home from '../components/Home'
import About from '../components/About'
//1.通过Vue.use(插件),安装插件
Vue.use(VueRouter)//2.创建VueRouter对象
const routes = [{path:'/home',component:Home},{path:'/about',component:About}]
const router = new VueRouter({//配置路由和组件之间的应用关系routes
})//3.将router对象传入到Vue实例中
export default router
//main.jsimport Vue from 'vue'
import App from './App'
import router from './router'Vue.config.productionTip = falsenew Vue({el: '#app',router,components: { App },template: '<App/>'
})
2021.11.5
使用vue-router的步骤
1.创建路由组件
2.配置路由映射,组件和路径映射关系
3.使用路由:通过<router-link>和<router-view>
创建了Home和About组件
导入组件
import Home from '../components/Home'
import About from '../components/About'
配置映射关系
const routes = [{path: '/home',component: Home},{path: '/about',component: About}]
在App.vue中使用
<div id="app"><router-link to="/home">首页</router-link><router-link to="/about">关于</router-link><router-view></router-view></div>
如果想要在点击进去默认显示一个组件的内容,设置redirect重定向
{path: '/',//redirect重定向redirect: '/home'},
4.2.路由上面#使用html5优化
有#不太像url
加上一个mode属性
4.3.router-link属性的补充
<router-link>在前面只是使用了属性to,用于跳转路径
还有其他属性
tag,指定<router-link>之后渲染成什么标签
replace,使用history.replaceState模式,replace不会留下history记录,返回按钮就没有效果了
active-class,当<router-link>对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class
如果不修改的话,默认的class就是router-link-active,但是如果想要修改这个class类就可以在标签用active-class='active',但如果要修改的router-link太多了,可以在router文件夹的index.js添加linkActiveClass,class就变成了active,在style里面用.active{}
4.4.通过代码跳转路由
直接使用button按钮标签,绑定事件
this.$router是自带的
4.5.动态路由的使用
想要拿到lisi
this.$route哪个路由活跃就拿到哪个路由
userId和上面path里面的相对应
4.6.路由的懒加载
当打包构建应用时,js包会变得非常大,影响页面加载
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了
路由懒加载的主要作用是将路由对应的组件打包成一个个的js代码块
只有在这个路由被访问到的时候,才加载对应的组件
有两种编写方式
const Home = () => import('../components/Home')
const About = () => import('../components/About')const routes = [{path: '/home',component: Home},{path: '/about',component: About},
]
const routes = [{path: '/home',component: () => import('../components/Home')},{path: '/about',component: () => import('../components/About')},
]
一个懒加载在打包的时候会生成一个js文件
4.7.嵌套路由
创建对应的子组件,并且在路由映射中配置对应的子路由
在组件内部使用<router-view>标签
4.8.传递参数的方式
传递参数主要有两种类型params和query
params的类型
配置路由格式:/router/:id
传递的方式:在path后面跟上对应的值
传递后形成的路径:/router/123,/router/abc
query的类型
配置路由格式:/router,也就是普通配置
传递的方式:对象中使用query的key作为传递方式
传递后形成的路径:/router?id=123,/router?id=abc
4.9.传递参数使用方法
4.10.$route和$router的区别
$router 为VueRouter实例,想要导航到不同url,则使用$router.push方法
$route 为当前router跳转对象里面可以获取name、path、query、params等
4.11.导航守卫
想要实现跳转的时候标题改变,我们可以利用beforeEach来完成标题的修改
to 即将要进入的目标的路由对象
from 当前导航即将要离开的路由对象
next 调用该方法后,才能进入下一个钩子
2021.11.6
4.12.keep-alive
router-view也是一个组件,如果直接包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
actived(){}
deactived(){}
//这两个函数只有在组件被保持状态,使用了keep-alive才有效
keep-alive有两个非常重要的属性
include-字符串或正则表达,只有匹配的组件会被缓存
exclude-字符串或正则表达,任何匹配的组件都不会被缓存
5.Promise
Promise是异步编程的一种解决方案
封装网络请求的函数,不能立即拿到结果,这个时候可以传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去
链式编程
<script>//resolve,reject本身他们又是函数new Promise((resolve, reject) => {//异步操作setTimeout(() => {resolve()reject('error message')}, 1000)}).then(() => {console.log('处理代码1')return new Promise((resolve, reject) => {setTimeout(() => {resolve()}, 1000)})}).then(() => {console.log('处理代码2')}).catch((err)=>{console.log(err)})</script>
什么情况下会用到promise?
一般情况下有异步操作时,使用promise对这个异步操作进行封装,成功的时候会调用resolve,去then那里执行,失败的时候调用reject,只要一个catch
语法糖形式
<script>new Promise((resolve, reject) => {setTimeout(() => {resolve('aaa')}, 1000)}).then(res => {console.log(res, '第一层');return Promise.resolve(res + '111')}).then(res => {console.log(res, '第二层');return Promise.resolve(res + '222')})</script>
省略掉promise.resolve,会在return后自动加上一层Promise
<script>new Promise((resolve, reject) => {setTimeout(() => {resolve('aaa')}, 1000)}).then(res => {console.log(res, '第一层');return res + '111'}).then(res => {console.log(res, '第二层');return res + '222'}).then(res => {console.log(res)})</script>
6.Vuex
2021.11.8 写实习报告
Vuex是一个专为Vue.js应用程序开发的状态管理模式
把需要多个组件共享的变量全部存储在一个对象里面,将这个对象放在顶层的Vue实例中,让其他组件可以使用
什么状态需要使用vuex?
比如用户的登录状态、用户名称、头像、地理位置信息
比如商品的收藏、购物车中的物品
这些状态信息,我们都可以放在统一的地方,对它们进行保存和管理,而且他们还是响应式的
复习一下父子组件通信
//App.vue
<template><div id="app"><h2>{{message}}</h2><h2>{{counter}}</h2><button @click="counter++">+</button><button @click="counter--">-</button><hello-vuex :counter="counter"/></div>
</template><script>
import HelloVuex from './components/HelloVuex'
export default {name: 'App',data(){return {message:'我是App组件',counter:0}},components:{HelloVuex}
}</script>
//HelloVuex.vue
<template><div class="hello"><h2>{{counter}}</h2></div>
</template><script>
export default {name: 'HelloVuex',data () {return {msg: 'Welcome to Your Vue.js App'}},props:{message:String,counter:Number}
}
</script>
vuex是插件
npm install vuex --save
创建文件夹store,文件index.js
引进Vue和Vuex
创建对象
在main.js挂载
6.1.store
在store对象声明变量,就可以到处用
$store.state.counter
但是官方不推荐用$store.state.counter++这么修改,要走流程
全局单例模式,将共享的状态抽取出来,交给vuex大管家,统一管理,必须要按照规定好的规定,进行访问和修改等操作
devtools浏览器插件,记录每次修改
action异步操作
2021.11.9
vue.js
index.js
vue state推荐单一状态树,数据再多也统一放在一个store里面
当给state中的对象添加新属性的时候,使用下面的方式
1.使用Vue.set(obj,'newProp',123)
2.用新对象给旧对象重新赋值
6.2.getters的基本使用
getters:{powerCounter(state){return state.counter * state.counter}
}
<h2>{{$store.getters.powerCounter}}</h2>
类似于computed
getters里面有两个参数,一个是state,一个是getters,如果要传入参数进行筛选的话,可以返回一个函数
getters:{moreAgeStu(state){return function (age){return state.student.filter(s = >s.age >age)//这里就传入了参数age}}
}
6.3.mutation状态更新
vuex的store状态的更新唯一方式:提交mutation
mutation主要包括两部分
字符串的事件类型(type)
一个回调函数(handle),该回调函数的第一个参数就是state
mutation的定义方法
mutations:{increment(state){state.count++}
}
通过mutation更新
increment:function(){this.$store.commit('increment')
}
在要使用的组件中定义方法,通过this.$store.commit('mutations中要定义的名字')来调用mutations中定义的方法
mutation里面的操作都是同步操作
Vue.delete(state.info,'age')可以实现响应式
6.4.Action的基本定义
Action类似于Mutation,但是是用来替代Mutation进行异步操作的
Vuex要求我们Mutations中的方法必须是同步方法,主要原因是当我们使用devtools时,可以使用devtools帮我们捕捉mutations的快照,如果是异步操作,那么devtools将不能很好地跟踪这个操作什么时候会被完成
this.$store.dispatch('名字','我是payload')
7.网络请求模块的选择
npm install axios --save
很多参数在开发中都是固定的,这个时候就可以抽取一些,可以利用axios的全局配置
axios.defaults.baseURL = '123.123.132.12:8080'
axios.defaults.timeout = 5000
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
常见的配置选项
请求地址 url:'/user'
请求类型 method:'get'
请求根路径 baseURL:'http;//'
请求前的数据处理 transformRequest:[function(data){}]
请求后的数据处理 transformResponse:[function(data){}]
自定义的请求头 headers:{'x-Requested-With':'XMLHttpRequest'}
URL查询对象 params:{id:12}
7.1.axios的实例
const instance1 = axios.create({baseURL:'http://123.21.321:8080',timeout:5000})instance1({url:'/home/multidata'}).then(res => {console.log(res);
})instance1({url:'/home/data',params:{type:'pop',page:2}
})
7.2.模块封装
每个文件都要引进axios框架的话,就太麻烦了,如果以后框架不再维护了,不好修改。
创建一个network文件夹,创建request.js文件,
import axios from 'axios'
export function request(config,success,failure){
//创建axios的实例const instance = axios.create({baseURL:'http://13.123:8080',timeout:5000})
//发送真正的网络请求instance(config).then(res =>{console.log(res);success(res)}).catch(err =>{console.log(err);failure(err)})
}
export function request(config){return new Promise((resolve,reject)=>{const instance = axios.create({baseURL:'http://13.123:8080',timeout:5000})instance(config).then(res =>{resolve(res)}).catch(err =>{reject(err)})})}
最简便的方法
export function request(config){const instance = axios.create({baseURL:'http://123:8080',timeout:5000})return instance(config)
}
7.3.拦截器
axios提供了拦截器,用于我们在发送每次请求或者得到响应后,进行相应的处理
import axios from 'axios'
export function request(config){const instance = axios.create({baseURL:'http://123:8080',timeout:5000})
//请求拦截
instance.interceptors.request.use(config =>{console.log(config);//config里面有一些信息不符合服务器要求return config},err =>{console.log(err) })//响应拦截
instance.interceptors.response.use(res =>{return res.data},err =>{})return instance(config)
}