一、前提
1.项目初始化
Babel 把js语法进行翻译降级
TypeSCript 基于JavaScript封装的一个超类,js是弱类型语言,ts是强类型语言
PWA脱机应用
Router路由
后面两个是测试用需要的
2.常见错误
这种一般是Eslint错误
ESLint在哪里生效? webpack开发服务器+ESLint配置检查
3.eslint配置
// 目标1: 有2处在检查我的代码
// vscode+eslint插件+工作区根目录下.eslinrc.js配置, 在保存时, 检查代码
// 如果在写代码过程中用插件解决了问题, webpack里就不会报错了
// webpack开发服务器(在下面终端中)+eslit插件, 在保存时, 检查代码
4.Git配置
git remote add origin git@gitee.com:jcicy/toutiao.git
git push -u origin "master"
5.下载vant
yarn add van@2.12.34
二、统一管理请求的接口
1.封装axios函数
之前的方法
import theAxios from 'axios'
// 基于axios封装网络请求
// 每个程序员的想法都不一样, 封装的地方和名字都不一样, 但是思想相同
const axios = theAxios.create({
baseURL: 'http://geek.itheima.net',
timeout: 20000 // 20秒超时时间(请求20秒无响应直接判定超时)
})
export default axios
// 但是上面有局限性
// 导出的axios方法在使用时
/*
// 我在逻辑页面调用时, 传入的这5个配置名字
axios({
url: '请求地址',
method: '请求方式',
params: {},
data: {},
headers: {}
})
*/
// 问题来了, 万一将来我要更新request.js里封装网络请求的工具
// 把axios换成jquery的$.ajax
// import $ from 'jquery'
// export default $.ajax
/*
$.ajax({
url: '请求地址',
type: '请求方式',
data: {}, // 没有params
headers: {}
})
*/
解决方案:一摸一样的控制面板、高级的设置模式
以后换库, 只需要改这里, 逻辑页面不用动, 保证代码的复用性和独立性(高内聚低耦合)
//导出自定义函数, 参数对象解构赋值
export default ({
url,
method = 'GET',
params = {},
data = {},
headers = {}
}) => {
return axios({
url,
method,
params,
data,
headers
})
}
export default ({
url,
method = 'GET',
params = {},
data = {},
headers = {}
}) => {
//以后换库, 只需要改这里, 逻辑页面不用动, 保证代码的复用性和独立性(高内聚低耦合)
return new Promise((resolve, reject) => {
$.ajax({
url,
data,
headers,
type: method,
success: (res) => {
resolve(res)
},
error: err => {
reject(err)
}
})
})
}
小结:
1.为什么要二次封装 axios函数
为了让代码更加灵活,统一管理
2.axios.create作用
创建返回一个新的axios函数对象
2.封装接口方法
// 统一封装接口方法
// 每个方法负责请求一个url地址
// 逻辑页面, 导入这个接口方法, 就能发请求咯
// 好处: 请求url路径, 可以在这里统一管理
import axios from '@/utils/request'
// 频道 - 获取所有频道
// export const getAllChannelsAPI = () => {
// return axios({
// url: '/v1_0/channels',
// method: 'GET'
// })
// }
// 方法在逻辑页面调用要记得return
// 这里可以简写为 箭头函数return 大括号可以省略
// 默认把结果返回到函数调用的方法
// 接口方法, 只负责调用一个接口, 返回一个Promise对象
export const getAllChannelsAPI = () =>
axios({
url: '/v1_0/channels',
method: 'GET'
})
测试这个方法
在app.vue中导入过来, 尝试发起一个请求
import { getAllChannelsAPI } from '@/api/index'
export default {
async created() {
const res = await getAllChannelsAPI()
console.log(res)
}
}
3.try和catch的使用
如何捕获await错误情况?
await用于取代then函数, 等待Promise成功结果提取在原地
await无法获取Promise失败的结果, 一旦失败Promise错误直接抛出到控制台
解决方案:使用JS里内置语法, try+catch
/*
try {
// 可能会报错的代码(例如await)
} catch (err) {
//抛出错误
// try里代码报错, 捕捉到这里执行
}
*/
async created() {
// try加catch捕获await同步代码的错误
try {
const res = await getAllChannelsAPI()
console.log(res)
} catch (err) {
// err参数就是拿到的错误对象
// 给用户来个弹窗提示-程序出错了
// console.dir()详细打印
console.dir(err)
}
}
5.登录页面-路由准备-页面文件创建
步骤:
1.src/views/Login/index.vue - 作为登录页面 - 先随意弄写标签显示
这里一般不是引入到app.vue 而是配置路由
2.src/router/index.js - 添加登录的路由规则
import Login from '@/views/Login'
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: Login
}
3.路由给挂载点, 在App.vue中
<router-view></router-view>
4.打开页面测试下, 是否能显示登录页面
6.登录页面-头部导航-vant组件使用
// 目标2: 组件使用套路
// 1. 明确目标, 找到类似组件
// 2. 引入注册然后复制过来
// 3. 读和删没用的
// 4. 修改, 改成我们想要的样子
// 样式修改:
// (1): 找到类名, 自己写css覆盖掉它
// (2): 看文档, 是否支持自定义样式
找背景类名
.van-nav-bar{
background: #007bff;
}
文字颜色
写了类名还是不行,因为加了scoped
/* /deep/ 就是把data-v-hash值选择器写到类名的前面 */
/deep/ .van-nav-bar__title{
color: white;
}
<style scoped lang="less">
/* 此类名是van-nav-bar组件内根标签 */
// .van-nav-bar {
// background-color: #007bff;
// }
/* 此选择器名字是van-nav-bar组件内标签
scoped尝试把此选择器后面加上属性选择器匹配当前页面标签 (选不中组件内部的) */
// lang="less" 当前style标签内是less语法
// 用/deep/就不会被vscode标记红线
// /deep/ 会把属性选择器加到前面 (用后代选择器的方式往里找匹配的类名)
// 结论: 要修改组件内样式, 如果你用了scoped, 就需要在选择器前/deep/即可
// /deep/ .van-nav-bar__title {
// color: white;
// }
</style>
因为加了scoped 所以不会显示,这个标签没有加自定义属性。webpack打包时给加上自定义属性。
结论: 要修改组件内样式, 如果你用了scoped, 就需要在选择器前/deep/即可
7.vant组件自定义样式
配置完成后要重启服务器
方法二:
console.log(__dirname) // 当前文件, 所在文件夹, 的绝对路径
因为eslint的存在,需要path.join拼接
// 不要手动写绝对路径, 用代码来动态获取, 绝对地址
const path = require('path')
// 或者可以通过 less 文件覆盖(文件路径为绝对路径)
hack: `true; @import "${path.join(__dirname, 'src/styles/cover.less')}";`
8.登陆表单_准备
1.输入框name 名称,提交表单的标识符,表单提交时,默认收集一个提交对象
2.rules 表单校验规则 :属性名=”表达式" 不加冒号是字符串
3. 属性后面无值, 默认值为true
block代表块级元素
type代表类型(有默认颜色)
native-type代表原生button的type属性
代表这个van-button组件渲染的原生button标签type是submit提交整个表单功能的按钮
9登陆表单-微调_完成页面铺设
name对应后台的参数名
label左侧文字
// 目标1: 实现顶部导航->自定义样式
// 目标2: 实现表单组件->读,改,加
// 目标3: 收集值以后, 调用接口->查看登录结果
// 目标4: 点击登录后给用户提示(正在登陆中~~~), 防止用户频繁的点击
methods: {
// {mobile: '13888888888', code: '246810'}
onSubmit(values) {
console.log('submit', values)
console.log(this.user)
}
}
/^1[3-9]\d{9}$/
第1位:只能是1
第2位:[34578]
第3位之后,必须是9位数字
10.登录接口调用
axios内部,会把参数对象转成json字符串格式发给后台
axios内部会自动携带请求参数headers里Content-type:‘application/json’帮你添加好
11.network
https://vant-contrib.gitee.io/vant/v2/#/zh-CN/notify
12.优化
async onSubmit(values) {
// console.log('submit', values)
// console.log(this.user)
this.isLoading = true
try {
const res = await loginAPI(this.user)
console.log(res)
Notify({ type: 'success', message: '登陆成功!' })
} catch (err) {
Notify({ type: 'danger', message: '账号或者验证码输入错误' })
}
// 请求后 无论成功还是失败 把状态关掉
this.isLoading = false
}
13.token本地存储
// 此文件->封装3个方法->专门用于操作token的
// 封装点东西: 目的: 代码分层, 更方便清晰, 以后修改方便
// 本地存储存的是字符串 (JSON字符串是字符串的一种)
const key = 'geek-itheima'
// 设置
export const setToken = token => {
localStorage.setItem(key, token)
}
// 获取
export const getToken = () => {
localStorage.getItem(key)
}
// 删除
export const removeToken = () => {
localStorage.removeItem(key)
}
setToken(res.data.data.token)
14.布局页面-登录跳转到这儿
// 跳转一定要写在最后->尽量最后执行
// location.href -> 当前浏览器地址和要跳转的地址一样(不包含#后面锚点信息) -> 不会刷新网页
// 地址改变, 就会导致网页刷新
// this.$router.push() 压栈(会产生历史记录, 可以回退), this.$router.replace() 替换(不会产生历史记录)
this.$router.replace({
path: this.$route.query.path || '/layout/home'
// 因为我们路由规则里/layout里没有重定向, 所以直接在这里写全
})
小结:
1.router和route区别是?
$router下用于跳转路由
$route是路由信息对象
2.路由的push和replace方法区别?
push跳转后, 可以返回
replace跳转后, 无法返回
15.顶部导航插槽
使用插槽:占位+template
1.为何插槽看不见slot标签?
因为你用的vant组件, 组件内部写好了slot, 你只需要使用即可
2.JS里引入图片为何import
因为脚手架底层运作是webpack, 图片会认为是模块, 需要模块化导入
v-slot:可以简写为#