概要
提示:本文书写前端概要用来整理自己开发思想,万能公式,所有开发需求为主,实际开发中还需具体情况具体分析
例如:
前端开发总结两字无非就是获取数据展示数据,让数据在页面中展示好看而已,所有我们可以整体分开展示,一个为获取数据,一个为展示数据
展示数据
` 提示:总结来说用html与css让页面展示出来
1.在开发中我们对需求时候我会浏览整个需求文档,需求原型在自己心中做到一个有数
比如:
一个很简单的页面,我从中获取到的上面一个数据展示,中间一个tab切换,下面一个可编辑列表,首先我会考虑我要先去找一个可编辑列表的组件,所以我找了一个ui库,然后在开发中,我想到如果把这个封装成一个组件,那会不会在所有之中我就能直接传值取值使用所以代码实现如下:
<script setup>
import {ref, defineProps, onBeforeMount, watch} from 'vue';
import {uuid} from "@/pages/activiti/config/utils/utils";
import FormCell from "@/components/UC/FormCell/index.vue";
const props = defineProps({
rows: {
type: Array,
default: () => [ {
uuid:uuid(),
},],
},
columns: {
type: Array,
default: () => [],
},
options: {
type: Array,
default: () => [],
},
disabled: {
type: Boolean,
default: false,
},
addhidden: {
type: Boolean,
default: true,
},
});
const rowsData = ref(props.rows)
watch(() => props.rows, (newValue, oldValue) => {
rowsData.value = []
rowsData.value = newValue
},{deep: true})
/**
* 新增行
*/
const openAdd = () => {
rowsData.value.push({uuid:uuid()})
}
/**
* 删除行
* @param row
*/
const del = (row) => {
const index = rowsData.value.findIndex(r => r.uuid === row.uuid);
if (index !== -1) {
rowsData.value.splice(index, 1);
}
}
//下载附件
async function down(row) {
let save_link = document.createElement("a");
save_link.href = row.url;
save_link.download = row.name;
save_link.click();
}
//预览
function downpre(row) {
window.open(row.previewUrl);
}
const gridData = ref([]);
const uploadList = ref([]);
const fujianlog = ref([]);
watch(
uploadList,
(newValue, oldValue) => {
if (newValue && newValue.length === 1) {
gridData.value.push(uploadList.value[0]);
fujianlog.value.push("新增附件" + newValue[0].name);
uploadList.value = [];
}
},
{ deep: true }
);
/**
* 打开上传弹窗
* @param attachment1
* @param rowIndex
*/
const dialogTableVisible = ref(false);
const uploadIndex = ref("");
const field = ref("");
const openUpLoad = (attachment1, rowIndex,disabled,field1) => {
if(disabled) return
uploadIndex.value = rowIndex;
field.value = field1;
gridData.value = [];
fujianlog.value = [];
if (attachment1) {
let myArray;
// 判断 attachment1 是否是 JSON 字符串
if (typeof attachment1 === 'string') {
try {
// 尝试将 JSON 字符串解析为数组
myArray = JSON.parse(attachment1);
} catch (error) {
console.error('attachment1 不是有效的 JSON 字符串:', error);
return; // 如果解析失败,直接返回
}
} else if (Array.isArray(attachment1)) {
// 如果 attachment1 已经是数组,直接使用
myArray = attachment1;
} else {
console.error('attachment1 不是数组或 JSON 字符串');
return; // 如果 attachment1 不是数组或 JSON 字符串,直接返回
}
// 如果数组不为空,进行处理
if (myArray.length > 0) {
const myString = JSON.stringify(myArray);
gridData.value = JSON.parse(myString);
}
}
dialogTableVisible.value = true;
}
//删除单个附件
function handleDelete(index, row) {
gridData.value.splice(index, 1);
console.log(fujianlog, row.name, "row");
let delFujian = "删除附件" + row.name;
fujianlog.value?.push(delFujian);
console.log(fujianlog.value, "111");
}
//提交附件
function submitUpload() {
rowsData.value[uploadIndex.value][field.value] =gridData.value;
if (rowsData.value[uploadIndex.value].attachmentLog) {
fujianlog.value.forEach((item) => {
rowsData.value[uploadIndex.value].attachmentLog.push(item);
});
} else {
rowsData.value[uploadIndex.value].attachmentLog=fujianlog.value
}
dialogTableVisible.value = false;
}
const shouldShowUpload=(fieldValue)=> {
return fieldValue && (Array.isArray(fieldValue) || typeof fieldValue === 'string');
}
// 获取字段值,处理 JSON 字符串
const getFieldValue=(fieldValue)=> {
if (!fieldValue) return [];
// 如果是字符串,尝试解析为 JSON
if (typeof fieldValue === 'string') {
try {
const parsedValue = JSON.parse(fieldValue);
if (Array.isArray(parsedValue)) {
return parsedValue;
}
} catch (e) {
console.error('Failed to parse JSON:', e);
}
}
// 如果是数组,直接返回
if (Array.isArray(fieldValue)) {
return fieldValue;
}
// 其他情况返回空数组
return [];
}
/**
* 获取表格数据
*/
const getData=()=>{
return rowsData.value
}
onBeforeMount(()=>{
})
defineExpose({
getData,
})
</script>
<template>
<div class="q-pa-md" style=" height: 100%;">
<div class="q-mb-md " style="text-align: right;" v-show="!disabled">
<q-btn label="新增" v-if="addhidden" color="primary" @click="openAdd()"></q-btn>
</div>
<q-table
:rows="rowsData"
:columns="columns"
row-key="id"
hide-pagination
:bordered="false"
:pagination="{ rowsPerPage: 0 }"
class="my-sticky-header-table11"
>
<template v-for="(c,index ) in columns" #[`body-cell-${c.field}`]="props">
<q-td :key="c.field" :props="props"
>
<template v-if="c.field === 'rowIndex'">
{{ props.rowIndex+1 }}
</template>
<template v-else-if="c.field === 'btn'" >
<q-btn
label="删除"
color="red"
flat
dense
@click="del(props.row)"
></q-btn>
</template>
<template v-else-if="c.slot === 'slot'">
<slot :name="'body-cell-' + c.field" v-bind="scope">
</slot>
</template>
<template v-else>
<el-date-picker
v-model="props.row[c.field]"
v-if="c.type=='date'"
:type="c.typeDate? c.typeDate : 'date'"
placeholder="请选择"
:format="c.format || 'YYYY-MM-DD'"
:value-format="c.format || 'YYYY-MM-DD'"
size="small"
style="width:100%"
:disabled="disabled"
/>
<el-select
v-model="props.row[c.field]"
placeholder="请选择"
v-else-if="c.type=='select'"
size="small"
style="width:100%"
:disabled="disabled"
:teleported="false"
>
<el-option
v-for="item in c.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<div v-else-if="c.type=='dict'">
<FormCell v-model="props.row[c.field]" hideLabel="true" :disabled="disabled" type="select" dict="message_type" emit-value map-options></FormCell>
</div>
<div v-else-if="c.type=='file'">
<div
:class="[disabled ? 'unActive' : 'active' ]"
v-show="!props.row[c.field] || props.row[c.field].length === 0"
@click="openUpLoad(props.row[c.field], props.rowIndex,disabled,c.field)"
>
上传
</div>
<div
v-show="shouldShowUpload(props.row[c.field])"
style="color: #4cbaff; cursor: pointer; font-size: 12px"
@click="openUpLoad(props.row[c.field], props.rowIndex,disabled,c.field)"
>
上传附件({{ getFieldValue(props.row[c.field])?.length }})
</div>
</div>
<el-input
v-else-if="c.type=='input'"
v-model="props.row[c.field]"
:type="c.typeNumber?'number':''"
placeholder="请输入"
size="small"
:disabled="disabled"
></el-input>
<span v-else>
{{props.row[c.field]}}
</span>
</template>
</q-td>
</template>
</q-table>
<el-dialog
v-model="dialogTableVisible"
title="上传附件"
align-center
width="60%"
>
<FormCell
class="user-form-cell myUpdateProcessUpload"
label="附件上传"
v-model="uploadList"
type="file"
:hideLabel="true"
style="font-size: 12px"
></FormCell>
<el-table :data="gridData">
<el-table-column type="index" width="20" />
<el-table-column
property="name"
label="附件文件名"
min-width="40%"
align="center"
/>
<el-table-column
property="createName"
label="上传人"
min-width="15%"
align="center"
/>
<el-table-column
property="createTime"
label="上传时间"
min-width="15%"
align="center"
/>
<el-table-column
fixed="right"
label="操作"
min-width="20%"
align="center"
>
<template #default="scope">
<el-button
type="primary"
size="small"
@click.prevent="down(scope.row)"
>
下载
</el-button>
<el-button
type="primary"
size="small"
@click.prevent="downpre(scope.row)"
>
预览
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<q-btn
size="small"
style="margin-right: 10px"
@click="dialogTableVisible = false"
>取消</q-btn
>
<q-btn size="small" color="primary" @click="submitUpload"> 确定 </q-btn>
</div>
</template>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
.my-sticky-header-table11 {
/* height or max-height is important */
:deep(.el-input--small .el-input__inner){
height: 40px;
line-height: 40px;
}
max-height: 100%;
:deep(.q-table) {
thead tr th {
position: sticky;
z-index: 1;
background: rgb(240, 247, 254);
font-weight: 700;
}
thead tr:first-child th {
top: 0;
}
}
/* this is when the loading indicator appears */
&.q-table--loading thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
}
:deep(.q-table__card){ box-shadow: none;
//border: ;
}
.active{
color: #4cbaff;
cursor: pointer;
font-size: 12px;
}
.unActive{
color: #cee5f4;
font-size: 12px;
}
:deep(.el-dialog) {
z-index: 999999 !important;
transform: translateZ(0)// 根据需要调整数值
}
</style>
综上代码中rows是添加数据,columns表头,这样我就能做个双向绑定,让其在提交时候获取数据
其他tab切换那就更简单手写就好啦
数据处理
` 提示:思想中数据处理无非就是调用接口获取数据那,之后获取数据在页面中传值所以我在新建模块文件夹中我会新建三个文件
第一个api,js
这个文件夹我全部用来实现接口加载.所有的接口调用封装在这个文件中,而且我会用一个在这里插入代码片
class ProductionProject {
constructor() {
this.processOptions =ref('1');
}
//获取详情
getDetail (id) {
api.sendAxios('/produce_project/{id}', {id:id},{method: 'get'}).then(res=>{
})
}
//获取立项跟投决的详情
getLTDetail (type) {
api.sendAxios('/produce_project_stage/page', {stageType:type,produceProjectId:this.produceProjectId.value},{method: 'get'}).then(res=>{
})
}
//列表
getProjectProcessDetail () {
return api.sendAxios('/produce_project_report/page', {produceProjectId:this.produceProjectId.value,pageNo:1,pageSize:100},).then(res=>{
})
}
}
export const productionProject = new ProductionProject();
我会封装成一个class 把这个class暴露出去,这样我在所有页面中我都能使用到这个class中的数据,这样就保持了页面数据统一与完整性
技术细节
在这其中,你会遇到数据加载问题,页面渲染完数据加载问题等,无非做个监听就好,很通透的写法
小结
开发道路分叉太多太多了,找到自己的写法,让自己读起来容易,感觉花里胡哨的写法很绚丽但有时候把自己绕进去最致命。