Vue小项目总结
简介
项目是一个关于工作室的招新官网,分四个如下模块:
该项目由vue框架搭建而成,使用css中less预处理语言,涉及一些值得记录的知识点,方便今后回顾,包括:搭建好Vue基本框架,公共css样式导出,风车图的旋转,按钮点击后页面的显示和隐藏,对接后端接口,elementUI中form表单的使用,打包dist等。
一、搭建基本框架
1.创建名为maker-iot的项目:
- vue create maker-iot
- 选择Manually select featrues
- 空格选择Babel、Router、Vuex、CSS pre-processors
- 选择3.x
- 输入No
- 选择Less
- 选择In dedicated config files
- 是否保存:Y 如上操作,即创建完毕
二、公共样式导出,并解决重复引用问题
1.在assets中创建style文件夹,创建mixins.less
,variables.less
文件,
敲下以下代码:
mixins.less:此处运用到混入,可进一步减少css冗余。
// 鼠标经过上移阴影动画
.hoverShadow() {
margin-top: 10px;
&:hover {
margin-top: 20px;
}
}
.size {
width: 100px;
height: 100px;
}
.size2(@w) {
width: @w;
height: @w;
}
// 运用混入
.box {
.size2(200px);
.hoverShadow ();
background-color: red;
text-align: center;
line-height: 200px;
}
variables.less:此处为常用变量参数,调用该参数替代名作为调节样式,方便统一修改
// 主题
@xtxColor: #27BA9B;
// 辅助
@helpColor: #E26237;
// 成功
@sucColor: #1DC779;
// 警告
@warnColor: #FFB302;
// 价格
@priceColor: #CF4444;
2.为了避免在不同组件中重复引入该样式,故在vue.config.js中配置如下
配置前在终端安装响应插件:vue add style-resources-loader
之后写入以下代码:
// +(解决文件需重复引入)
const path = require('path');
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 为解决以下两个文件需要重复引入的问题
// 在此之前需要执行以下代码:vue add style-resources-loader
pluginOptions: {
'style-resources-loader': {
preProcessor: 'less',
patterns: [
// __dirname绝对路径
// +(解决文件需重复引入)
path.join(__dirname, './src/assets/styles/variables.less'),
// +(解决文件需重复引入)
path.join(__dirname, './src/assets/styles/mixins.less')
]
}
},
})
3.在组件中使用案例:
<div class="box">
我是盒子
</div>
.box {
background-color: @helpColor;
}
盒子样式如下:
4.可以在style文件夹中建base.css,在main.js中引入,作为全局初始化样式,一般可设如下代码:
* {
padding: 0;
margin: 0;
/* 边框+内边距计入盒子宽高 */
box-sizing: border-box;
}
body {
font-family: '仿宋', '微软雅黑';
font-size: 14px;
/* 行高是字体大小的1.5倍 */
line-height: 1.5;
font-weight: normal;
color: #333;
background-color: #f9f9f9;
}
/* 边框宽度为0 */
/* 默认宽度为100%,父级宽度多少它宽度就多少 */
div {
border-width: 0px;
}
a {
color: #333;
text-decoration: none;
outline: none;
}
li {
list-style: none;
}
/* 设置边框样式 */
input {
outline: none;
}
/* 媒体查询 */
@media (max-width: 768px) {
/* 在小屏幕下,调整全局样式 */
body {
font-size: 12px;
}
}
.ellipsis {
/* 不换行 */
white-space: nowrap;
/* 超出显示省略号 */
text-overflow: ellipsis;
/* 超出内容隐藏 */
overflow: hidden;
}
/* 超过两行生省略号 */
.ellipsis-2 {
/* 对于中日韩英等文本,可以实现任意字符换行 */
word-break: break-all;
text-overflow: ellipsis;
/* 隐藏超出部分的内容,用于清除浮动,裁剪文本 */
overflow: hidden;
}
/* 清除浮动 */
.clearfix::after {
content: '';
display: block;
/* 隐藏元素但仍占据空间 */
visibility: hidden;
/* 在元素下方新建一行,并清除所有浮动元素的影响;*/
/* 常用于解决父元素因为子元素浮动而导致高度坍塌问题 */
clear: both;
}
导入main.js中,import './assets/styles/base.css'
三、风车旋转
例图如下:
下面我将分三个版块来介绍该风车图:
1.点击前端组,左上角 "& &组——现任成员"修改为"前端组——现任成员",整个前端组的成员介绍展现出来,此处运用路由进行了跳转,思路如下:
a、在Member中创建各个组的组件,如下:
b、在Router的index.js中引入路由:
//导入路由部分
//成员
import Member from '@/views/Member.vue'
//引入二级路由
import MemberCopy from '@/views/Member/MemberCopy.vue'
//引入三级路由
import BackEnd from '@/views/Member/BackEnd.vue'
...
import HardWare from '@/views/Member/HardWare.vue'
const routes = [
{
path: '/',
...
},
{
path: '/Member',
component: Member,
children: [
{
path: '/Member',
component: MemberCopy,
children: [
{
path: '/Member',
component: BackEnd
},
...
{
path: '/HardWare',
component: HardWare
}
]
}
]
},
c、在MemberCopy.vue文件中使用路由:
<router-link to="/Front">
<div class="group">
前端组
</div>
</router-link>
...
2.中间的介绍版块顺时针旋转,头像始终保持向上:
a、基本结构如下:
<ul class="circle">
<li>
<button @click="showone(1)"
:class="yin===1? 'active':''" >
<img src="../../assets/qq头像/YG.jpg" alt="">
</button>
</li>
<li>
<button @click="showone(2)"
:class="yin===2? 'active':''" >
<img src="../../assets/qq头像/WH.jpg" alt="">
</button>
</li>
...
</ul>
b、其对应的css样式:
ul {
width: 6.2rem;
...
transform-origin: 3.1rem 3.1rem;
animation: tf 34s linear infinite;
li {
width: 1.2rem;
...
//旋转点自身高度的一半,父亲宽度的一半+自身宽度的一半
transform-origin: .6rem 3.7rem;
button {
width: 1.2rem;
...
//反向旋转
animation: tf reverse 34s linear infinite;
}
&:nth-of-type(2) {
transform: rotate(72deg);
img {
transform: rotate(-72deg);
}
}
&:nth-of-type(3){
transform: rotate(144deg);
img {
transform: rotate(-144deg);
}
}
...
}
}
@keyframes tf {
0%{
transform:rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
(其实此处的button按钮略显多余,下次可以试着把button删去,将点击事件放在小 li 容器中)
3、当点击按钮时,展现对应的文字介绍:
a、介绍版块如下:
<div id="circle-text"
v-show="yin==1">
<div id="circle-tu-wen">
...
</div>
<div id="member-introduce">
...
</div>
</div>
<div id="circle-text"
v-show="yin==2">
<div id="circle-tu-wen">
...
</div>
<div id="member-introduce">
...
</div>
</div>
...
b、按钮版块可如上2.a所示
c、对介绍版块进行判断是否显示:
export default {
data () {
return {
// 控制切换按钮后按钮改变样式
yin: 1,
// 控制点击按钮后子组件显示,再次点击隐藏
shi: true,
}
},
methods: {
//判断函数
showone (value) {
this.yin === value ? this.shi = !this.shi : this.shi = true
this.yin = value
},
},
setup() {
let pasttext = reactive({
first:{
name: '* *',
occupation: '前端组长,前端开发',
signature:'永远做自己能力范围内的事,就无法取得进步'
},
second:{
...
}
...
});
return {
pasttext
}
}
}
四、导入elementUI,并使用表单
1.安装elementUI:
npm install element-plus --save
2.在main.js全局导入:
import ElementPlus from 'element-plus'
3.调用elementUI:
const app = createApp(App);
app.use(ElementPlus).mount('#app');
4.开始使用form表单:
<template>
<el-form :model="form">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入你的姓名" required />
</el-form-item>
</template>
<script>
import {reactive} from "vue"
export default {
setup() {
const form = reactive({
name: '',
introduce:''
)}
return {form}
}
<style scoped lang="less">
// 改变element元素样式
/deep/.el-form-item__label {
font-size: .4rem;
}
/deep/.el-input__inner {
&::placeholder {
font-size: 14px;
}
}
</style>
五、路由之间传值
从Join组件传值给JoinSpecific
1.在join组件中:传"后端"数据到JoinSpecific
<router-link :to="{path:'/JoinSpecific',query:{name:'后端'}}">
<el-button type="primary" round id="shenqing">申请岗位</el-button>
</router-link>
2.在router中index.js文件中,导入路由:
import JoinSpecific from '@/views/Join/JoinSpecific'
const routes = [
{
path: '/',
name: 'HomeView',
component: HomeView,
children: [
{
path: '/',
component: Home
}
]
},
...
//和主页面路由同级
{
path: '/JoinSpecific',
name: 'JoinSpecific',
component: JoinSpecific
}
]
3.在JoinSpecific中接收数据:
import { onMounted} from 'vue'
import { useRoute } from 'vue-router'
export default {
setup(){
let $route = useRoute()
onMounted(() => {
//注意:箭头函数中this指向
form.introduce=$route.query.name
})
}
}
六、连接接口,传值给后端
1.首先导入axios:
a、安装axios:npm install axios --save-D
b、在main.js中导入:
//引入axios
import axios from 'axios'
const app = createApp(App);
app.use(store)
.use(router)
.use(ElementPlus)
.mount('#app');
app.config.globalProperties.$http = axios;
2.在src中建utils文件夹,再建request.js文件,导入base_url:
import axios from 'axios'
//创建axios实例
const service = axios.create({
baseURL: 'http://124.222.203.172:8081', // api的base_url。此处为nginx的地址
timeout: 50000 // 请求超时时间
})
export default service
3.在src中建api文件夹,再建use.js文件,导入request.js,返回post请求:
import request from '@/utils/request'
export default {
// 没有,默认为空
newMember(userInfo = {}) {
return request({
url: `/makerservice/newMember/rigist`,
method: 'post',
data: userInfo
})
},
}
4.在JoinSpecific中点击提交按钮,发送数据
<template>
<el-button type="primary" round @click="submitForm()">申请岗位</el-button>
</template>
<script>
import UserApi from '@/api/user.js'
export default {
setup(){
function submitForm() {
alert('你已经提交成功')
UserApi.newMember(form)
.then(response => {
this.code = response.data.code
//手动将name清空
form.name = ''
})
}
}
}
</script>
此处有个提交数据后清空的问题,使用this.$refs.form.resetFields();
无法实现,解决方法:手动清空 form.name = ''
七、打包dist文件:
1.在vue.config.js中加入以下内容
module.exports = defineConfig({
publicPath: "./",
// 构建时的输出目录
outputDir: "dist",
// 放置静态资源的目录
assetsDir: "assets",
// html 的输出路径
indexPath: "index.html",
//文件名哈希
filenameHashing: true,
lintOnSave: true,
// 是否使用带有浏览器内编译器的完整构建版本
runtimeCompiler: false,
// babel-loader 默认会跳过 node_modules 依赖。
// 配置 webpack-dev-server 行为。
devServer: {
open: process.platform === 'darwin',
host: '0.0.0.0',
port: 8081,
https: false,
hotOnly: false,
// 查阅 https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-cli/cli-service.md#配置代理
proxy: {
'/api': {
target: "http://124.222.203.172.maker-iot.com", // 项目用到的域名
changeOrigin: true,
secure: false,
pathRewrite: {
"^/api": ""
}
},
// '/foo': {
// target: '<other_url>'
// }
}
}
})
2.执行 npm run build
开始打包
总结
1.本次项目,没有合理运用到页面布局框架,纯靠HTML和CSS手写,耗时费力,且得到的效果并不理想,当页面用手机端打开时,整个页面布局会乱掉,由于布局上的失误,导致后续的响应式难以实现,更改量大。
关于实现页面布局响应式问题,需要利用好现有的框架,在做界面时,反复在电脑和手机端查看,尽量做到在不同机位上,都能有较为美观的展现。
2.由于后期需求不断变化,更改频繁,多次在调整样式时,耗费时间,并没有很大意义。下次需注意:做好需求分析,明确对方需要怎样的界面效果,并在一开始就尽可能收集页面布局的相关信息,考虑清楚后再动手写,会相对轻松且高效。
3.没有合理运用好css公共样式,在不断写重复代码,出现代码冗余,这点同样值得注意。
4.另外,网页部署上去后,会出现渲染延迟的问题,这一点在下一次做项目时,需要注意到并解决。
5.网页放在不同电脑上打开,有的盒子会相对减小,导致文字超出原本涉及的盒子大小,下一次需要考虑到页面兼容的问题。
转载自:https://juejin.cn/post/7234315967563104313