环境配置
Vue脚手架的创建
- 在终端中打开输入
vue create 项目包名 -m npm
注意⚠️:项目名称不再允许包含大写字母。
- 选择第三项
3.选择要安装的模块
从上到下的功能模块:
- Babel - ES:降级处理
- Router-Vue:路由插件
- CSS预处理器
- ESLint代码格式检查工具
- 选择下载Vue2版本
- 选择模式
- 选择路由模式(输入n)
- 选择Css预处理器(选择Less)
- ESLint版本(选择Standard——标准版)
- 选择配置
从上到下依次是:
- Lint on save 代码保存的时候,检查代码格式
- 配置文件保存位置选择保存到单个文件中
- 如果选择
package.json
表示几种保存在package.json
中- 是否将所有选择保存为预设(输入n)
- 等待安装完成,出现如下字样即表示创建成功。
- 运行项目:
cd
到指定文件夹,执行npm run serve
启动项目。
安装ESLint插件
ESLint 是一个用于检测和规范 JavaScript 代码风格及语法错误的工具。它可以帮助开发者保持代码的一致性和可读性,提高代码质量。例如,它能检查是否遗漏了分号,变量名是否符合规范等。
作用:检查代码格式,保证每个成员的代码风格应该一致。
安装方式:直接在vscode扩展商店中搜索ESLint
,点击下载即可。
当通过 @vue/cli 脚手架工具安装项目后,默认已经将 eslint 相关的包安装并配置好了。
我们将使用vue 的 eslint 插件规定的默认规则进行代码检查。如果需要查看规则,则可以查看 https://eslint.nodejs.cn/docs/latest/rules/%E3%80%82
ESLint报错提示:
配置ESLint
-
关于ESLint的配置,需要放到配置文件
.eslintrc.js
中。 -
打开
.eslintrc.js
文件,找到里面的rules
节点,这个rules
节点,用于自定义 ESLint规则 -
配置的每条语句结束,必须加分号。
例如:在 rules
节点中加入如下规则
"rules": {"semi": ["error", "always"]
}
注意⚠️:修改了配置文件,需要重启项目。
安装自动化格式插件
自动化格式插件有很多种,比如 ESlint、Vue插件,都带这种格式化功能。
这边的话就跟我的配置来安装包,保证了配置统一性。
安装步骤:
- 在扩展商店查找以下👇插件
- 打开 vscode,按
Ctrl + ,
快捷键,打开设置界面。 - 点击右上角的
打开设置(json)
- 将下面的代码复制进去(复制到最后一个大括号之前)
// 代码缩进 2 个空格
"editor.tabSize": 2,
// 保存(包括自动保存),自动格式化
"editor.formatOnSave": true,
// 按Ctrl + S保存时,自动修复
"editor.codeActionsOnSave": {"source.fixAll.eslint": true
},
// 编辑器窗口失去焦点时,自动保存代码【可选】
"files.autoSave": "onFocusChange",
// 配置vue默认的格式化程序【必须的配置】
"[vue]": {"editor.defaultFormatter": "numso.prettier-standard-vscode"
},
// 设置JS文件的默认格式化程序【必须的配置】
"[javascript]": {"editor.defaultFormatter": "numso.prettier-standard-vscode"
},
"[jsonc]": {"editor.defaultFormatter": "numso.prettier-standard-vscode"
},
注意⚠️:如果出现 黄色的下划线,说明有重复的配置。去掉前面的(你自己的)。
使用方法:
右键–>找到使用…格式化文档–>选择Prettier-Standard
Vant组件库
因为本次项目是一个移动端项目,所以移动端上使用的组件库目前比较不错的一个流行库就是Vant啦🥳。
官方网站:Vant 2 - 轻量、可靠的移动端组件库 (vant-ui.github.io)
安装步骤:
打开终端输入以下👇命令
npm i vant@latest-v2
安装如果有报错用👇
npm i vant@latest-v2 --legacy-peer-deps
检查是否安装完成:
引入组件
- 按需引入:只引入项目中实际用到的组件,能减小项目体积。通常通过配置或特定的模块加载方式实现。
- 全局引入:将组件库整体加载到项目中,在任何地方都能直接使用。比如在入口文件中一次性引入。
- 手动导入:把组件库当作一个模块,在需要的模块中单独引入相关组件。
⚠️ 注意三种方式不能混用。
⚠️ 我会讲按需引入
和全局引入
这两种方式的引入步骤,但是本项目使用的是全局引入的方式来制作。所以按需引入方式教学大家看看就好🙏。
全局引入
步骤:直接在main.js中粘贴以下👇代码:
import Vant from 'vant'
import 'vant/lib/index.css'
Vue.use(Vant)
按需引入
步骤:
-
安装一个插件(插件配置后,就可以实现自动导入)
npm i babel-plugin-import -D --legacy-peer-deps
-
在
babel.config.js
中配置module.exports = {presets: ['@vue/cli-plugin-babel/preset'],plugins: [['import', {libraryName: 'vant',libraryDirectory: 'es',style: true}, 'vant']] }
-
按需引入main.js
import { Button, Icon } from 'vant'Vue.use(Button) Vue.use(Icon)
-
在App.vue中测试
<van-button type="primary">主要按钮</van-button> <van-button type="info">信息按钮</van-button> <van-button type="default">默认按钮</van-button> <van-button type="warning">警告按钮</van-button> <van-button type="danger">危险按钮</van-button>
再次强调⚠️
完整导入和按需导入Vant,二者只能用一个;
- 如果你用完整导入,请将按需导入的配置都去掉,然后重启项目。
实现vw适配
使用Vant组件的适配方案就非常的简单😆。
官方说明:https://vant-contrib.gitee.io/vant/v2/#/zh-CN/advanced-usage
步骤:
-
安装命令
npm i postcss-px-to-viewport@1.1.1 -D 安装报错就用👇 npm i postcss-px-to-viewport@1.1.1 -D --legacy-peer-deps
-
在项目的根目录,新建一个配置文件
pocstcss.config.js
// postcss.config.js module.exports = {plugins: {'postcss-px-to-viewport': {// 设计稿如果是2倍图,宽是750,则 750/2 = 375,下面就写375// 设计稿如果是3倍图,宽是 1080,则 1080/3 = 360,下面就写360viewportWidth: 375}} }
路由配置
总体路由结构图:
我们根据上面的结构图分析一下,这个项目呢——是由4个页面组成的。
一共有4个一级目录:App.vue
、Login.vue
、Register.vue
、Detall.vue
和1个二级目录:Home.vue
。所以我们先根据结构创建好项目目录先。
怎么在src
文件夹下的views
新建以下👇文件:
-
Home.vue:用来做主页
<template><div id="app">主页</div> </template><script>export default {} </script><style lang="less" scoped></style>
-
Login.vue:用来做登录页
<template><div id="app">登录页</div> </template><script>export default {} </script><style lang="less" scoped></style>
-
Register.vue:用来做注册页
<template><div id="app">登录页</div> </template><script>export default {} </script><style lang="less" scoped></style>
-
Detall.vue:用来做详情页
<template><div id="app">登录页</div> </template><script>export default {} </script><style lang="less" scoped></style>
创建完上面四个文件之后我们还有在views
文件夹下再创建一个Layout
包,继续创建我们的二级目录文件:
-
Article.vue:文章列表
<template><div id="app">文章列表</div> </template><script>export default {} </script><style lang="less" scoped></style>
-
Collect.vue:收藏界面
<template><div id="app">收藏界面</div> </template><script>export default {} </script><style lang="less" scoped></style>
-
Like.vue:喜欢界面
<template><div id="app">喜欢界面</div> </template><script>export default {} </script><style lang="less" scoped></style>
-
User.vue:用户界面
<template><div id="app">用户界面</div> </template><script>export default {} </script><style lang="less" scoped></style>
配置路由
前置知识:路由
路由模版:
const routes = [{path:'/', //url地址component: () => import('文件路径'), //指定文件} ]
二级路由模版:
const routes = [{path:'/', //url地址component: () => import('文件路径'), //指定文件redirect: '/二级默认展示url地址', // 重定向,指向二级路由默认展示的页面children: [{path:'/', //url地址component: () => import('文件路径'), //指定文件}]} ]
直接在router文件夹下的index.js
文件下书写我们的路由代码。
import Vue from 'vue'
import VueRouter from 'vue-router'Vue.use(VueRouter)const routes = [// 主页{path: '/',component: () => import('@/views/Home.vue'),redirect: '/article', // 重定向,指向二级路由默认展示的页面children: [// 列表页{ path: 'article', component: () => import('@/views/Layout/Article') },// 藏页{ path: 'collect', component: () => import('@/views/Layout/Collect') },// 喜欢页{ path: 'like', component: () => import('@/views/Layout/Like') },// 用户页{ path: 'user', component: () => import('@/views/Layout/User') }]},// 登录页{ path: '/login', component: () => import('@/views/Login.vue') },// 详情页{ path: '/detail', component: () => import('@/views/Detail.vue') },// 注册页{ path: '/register', component: () => import('@/views/Register.vue') }
]const router = new VueRouter({routes
})export default router
之后在App.vue中和Home.vue中,分别加入 <router-view></router-view>
。
<template><div class="layout-page"><router-view></router-view></div>
</template><script>
export default {name: 'layout-page'
}
</script><style lang="less" scoped>
</style>
最后我们进而可以通过url栏手动修改值来测试一下页面跳转。
登录页面搭建
静态布局
效果展示:
登录页面的搭建主要用到Vant组件中的导航栏组件
。
所以我们只需要保留title属性即可:
<!-- 登录login页面 -->
<template><div class="login-page"><van-nav-bar title="面经项目登录" /></div>
</template><script>
export default {name: 'login-page',methods: {}
}
</script><style lang="less" scoped></style>
然后我们就要写一个表单来实现账号密码输入框,同样的在Vant组件中找到表单
组件。
我先来对一些代码字段解析一下让大家更好的理解:
<van-fieldv-model="username"name="username"label="账号"placeholder="请输入账号":rules="[{ required: true, message: '请填写用户名' }]"/>
v-model="username"
: 将输入字段的值绑定到 Vue 实例的username
数据属性上。name="username"
: 设置输入字段的name
属性,通常用于表单提交时标识字段。label="账号"
: 设置输入字段的标签文本为“账号”。placeholder="请输入账号"
: 设置输入字段的占位符文本为“请输入账号”。:rules="[{ required: true, message: '请填写用户名' }]"
: 设置输入字段的验证规则,这里要求输入字段必须填写,否则会显示错误消息“请填写用户名”。
然后就是修改提交
按钮的样式,我这里也是先对代码进行解释:
<van-button round block type="info" native-type="submit">提交</van-button>
round
: 使按钮具有圆角。block
: 使按钮宽度充满其父容器。type="info"
: 设置按钮的类型为info
,通常表示按钮具有提示或信息性质。native-type="submit"
: 将按钮的type
属性设置为submit
,使其在表单中可以提交表单数据。
我们还需要修改一下圆角按钮的样式,首先将提交
改为登录
,然后去掉小圆角,将按钮颜色改为橙色。
如何修改颜色呢?Vant 的 <van-button>
组件支持 color
属性,你可以直接在组件上设置颜色。例如,如果你想将按钮颜色改为橙色。
<div style="margin: 16px"><van-button block type="info" native-type="submit" color="#FF5500">登录</van-button>
下面还有一个超链接用于跳转到注册页面,可以使用a标签
或者是直接使用<router-link>
标签。我这里就用link标签方便一点。
<router-link to="/register">还没有账号,去注册吧!</router-link>
测试一下是否能跳转:
然后再给link添加一个class写样式:
<style lang="less" scoped>
.link {float: right;font-size: 14px;color: #ff5500;margin-right: 10px;
}
</style>
最后就完成了我们想要的效果啦🥳!
但是我们还可以把代码复制给Ai做一下界面美化。下面我就贴上我完成的代码:
<!-- 登录login页面 -->
<template><div class="login-page"><!-- 标题栏 --><van-nav-bar title="面经项目登录" /><!-- 表单 --><div class="font-div"><van-form @submit="onSubmit"><van-fieldv-model="username"name="username"label="账号"placeholder="请输入账号":rules="[{ required: true, message: '请填写用户名' }]"/><van-fieldv-model="password"type="password"name="password"label="密码"placeholder="请输入密码":rules="[{ required: true, message: '请填写密码' }]"/><div style="margin: 16px"><van-button block type="info" native-type="submit" color="#FF5500">登录</van-button></div></van-form><!-- 超链接-注册按钮 --><router-link class="link" to="/register">还没有账号,去注册吧!</router-link></div></div>
</template><script>
export default {name: 'login-page',data () {return {username: '',password: ''}},methods: {onSubmit (values) {console.log('submit', values)}}
}
</script><style lang="less" scoped>
.font-div {position: absolute;top: 26%;left: 50%;transform: translate(-50%, -50%);width: 300px;padding: 20px;border: 1px solid #ddd;border-radius: 8px;// box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);// background-color: #fff;
}.van-nav-bar {// background-color: #ff5500;margin-top: 10px;/deep/ .van-nav-bar__title {color: #ff5500;font-weight: 700;font-size: 25px;}
}.van-button {border-radius: 4px;
}.link {display: block;text-align: right;font-size: 14px;color: #ff5500;margin-top: 10px;
}
</style>
表单验证
Vant组件也有告诉我们,通过 rules
定义表单校验规则
使用 Field 的 rules
属性可以定义校验规则,可选属性如下:
键名 | 说明 | 类型 |
---|---|---|
required | 是否为必选字段,当值为空字符串、空数组、undefined 、null 时,校验不通过 | boolean |
message v2.5.3 | 错误提示文案 | string | (value, rule) => string |
validator v2.5.3 | 通过函数进行校验 | (value, rule) => boolean | Promise |
pattern v2.5.3 | 通过正则表达式进行校验 | RegExp |
trigger v2.5.2 | 本项规则的触发时机,可选值为 onChange 、onBlur | string |
formatter v2.5.3 | 格式化函数,将表单项的值转换后进行校验 | (value, rule) => any |
我们这里主要用到required
`message \
pattern `。通过正则表达式校验可以让我们对输入的信息进行数字、字母、长度的要求。
v-model="password"type="password"name="password"label="密码"placeholder="请输入密码":rules="[{ required: true, message: '请输入密码' },{pattern: /^(?=.*[a-zA-Z]).{2,6}$/,message: '密码必须为2-6位且包含至少一个字母'}]"/>
在这个正则表达式中:
^(?=.*[a-zA-Z])
是一个正向先行断言,确保字符串中至少包含一个字母(不区分大小写)。.{2,6}$
确保整个字符串的长度在2到6个字符之间。
如果规则比较多,可以在data里面写一个变量,
<van-fieldv-model="username"name="username"label="账号"placeholder="请输入账号":rules="userRules"
/>export default {name: 'login-page',data () {return {username: '',password: '',userRules: [{ required: true, message: '请输入账号' },{ pattern: /^\d{2,6}$/, message: '账号必须为2-6位数字' }]}},
}
其中 pattern
键名对应的正则表达式 /^\d{2,6}$/
用于验证输入是否全为数字且长度为2-6位。如果输入不符合这个正则表达式,将会显示 message
键名对应的错误信息。
注册页面布局
注册页面和登录页面大多相似,我们直接复制登录页面的代码到注册页面中,然后稍微做一些修改就好了。
- 修改标题
- 修改注册按钮
- 修改超链接,别忘了还有文本也要修改哦🤗
- 修改组件名称
- 修改主题颜色,然他和注册页面有所区分
整体效果:
发送请求
首先我们要注册一个账号,所以就要对后台数据发送请求,使用axios来完成这个注册操作。
首先安装一个axios包
npm i axios
如果报错了就用以下👇安装
npm install axios --legacy-peer-deps
axios前置知识
补一下前置知识有关axios的内容!
import axios from 'axios'export default{name:'',date(){},method:{async onSubmit(values){//定义一个变量接受结果const {data:res} = await axios({method:'',url:'',data:value})console.log(res)}}
}
因为黑马那边的数据接口关闭了,所以我们没办法调用他们接口里面的数据。既然别人不给我们,那么我们就自己造!因为大家都是前端朋友,使用json-server来搭建接口会更加友好一点,不会涉及后端知识,也不用mysql数据库。
搭建数据大家可以看我这一篇文章:
然后我们这里的话也是用的是json-server,我这里给大家放上json数据供大家搭建
{"users": [{"id": 1,"name": "李雷","UID": "01a1"},{"id": 2,"name": "韩梅梅","UID": "02b2"},{"id": 3,"name": "张伟","UID": "03c3"},{"id": 4,"name": "王芳","UID": "04d4"},{"id": 5,"name": "赵敏","UID": "05e5"},{"id": 6,"name": "马云","UID": "06f6"},{"id": 7,"name": "马东","UID": "07a7"}],"register": [{"id": 1,"username": "01","password": "a1"},{"id": 2,"username": "02","password": "a2"},{"id": 3,"username": "03","password": "a3"},{"id": 4,"username": "04","password": "a4"},{"id": 5,"username": "05","password": "a5"},{"id": 6,"username": "06","password": "a6"},{"id": 7,"username": "07","password": "a7"}]
}
封装axios
为了让整体项目更加的规整,我们需要将axios单独封装到一个文件当中,方便后面管理。
我们在src目录下新建一个utils
文件夹,里面再新建一个文件一般叫做request.js
。
// 封装axios请求
// 1.导入axios
import axios from 'axios'
// 2.配置
const requerst = axios.create({// 配置请求根路径baseURL: 'http://localhost:5000'// 超时时间// timeout:5000
})
// request配置拦截器
// 3.导出
export default requerst
导入request.js文件
import request from '@/utils/request'
配置axios
async onSubmit (values) {const { data: res } = await request({method: 'POST',url: '/register',data: values})console.log(res)
抽离注册的API方法
在src目录下新建一个Api
文件夹,里面再新建一个文件一般叫做user.js
。用来存放与用户相关的请求。
// 和用户相关的请求
import request from '@/utils/request'export function registerAPI (data) {return request({method: 'POST',url: '',data: data})
}
在注册组件中导入api方法
// <!-- 导入封装的axios -->
// import request from '@/utils/request'
// 导入API方法
import { registerAPI } from '@/Api/user'
记得把上次导入axios语句注释掉⚠️
修改调用方法
const { data: res } = await registerAPI()
// 之前的都注释掉了// request({// method: 'POST',// url: 'register',// data: values// })
我们可以发现调用的registerAPI
依旧是原来的request
。
最后再给registerAPI()方法传入values参数:
const { data: res } = await registerAPI(values)
还有user.js里面的url写上我们的路径:
// 和用户相关的请求
import request from '@/utils/request'export function registerAPI (data) {return request({method: 'POST',url: 'register', //user.js里面的url写上我们的路径data: data})
}
之所以要这样写,就是为了我们这个方法能够复用起来,以后要使用这个直接调用这个方法就可以了。
注册、登录页面跳转
下面我们就要写一个注册跳转功能,让我们注册完之后跳转到登录界面 。使用axios的try
和catch
方法来实现。
async onSubmit (values) {try {const { data: res } = await registerAPI(values)console.log(res) // 其实这个res这个变量没有用到过,可以删掉也可以的this.$toast('注册成功')this.username = this.password = '' // 重置表单this.$router.push('/login') // 跳转到登录页面} catch (err) {}}
同样的我们也在登录页面设置一些,来实现登录成功跳转到首页当中。这一次我们只需要在login.vue文件中进行设置就可以了,具体代码和注册跳转是同样滴。
methods: {// 点击登录的时候执行async onSubmit (values) {// values={username:'',password:''}try {await registerAPI(values) //这里我就把没有用到的data删掉了this.$toast('登录成功')this.username = this.password = ''this.$router.push('/article') //这里url要变成主页的地址} catch (err) {}console.log('submit', values)}}
⚠️前面别忘记导入封装好的registerAPI
方法。
主页搭建
面经列表数据
封装面经方法
在Api包中新建一个article.js
。
// 存放和面经内容相关的请求
import request from '@/utils/request'export function articleAPI (params) {return request({url: '',params: params})
}
这里因为params先待定。
然后我们在article.vue组件中的脚本区域获取数据。
import { articleAPI } from '@/Api/article'
export default {name: 'article-page',data () {return {curent: 1, // 页码、获取第一页的数据sorter: 'weight_desc'}},methods: {async article () {const { data: res } = await articleAPI({current: this.current,sorter: this.sorter})console.log(res)}},created () {this.article() // 创建生命周期,使其一开始就加载页面}
}
{"code": 10000,"message": "请求成功","data": {"current": 1,"pageTotal": 10,"pageSize": 20,"total": 1000,"rows": [{"id": "40821","stem": "广东紫云平台数据服务有限公司前端面经,未通过","content": "<p><b>面试公司:</b>广东紫云平台数据服务有限公司<br></p><p><b>面试岗位"createdAt": "2022-01-20 00-00-00","creator": "中二苏北陌","avatar": "http://teachoss.itheima.net/heimaQuestionMiniapp/%E5%AE%98%E6%96%B9%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F%402x.png","likeCount": 1,"views": 32}]}
}
axios前置知识——get请求
省略
method
属性(默认GET):javascriptexport function articleAPI(data) {return request({url: '', // 这里应填写实际的API URLparams: data // 使用params来传递URL查询参数}); }
明确指定
method
为'GET'
:javascriptexport function articleAPI(data) {return request({method: 'GET',url: '', // 同样需要填写实际的API URLparams: data}); }
在这两种方式中,
params
属性用于传递URL查询参数,这是GET请求中常见的做法。例如,如果你需要根据用户ID获取文章详情,你可以这样调用articleAPI
函数:javascript复制 articleAPI({ userId: 123 });
面经页面搭建
页面搭建就是用Vant组件库里面的Cell单元格,通过循环遍历的方式,来渲染出列表。
<van-cell title="单元格" value="内容" />
但是单元格现实的内容太少了,我们还需要用到插槽
来搭建更多的内容。
<van-cell value="内容" is-link><!-- 使用 title 插槽来自定义标题 --><template #title><span class="custom-title">单元格</span><van-tag type="danger">标签</van-tag></template>
</van-cell><van-cell title="单元格" icon="shop-o"><!-- 使用 right-icon 插槽来自定义右侧图标 --><template #right-icon><van-icon name="search" class="search-icon" /></template>
</van-cell><style>.custom-title {margin-right: 4px;vertical-align: middle;}.search-icon {font-size: 16px;line-height: inherit;}
</style>
给插槽传值
在Vue 2中,给插槽(slot)传值通常使用
slot-scope
属性。slot-scope
属性允许你将数据传递给具名插槽或作用域插槽。全写形式:<template v-slot:title> 简写形式:<template #title>
静态结构我去直接提供给大家啦,大家可以试一试调一调。
<template><div class="article-page"><nav class="my-nav van-hairline--bottom"><a href="javascript:;">推荐</a><a href="javascript:;">最新</a><div class="logo"><img src="@/assets/logo.png" alt=""></div></nav><van-cell class="article-item" ><template #title><div class="head"><img src="@/assets/logo.png" alt="" /><div class="con"><p class="title van-ellipsis">宇宙头条校招前端面经</p><p class="other">不风流怎样倜傥 | 2022-01-20 00-00-00</p></div></div></template><template #label><div class="body van-multi-ellipsis--l2">笔者读大三, 前端小白一枚, 正在准备春招, 人生第一次面试, 投了头条前端, 总共经历了四轮技术面试和一轮hr面, 不多说, 直接上题 一面</div><div class="foot">点赞 46 | 浏览 332</div></template></van-cell></div>
</template>
样式:
<style lang="less" scoped>
.article-page {margin-bottom: 50px;margin-top: 44px;.my-nav {height: 44px;position: fixed;left: 0;top: 0;width: 100%;z-index: 999;background: #fff;display: flex;align-items: center;> a {color: #999;font-size: 14px;line-height: 44px;margin-left: 20px;position: relative;transition: all 0.3s;&::after {content: '';position: absolute;left: 50%;transform: translateX(-50%);bottom: 0;width: 0;height: 2px;background: #222;transition: all 0.3s;}&.active {color: #222;&::after {width: 14px;}}}.logo {flex: 1;display: flex;justify-content: flex-end;> img {width: 64px;height: 28px;display: block;margin-right: 10px;}}}
}
.article-item {.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 10px;p {margin: 0;line-height: 1.5;&.title {width: 280px;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>
将单个单元格封装成组件
因为不止在主页中会用到这个单元格列表,其二级目录下的收藏页,或者喜欢页也都会有这个列表的展示,所以我们不妨直接将他封装成一个组件,后面需要用到的时候直接调用即可ヾ(◍°∇°◍)ノ゙。
在src下面新建一个components
文件夹用来存放组件,然后新建一个.vue
文件,就叫做Articleitem.vue
吧。
然后把上面写的单元格列表和样式全部丢进去(≧∇≦)ノ。
<!-- 封装单元格组件 -->
<template><div><van-cell class="article-item"><template #title><div class="head"><img src="@/assets/logo.png" alt="" /><div class="con"><p class="title van-ellipsis">宇宙头条校招前端面经</p><p class="other">不风流怎样倜傥 | 2022-01-20 00-00-00</p></div></div></template><template #label><div class="body van-multi-ellipsis--l2">笔者读大三, 前端小白一枚, 正在准备春招, 人生第一次面试, 投了头条前端,总共经历了四轮技术面试和一轮hr面, 不多说, 直接上题 一面</div><div class="foot">点赞 46 | 浏览 332</div></template></van-cell></div>
</template><script>
export default {}
</script><style lang="less" scoped>
.article-item {.head {display: flex;img {width: 40px;height: 40px;border-radius: 50%;overflow: hidden;}.con {flex: 1;overflow: hidden;padding-left: 10px;p {margin: 0;line-height: 1.5;&.title {width: 280px;}&.other {font-size: 10px;color: #999;}}}}.body {font-size: 14px;color: #666;line-height: 1.6;margin-top: 10px;}.foot {font-size: 12px;color: #999;margin-top: 10px;}
}
</style>
注册全局组件
在main.js
中导入:
import ArticleItem from '@/components/ArticleItem.vue'
注册:
Vue.component('ArticleItem', ArticleItem)
回到Article.vue文件使用组件
<ArticleItem></ArticleItem>
[eslint]Component name "Articleitem" should always be multi-word vue/multi-word-component-names
循环遍历列表数据
在data中创建list用来存储面经列表项目
data () {return {curent: 1, // 页码、获取第一页的数据sorter: 'weight_desc'list:[] //存储要展示的面经列表项目}},
v-for循环遍历
<ArticleItem v-for="item in list" :key="item.id" :item="item" //父传子></ArticleItem>
子组件接受传值
props: {item: {type: Object,//默认值如果是数组或对象,则而要写成函数,函数中返回数组或对象default: () =>({})}}
使用差值表达式渲染数据
推荐和最新栏目
类名切换
接口文档中是规定了排序字段通过这个来区分最新
还是推荐
。
sorter属性通过发请求数据到之前定义好的onLoad
方法中:
用到的是切换类名,通过绑定类名的值,在模版字符串里面进行判断接口中的数据是哪一种,吐过是推荐就传weight,如果是最新页面就不要传值。
然后还有添加一个点击事件,作用是为了通过点击事件实现两个a标签切换。
点击方法:
数据切换
类名变换实现了,那么我们的样式就会改变。
继续调用上面的Onload
方法,来获取到数据。
最不好理解的问题,如果在推荐页面滚到比较低的地方,然后切换到最新页面,这个时候滚动条依旧还在先前推荐页面滚动的位置,而不是重新再最顶部。为了避免重复发送请求,就要加上这句代码:
this.loading=true//避免自动发送请求
实现详情页
数据获取
我们希望在列表中点击标题的时候,能够进入到详细页面中观看内容。
localhost:8080/#/detail
这个时候就要用到路由传参
前置知识——路由传参
传参方式
地址栏
- 查询参数:
/xx/xx?id=2
- path:
/xx/xx
- 组件中获取参数值:
$route.query.id
动态路由
- 动态路由:
/xx/xx/2
- path:
/xx/xx/:id
- 组件中获取参数值:
$route.params.id
-
设置传参方式,在封装好的articleitem.vue组件中添加一个点击事件
@click="$router.push(/detail?id=${item.id})
-
路由规则不需要改动
-
组件中获取参数值
内容渲染
在article.js
文件中封装axios组件
导入封装好的axios请求
组件中处理请求数据
收藏点赞功能
在文章中,我们会有两个小按钮来实现收藏和点赞两个功能。
主要是通过的在接口里面的这两个数据:
在组件中使用:
-
绑定数据
-
添加点击事件
-
编写方法
-
处理细节
当我们点赞的时候,这里也要加上“1” -
提示功能就用咱们得
轻提示
就好啦。this.$toast.success('点赞成功')
-
修改服务器数据,因为我们做的都是页面上的数据,还没有涉及到服务器请求。一刷新就回到原来的数据了。
实现主题定制
整体网站风格,其实都是橙色的,可以通过变量覆盖的方式,制定主题色
https://vant-contrib.gitee.io/vant/v2/#/zh-CN/theme
注意 ⚠️下面的操作会涉及到修改配置文件,所以修改完配置文件之后都要重启一下项目。
引入样式源文件
main.js
引入less:
import Vant from 'vant'
import 'vant/lib/index.css'
import 'vant/lib/index.less'
Vue.use(Vant)
修改样式变量
vue.config.js
覆盖变量,直接全部复制我们的覆盖掉原来代码就可以了。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,css: {loaderOptions: {less: {// 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。lessOptions: {modifyVars: {// 直接覆盖变量blue: '#ff5500',// 'text-color': '#111',// 'border-color': '#eee'// 或者可以通过 less 文件覆盖(文件路径为绝对路径)// hack: 'true; @import "your-less-file-path.less";'}}}}}
})
修改配置文件后,需要重启服务。
实现收藏和喜欢页面
收藏和喜欢的页面结构都是一样的,就像登录
和注册
一样。所以我们只需要写一个页面,后面再稍微做一下修改就完成了这两个页面。
写一个标题栏:
1.收藏页标题去登录页复制
<template><div class="collect-page"><van-nav-bar fixed title="我的收藏" /><van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad"><article-item v-for="(item, i) in list" :key="i" :item="item" /></van-list></div>
</template>
封装API请求方法:
export const collectAndLikeListAPI = (params) => {return request.get('/h5/interview/opt/list', {params: params})
}
script内容:
去Article.vue复制<van-list></van-list>
,然后去Article.vue复制data和methods
,去掉sorter变量:去掉changeSorter方法
,最后在api/articlejs中,新封装一个获取收藏列表的方法
<script>
import { collectAndLikeListAPI } from '@/api/article'
export default {name: 'collect-page',data () {return {list: [],loading: false,finished: false,page: 1}},methods: {async onLoad () {// 异步更新数据const { data: res } = await collectAndLikeListAPI({page: this.page,optType: 2})this.list.push(...res.data.rows)this.loading = falseif (this.page === res.data.pageTotal || !res.data.rows.length) {this.finished = true} else {this.page++}}}
}
然后我们在首页收藏一些页面,就有最终的效果啦!
喜欢页面也是一样的,直接复制上面的代码,修改请求参数optType: 1
即可。
前置知识——vuex的使用
Vuex是vue项目中实现大范围数据共享的技术方案。
作用:能够方便、高效的实现组件之间的数据共享。
安装vuex
npm i vuex@3.6.2
配置vuex
- 封装一个store模块,里面新建一个index.js
- 在man.js导入store
基本使用:
state用于存储数据。
state:{name:'tom',age:20 }
组件中直接使用数据,组件中可通过
$store.state.属性名
getters是vuex中的计算属性,和组件中的计算属性意义一样,但是不支持set修改。
getters:{abc(state){return s state.age * state.age} }
为了方便取state中的数据:插件作者会给每个计算属性方法,传递一个state参数。
使用和state用法一致
$store.getters.属性名
导航守卫
前置知识——导航守卫
加入导航守卫,目的是如果在没有登录的情况下,是不允许访问到其他的页面。
- to.path — 要访问的地址
- from.path — 你从哪里来的
- next() — 放行
- next(‘/url’) — 不放行,并且跳转到url中。
在router.index.js路由文件中使用以下👇代码:
router.beforeEach((to,from,next)=>{if (to.path !=='/login'&& store.state.user.token === ''){next('/login')return}next()
})
打包项目
在项目终端中运行npm run build
打包的时候可能会有一点点久,大家稍等一会。
当再次出现终端路径,就表示打包完成了。
打包完毕之后就会生成一个dist
文件夹,文件夹里面的内容如下:
然后我们发现点击index.html
,项目是展示不出来的。因为我们的一些数据都在接口服务器上,需要在服务器上打来才行。如果要本地打开也不是没有办法,我们在vue.config.js
文件中添加下面一句话:
//表示打包的结果,允许以文件的形式打开
publicPath:'./'
我们还会发现在生成的文件当中会出现非常的.map
文件,这个作用就是映射原始代码对应打包后的代码位置,一般可以不要的。在vue.config.js
文件中添加下面一句话:
//去掉mao文件
productionSourceMap:false
然后还可以添加一个方法——生成打包报告,来看看是那些文件占用的体积比较大。
对于一些外部组件库,可以使用CDN
(引入网络中的文件)的方式引入组件。
然后再重新npm run build
打包文件。