reactive native vue3
时间: 2023-08-19 21:16:04 浏览: 166
React Native 和 Vue 3 都是流行的前端开发框架。它们都可以用来开发跨平台的移动应用程序,但它们有一些不同之处。
React Native 是基于 React 的框架,它允许开发者使用 JavaScript 和 React 的语法来构建原生移动应用程序。React Native 提供了一组丰富的组件和 API,可以直接调用原生平台的功能和特性。它的优点是开发效率高,可以快速构建跨平台应用,并且可以共享大部分代码逻辑。但是,React Native 在性能和原生体验方面可能会受到一些限制。
Vue 3 是一个用于构建用户界面的渐进式框架,它也可以用于开发移动应用程序。Vue 3 提供了一组易于使用的 API 和指令,可以将 HTML 模板与 JavaScript 代码进行绑定。Vue 3 的优点是学习曲线相对较低,易于上手,并且具有很好的性能和响应能力。Vue 3 还提供了一些用于构建移动应用程序的工具和插件,如 Vue Router 和 Vuex。
选择使用 React Native 还是 Vue 3 取决于您的具体需求和个人偏好。如果您已经熟悉 React 和其生态系统,并且希望快速构建跨平台移动应用程序,那么 React Native 可能是一个不错的选择。如果您对 Vue 3 更感兴趣,或者您已经熟悉 Vue,并且希望使用一种更灵活和可扩展的框架来构建移动应用程序,那么 Vue 3 是一个不错的选择。
相关问题
将项目用料明细,统计两个vue页面使用Composition API重构不要用vue3
将 `ProjectMaterialStatistics.vue` 和 `ProjectMaterialDetails.vue` 使用 Composition API 进行重构,但不使用 Vue 3,可以通过以下步骤实现:
### ProjectMaterialStatistics.vue
```vue
<template>
<a-spin :spinning="spinning" tip="报表同步中,请稍等">
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col>
<my-fast-date-picker
:radioList="[{
value: 2,
text: '月'
}, {
value: 3,
text: '年'
}]"
:radioVal="2"
:currName="'近半年'"
:showRadioGroup="true"
:fastTime="fastTime"
@change="change"
>
<template #text>时间:</template>
</my-fast-date-picker>
</a-col>
<template v-if="toggleSearchStatus">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="项目编号:">
<a-input placeholder="请输入项目编号" allowClear v-model="queryParam.projectCode"></a-input>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="项目名称">
<a-select
allowClear
show-search
v-model="queryParam.projectName_Code"
placeholder="请输入项目名称"
style="width: 100%"
:show-arrow="false"
:filter-option="false"
:not-found-content="null"
@search="projectCodeSearch"
@change="projectCodeChange"
>
<a-select-option v-for="d in projectNameList" :key="d.id">{{ d.text }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="物资">
<a-input placeholder="请输入物资编号/名称" allowClear v-model="queryParam.keyWord"></a-input>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="厂商">
<j-search-select-tag
placeholder="请选择厂商"
v-model="queryParam.producerId"
dict="biz_product_vendor,abbreviation,id,del_flag = 0 and status = 1"
/>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="规格型号">
<a-input placeholder="请输入规格型号" allowClear v-model="queryParam.specification"></a-input>
</a-form-item>
</a-col>
</template>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left; overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
<a @click="handleToggleSearch" style="margin-left: 8px">{{ toggleSearchStatus ? '收起' : '展开' }}
<a-icon :type="toggleSearchStatus ? 'up' : 'down'" />
</a>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator">
<div>
<a-button type="primary" icon="download" @click="handleExportXlsx()">导出</a-button>
</div>
</div>
<!-- table区域-begin -->
<div>
<a-table
ref="table"
size="middle"
:scroll="{ x: true }"
bordered
rowKey="uniqueId"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
class="j-table-force-nowrap"
@change="handleTableChange"
>
<span slot="receivingFreezeAmount">
领用冻结
<a-tooltip>
<template slot="title">项目领用申请审核通过后,待出库的数量。</template>
<a-icon type="info-circle" />
</a-tooltip>
</span>
<span slot="receivingFreezeAmount_title">
预算余量
<a-tooltip>
<template slot="title">预算余量=预算总数-领用冻结-领用总数+领用归还</template>
<a-icon type="info-circle" />
</a-tooltip>
</span>
<span slot="requisitionAmount_title">
领用总数
<a-tooltip>
<template slot="title">项目盘盈更新领用余料时,会自动产生领用增补单(不受预算限制),可能导致领用总数超过预算总数。</template>
<a-icon type="info-circle" />
</a-tooltip>
</span>
<span slot="budgetTotalAmount" slot-scope="text, record">
<a-tooltip>
<template slot="title">
<div class="tipItem">
<div>预算编号</div>
<div>预算数</div>
</div>
<div v-for="(value, key) in record.budgetDetail" class="tipItem" v-show="key !== '小计'">
<div>{{ key }}</div>
<div>{{ value }}</div>
</div>
<div class="tipItem">
<div>小记</div>
<div>{{ text }}</div>
</div>
</template>
<span style="color: blue">{{ text }}</span>
</a-tooltip>
</span>
<span slot="budgetSurplusAmount" slot-scope="text, record">
<span :style="{ color: record.budgetSurplusAmount <= projectBudgetMarginWarning ? 'red' : 'black' }">
{{ text }}
</span>
</span>
<span slot="inventoryAmount" slot-scope="text, record">
<span :style="{ color: record.inventoryAmount <= record.budgetSurplusAmount ? 'red' : 'black' }">
{{ text }}
</span>
</span>
</a-table>
</div>
</a-card>
</a-spin>
</template>
<script>
import { reactive, toRefs, onMounted, computed } from '@vue/composition-api';
import { getAction, postAction } from '@/api/manage';
import MyFastDatePicker from '@/components/date/MyFastDatePicker';
export default {
name: 'ProjectMaterialStatistics',
components: {
MyFastDatePicker
},
setup() {
const state = reactive({
projectNameList: [],
projectName_Code: '',
projectBudgetMarginWarning: 0,
expandedRowKeys: [],
workorderProjectList: [],
description: '营业报表管理页面',
fastTime: ['本月', '上月', '近半年'],
noCreate: true,
hasUpdateTime: true,
configOrderSubTypeList: [],
configOrderSubTypeTemp: undefined,
allDepartList: [],
hallCodeDataList: [],
spinning: false,
checkFlag: true,
updateTime: '',
url: {
list: '/web/projectUseMaterial/list',
exportXlsxUrl: '/web/projectUseMaterial/export',
exportPdfUrl: '/web/bizBusinessRecord/exportpdf',
exportDetailUrl: '/web/bizBusinessRecord/exportDetailExcel'
},
keyList: ['saleNum', 'saleName', 'terminalTypeName', 'userTypeName', 'configOrderMainTypeName', 'configOrderSubTypeName'],
ipagination: {
current: 1,
pageSize: 20,
pageSizeOptions: ['20', '50', '80'],
showTotal: (total, range) => `${range[0]}-${range[1]} 共${total}条`,
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
columns: [
{ title: '项目编号', align: 'center', dataIndex: 'projectCode', customRender: (text, row, index) => renderMergedCells(text, row, index) },
{ title: '项目名称', align: 'center', dataIndex: 'projectName', customRender: (text, row, index) => renderMergedCells(text, row, index) },
{ title: '物资编号', align: 'center', dataIndex: 'materialCode' },
{ title: '物资名称', align: 'center', dataIndex: 'materialName' },
{ title: '厂商', align: 'center', dataIndex: 'producerId_dictText' },
{ title: '规格型号', align: 'center', dataIndex: 'specification' },
{ title: '单位', align: 'center', dataIndex: 'unit' },
{ title: '预算总数', align: 'center', dataIndex: 'budgetTotalAmount', scopedSlots: { customRender: 'budgetTotalAmount' } },
{ align: 'center', slots: { title: 'receivingFreezeAmount' }, dataIndex: 'receivingFreezeAmount' },
{ align: 'center', slots: { title: 'requisitionAmount_title' }, dataIndex: 'receivingTotalAmount' },
{ title: '领用余料', align: 'center', dataIndex: 'receivingSurplusAmount' },
{ title: '领料使用', align: 'center', dataIndex: 'receivingUseAmount' },
{ align: 'center', dataIndex: 'budgetSurplusAmount', slots: { title: 'receivingFreezeAmount_title' }, scopedSlots: { customRender: 'budgetSurplusAmount' } },
{ title: '库存可用数', align: 'center', dataIndex: 'inventoryAmount', scopedSlots: { customRender: 'inventoryAmount' } }
],
queryParam: {
projectCode: '',
keyWord: '',
producerId: '',
specification: '',
projectName_Code: '',
projectName: ''
},
toggleSearchStatus: false,
dataSource: [],
loading: false
});
const renderMergedCells = (value, row, index) => {
const obj = { children: value, attrs: {} };
if (index === 0 || row.projectName !== state.dataSource[index - 1].projectName) {
let rowSpan = 1;
for (let i = index + 1; i < state.dataSource.length; i++) {
if (state.dataSource[i].projectName === row.projectName) {
rowSpan++;
} else {
break;
}
}
obj.attrs.rowSpan = rowSpan;
} else {
obj.attrs.rowSpan = 0;
}
return obj;
};
const projectCodeSearch = (value) => {
getAction('/web/projectRecord/searchMainProject', { order: 'desc', pageNo: 1, pageSize: 100, keyword: value }).then(res => {
state.projectNameList = res.result.map(item => ({ id: item.id, value: item.projectCode, text: item.projectName }));
});
};
const projectCodeChange = (value) => {
state.queryParam.projectName_Code = value;
const obj = state.projectNameList.filter(item => item.id === value);
if (obj.length > 0) {
state.exportParams.projectName = obj[0].text;
state.queryParam.projectName = obj[0].text;
} else {
state.exportParams.projectName = '';
state.queryParam.projectName = '';
}
};
const change = (val1, val2, val3) => {
state.exportParams.dateTpye = val3 === 2 ? 1 : 2;
state.queryParam.beginDate = val1;
state.queryParam.endDate = val2;
state.queryParam.hiddenZeroTotalAmountFlag = state.checkFlag ? 1 : 0;
};
const searchQuery = () => {
state.loadData(1);
};
const searchReset = () => {
state.queryParam.projectCode = '';
state.queryParam.keyWord = '';
state.queryParam.producerId = '';
state.queryParam.specification = '';
state.queryParam.projectName_Code = '';
state.queryParam.projectName = '';
state.loadData(1);
};
const handleToggleSearch = () => {
state.toggleSearchStatus = !state.toggleSearchStatus;
};
const handleExportXlsx = () => {
// 实现导出功能
};
const loadData = (pageNo) => {
state.loading = true;
getAction(state.url.list, { ...state.queryParam, pageNo, pageSize: state.ipagination.pageSize }).then(res => {
state.dataSource = res.result.records;
state.ipagination.total = res.result.total;
state.loading = false;
});
};
onMounted(() => {
state.loadData(1);
postAction('/web/sysCompany/queryLoginCompany').then(res => {
state.projectBudgetMarginWarning = res.result.projectBudgetMarginWarning || 0;
});
});
return {
...toRefs(state),
renderMergedCells,
projectCodeSearch,
projectCodeChange,
change,
searchQuery,
searchReset,
handleToggleSearch,
handleExportXlsx,
loadData
};
}
};
</script>
<style scoped lang="less">
@import '~@assets/less/common.less';
.tipItem {
display: flex;
justify-content: space-between;
border-bottom: 1px solid white;
padding: 2px;
div {
margin: 2px 5px;
}
}
.table-operator {
display: flex;
justify-content: space-between;
}
.ant-alert {
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
使用elment-plus为vuecli搭建的vue3项目封装一个带分页功能的下拉框
好的,下面是封装带分页功能的下拉框的步骤:
1. 安装 element-plus
在命令行中执行以下命令:
```
npm i element-plus -S
```
2. 创建分页组件
在 `components` 目录下创建一个名为 `Pagination.vue` 的分页组件,代码如下:
```vue
<template>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageSize"
:total="total">
</el-pagination>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
currentPage: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 10
},
total: {
type: Number,
default: 0
}
},
methods: {
handleSizeChange(val: number) {
this.$emit('update:pageSize', val);
},
handleCurrentChange(val: number) {
this.$emit('update:currentPage', val);
}
}
});
</script>
```
这里使用了 Element Plus 组件库提供的分页组件 `el-pagination`,同时通过 `props` 和 `$emit` 实现了父子组件之间的数据传递。
3. 创建下拉框组件
在 `components` 目录下创建一个名为 `DropdownPagination.vue` 的下拉框组件,代码如下:
```vue
<template>
<el-dropdown v-model="visible" @visible-change="handleVisibleChange">
<el-input v-model="inputValue" placeholder="请输入内容" @input="handleInput" @keyup.enter.native="handleInput"></el-input>
<el-dropdown-menu>
<el-dropdown-item v-for="item in options" :key="item.value" @click="handleItemClick(item)">
{{ item.label }}
</el-dropdown-item>
<el-dropdown-item v-if="total > pageSize" divided>
<pagination :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total"></pagination>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, watch } from 'vue';
import Pagination from './Pagination.vue';
export default defineComponent({
components: { Pagination },
props: {
options: {
type: Array,
default: () => []
},
total: {
type: Number,
default: 0
},
pageSize: {
type: Number,
default: 10
}
},
setup(props) {
const state = reactive({
visible: false,
inputValue: '',
currentPage: 1
});
const handleVisibleChange = (val: boolean) => {
if (!val) {
state.inputValue = '';
}
state.visible = val;
};
const handleInput = () => {
state.currentPage = 1;
state.visible = true;
};
const handleItemClick = (item: any) => {
state.inputValue = item.label;
state.visible = false;
props.$emit('select', item);
};
watch(
() => state.currentPage,
(val: number) => {
props.$emit('update:currentPage', val);
}
);
return {
...toRefs(state),
handleVisibleChange,
handleInput,
handleItemClick
};
}
});
</script>
```
这里使用了 Element Plus 组件库提供的下拉框组件 `el-dropdown` 和文本框组件 `el-input`,同时通过 `props` 和 `$emit` 实现了父子组件之间的数据传递。同时,我们在下拉框中加入了分页组件 `Pagination`,当列表项超过一页时,就会显示分页组件。
4. 在父组件中使用
在父组件中使用 `DropdownPagination` 组件,并传入相应的参数,代码如下:
```vue
<template>
<div class="container">
<dropdown-pagination
:options="options"
:total="total"
:page-size.sync="pageSize"
:current-page.sync="currentPage"
@select="handleSelect"
@update:currentPage="handleCurrentPageChange">
</dropdown-pagination>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive } from 'vue';
import DropdownPagination from './components/DropdownPagination.vue';
export default defineComponent({
components: { DropdownPagination },
setup() {
const state = reactive({
options: [
{ value: '1', label: '选项1' },
{ value: '2', label: '选项2' },
{ value: '3', label: '选项3' },
{ value: '4', label: '选项4' },
{ value: '5', label: '选项5' },
{ value: '6', label: '选项6' },
{ value: '7', label: '选项7' },
{ value: '8', label: '选项8' },
{ value: '9', label: '选项9' },
{ value: '10', label: '选项10' }
],
total: 100,
pageSize: 10,
currentPage: 1
});
const handleSelect = (item: any) => {
console.log(item);
};
const handleCurrentPageChange = (val: number) => {
console.log(val);
};
return {
...state,
handleSelect,
handleCurrentPageChange
};
}
});
</script>
```
在 `setup` 函数中,我们定义了一个响应式对象 `state`,并在模板中使用了 `DropdownPagination` 组件。同时,我们监听了子组件的 `select` 和 `update:currentPage` 事件,并在回调函数中输出相应的信息。
至此,一个带分页功能的下拉框组件就完成了。
阅读全文