当前位置: 首页 > news >正文

免费网站代码大全网站免费正能量小说

免费网站代码大全,网站免费正能量小说,怎么样开网站,网站ip和pv零、实现原理与应用案例设计 1、原理 基础实例 Demo 可以参照以下这篇博文#xff0c; 基于.Net CEF 实现 Vue 等前端技术栈构建 Windows 窗体应用-CSDN博客文章浏览阅读291次。基于 .Net CEF 库#xff0c;能够使用 Vue 等前端技术栈构建 Windows 窗体应用https://blog.c…零、实现原理与应用案例设计 1、原理 基础实例 Demo 可以参照以下这篇博文 基于.Net CEF 实现 Vue 等前端技术栈构建 Windows 窗体应用-CSDN博客文章浏览阅读291次。基于 .Net CEF 库能够使用 Vue 等前端技术栈构建 Windows 窗体应用https://blog.csdn.net/weixin_47560078/article/details/133974513原理非常简单基于 .Net CEF 实现用到的库为 CefSharp。 2、优势 可以使用Vue/React等前端技术美化页面提升用户友好度可以调度操作系统资源例如打印机命令行文件前后端开发可以并行 3、劣势 损失部分性能占用系统资源更高调试需要前后端分开调试对开发人员要求高需要懂前后端技术栈非跨平台仅支持Window 4、应用案例 该桌面应用从数据库加载数据到页面表格用户可以根据需求修改表格数据保存到Excel打印PDF。 5、技术栈 Vite Vue3 TS  ElementUI(plus) .NET Framework 4.7.2开发环境为 Win10VS2019VS Code。  6、开发流程 整合 Vue Vite ElementUI把 JS 需要调用的 .Net 方法临时用 JS 方法代替页面开发完毕接着开发 .Net 方法业务处理逻辑导出 .Net 方法临时 JS 方法替换为真正的 .Net 方法最后发布测试 一、前端设计与实现 1、整合 Vue Vite ElementUI # 创建 vite vue cnpm create vitelatest # element-plus 国内镜像 https://element-plus.gitee.io/zh-CN/ # 安装 element-plus cnpm install element-plus --save 按需引入 element plus # 安装导入插件 cnpm install -D unplugin-vue-components unplugin-auto-import 在 main.ts 引入 element-plus 和样式 // myapp\src\main.ts import { createApp } from vue //import ./style.css import App from ./App.vue import ElementPlus from element-plus import element-plus/dist/index.csscreateApp(App).use(ElementPlus).mount(#app) 配置 vite // myapp\vite.config.ts import { defineConfig } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers// https://vitejs.dev/config/ export default defineConfig({plugins: [vue(),AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),], })新建一个组件页面在 App.vue 中引用 // myapp\src\components\DataViewer.vue templateel-table :datatableData stylewidth: 100%el-table-column fixed propdate labelDate width150 /el-table-column propname labelName width120 /el-table-column propstate labelState width120 /el-table-column propcity labelCity width120 /el-table-column propaddress labelAddress width600 /el-table-column propzip labelZip width120 /el-table-column fixedright labelOperations width120template #defaultel-button link typeprimary sizesmall clickhandleClickDetail/el-buttonel-button link typeprimary sizesmallEdit/el-button/template/el-table-column/el-table /templatescript langts setup const handleClick () {console.log(click) }const tableData [{date: 2016-05-03,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Home,},{date: 2016-05-02,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Office,},{date: 2016-05-04,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Home,},{date: 2016-05-01,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Office,}, ] /script运行 npm run dev 官方 Table 组件示例运行效果如下 2、使用图标 Icon补充 cnpm install element-plus/icons-vue 3、api 封装 封装 DataUtil 用于模拟调用 .Net 方法获取数据 // myapp\src\api\DataUtil.tsexport const getData async (): Promiseany {// await CefSharp.BindObjectAsync(dataUtil)// return dataUtil.getData()return new Promise((resolve, _) {resolve([{date: 2016-05-03,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Home,},{date: 2016-05-02,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Office,},{date: 2016-05-04,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Home,},{date: 2016-05-01,name: Tom,state: California,city: Los Angeles,address: No. 189, Grove St, Los Angeles,zip: CA 90036,tag: Office,},])}) } 4、获取数据实现 页面 DataViewer.vue 加载数据调用 api 的 getData 异步方法在页面挂载时请求数据 // myapp\src\components\DataViewer.vue templateel-table v-loadingloading :datatableData stylewidth: 100%el-table-column fixed propdate labelDate width150 /el-table-column propname labelName width120 /el-table-column propstate labelState width120 /el-table-column propcity labelCity width120 /el-table-column propaddress labelAddress width600 /el-table-column propzip labelZip width120 /el-table-column fixedright labelOperations width120template #defaultel-button link typeprimary sizesmall clickhandleClickEdit/el-buttonel-button link typeprimary sizesmallDelete/el-button/template/el-table-column/el-table /templatescript langts setup import { ref, onMounted, reactive } from vue import { getData } from ../api/DataUtil// 表格数据加载标志 const loading ref(true)const handleClick () {console.log(click) }const tableData reactive([])onMounted(() {// 获取数据后将加载标志位位置 false并且绑定到表格getData().then((res: any) {loading.value falseconsole.log( getData , res)Object.assign(tableData, res)})})/script本地运行效果如下 5、更新数据实现 页面 DataViewer.vue 选中表格的某行数据后点击”Edit“进行编辑编辑后确认更新回显到页面 // myapp\src\components\DataViewer.vue template!-- 获取数据后展示 --el-table v-loadingloading :datatableData stylewidth: 100%el-table-column fixed typeindex :indexindexMethod /el-table-column propdate labelDate width150 /el-table-column propname labelName width120 /el-table-column propstate labelState width120 /el-table-column propcity labelCity width120 /el-table-column propaddress labelAddress width600 /el-table-column propzip labelZip width120 /el-table-column fixedright labelOperations width120template #defaultscopeel-button link typeprimary sizesmall clickhandleEdit(scope)Edit/el-buttonel-button link typeprimary sizesmallDelete/el-button/template/el-table-column/el-table!-- 更新数据时对话框 --el-dialog v-modeldialogFormVisible titleShipping addressel-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogFormVisible falseCancel/el-buttonel-button typeprimary clickhandleUpdate()Confirm/el-button/span/template/el-dialog /templatescript langts setup import { ref, onMounted, reactive } from vue import { getData } from ../api/DataUtil// 表格数据加载标志 const loading ref(true) const tableData reactive([])// 更新数据对话框 const dialogFormVisible ref(false) const formLabelWidth 140px// 当前选中行数据 const currentRow reactive({date: please input date,name: please input name,state: please input state,city: please input city,address: please input address,zip: please input zip,tag: please input tag, })const currentRowIndex ref(1)// 更新事件 const handleUpdate () {//console.log( handleUpdate , currentRow, currentRowIndex.value)Object.assign(tableData[currentRowIndex.value], currentRow)dialogFormVisible.value false }// 索引规则 const indexMethod (index: number) {return index 1 }// Edit 事件 const handleEdit (scope: any) {//console.log(edit,scope.$index,scope.row)Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogFormVisible.value true }// 挂载方法 onMounted(() {// 获取数据后将加载标志位位置 false并且绑定到表格getData().then((res: any) {//console.log( getData , res)loading.value falseObject.assign(tableData, res)})})/script style .el-button--text {margin-right: 15px; }.el-select {width: 300px; }.el-input {width: 300px; }.dialog-footer button:first-child {margin-right: 10px; } /style 本地运行效果如下 6、删除数据实现 页面 DataViewer.vue 选中表格的某行数据后点击”Delete“进行删除弹窗确认将删除结果回显到页面 // myapp\src\components\DataViewer.vue template!-- 获取数据后展示 --el-table v-loadingloading :datatableData stylewidth: 100%el-table-column fixed typeindex :indexindexMethod /el-table-column propdate labelDate width150 /el-table-column propname labelName width120 /el-table-column propstate labelState width120 /el-table-column propcity labelCity width120 /el-table-column propaddress labelAddress width600 /el-table-column propzip labelZip width120 /el-table-column fixedright labelOperations width120template #defaultscopeel-button link typeprimary sizesmall clickhandleEdit(scope)Edit/el-buttonel-button link typeprimary sizesmall clickhandleDelete(scope)Delete/el-button/template/el-table-column/el-table!-- 更新数据时对话框 --el-dialog v-modeldialogUpdateFormVisible titleUpdate Shipping address ?el-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogUpdateFormVisible falseCancel/el-buttonel-button typeprimary clickdoUpdate()Confirm/el-button/span/template/el-dialog!-- 删除数据时对话框 --el-dialog v-modeldialogDeleteFormVisible titleDelete Shipping address ?el-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input disabled v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input disabled v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input disabled v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input disabled v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input disabled v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input disabled v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input disabled v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogDeleteFormVisible falseCancel/el-buttonel-button typeprimary clickdoDelete()Confirm/el-button/span/template/el-dialog /templatescript langts setup import { ref, onMounted, reactive } from vue import { getData } from ../api/DataUtil import { ElMessage } from element-plus// 表格数据加载标志 const loading ref(true) const tableData reactive([])// 更新数据对话框 const dialogUpdateFormVisible ref(false) const dialogDeleteFormVisible ref(false) const formLabelWidth 140px// 当前选中行数据 const currentRow reactive({date: please input date,name: please input name,state: please input state,city: please input city,address: please input address,zip: please input zip,tag: please input tag, })const currentRowIndex ref(1)// 更新事件 const doUpdate () {//console.log( doUpdate , currentRow, currentRowIndex.value)Object.assign(tableData[currentRowIndex.value], currentRow)dialogUpdateFormVisible.value false }// 删除事件 const doDelete () {// console.log(doDelete , currentRowIndex.value)tableData.splice(currentRowIndex.value, 1)dialogDeleteFormVisible.value falseElMessage({message: Delete success.,type: success,}) }// 索引规则 const indexMethod (index: number) {return index 1 } // Delete 事件 const handleDelete (scope: any) {Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogDeleteFormVisible.value true }// Edit 事件 const handleEdit (scope: any) {//console.log(edit,scope.$index,scope.row)Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogUpdateFormVisible.value true }// 挂载方法 onMounted(() {// 获取数据后将加载标志位位置 false并且绑定到表格getData().then((res: any) {//console.log( getData , res)loading.value falseObject.assign(tableData, res)})})/script style .el-button--text {margin-right: 15px; }.el-select {width: 300px; }.el-input {width: 300px; }.dialog-footer button:first-child {margin-right: 10px; } /style 本地运行效果如下 7、保存/打印数据实现 点击页面的“Save”按钮弹出对话框选择文件保存的路径将数据保存为 Excel 文件点击页面的“Print”按钮将数据转化为PDF格式打印两个功能都需要调用 .Net 方法实现 // myapp\src\api\ExcelUtil.ts export const saveAsExcel async (data: any): Promiseany {// await CefSharp.BindObjectAsync(excelUtil)// return excelUtil.saveAsExcel(data)return new Promise((resolve, _) {resolve({code: 1,msg: ok,isSuccess: true})}) } // myapp\src\api\PrinterUtil.ts export const printPdf async (data: any): Promiseany {// await CefSharp.BindObjectAsync(printerlUtil)// return printerlUtil.printPdf(data)return new Promise((resolve, _) {resolve({code: 1,msg: ok,isSuccess: true})}) } // myapp\src\components\DataViewer.vue templatediv classcommon-layoutel-containerel-main!-- 获取数据后展示 --el-table v-loadingloading :datatableData height485 stylewidth: 100%el-table-column fixed typeindex :indexindexMethod /el-table-column propdate labelDate width150 /el-table-column propname labelName width120 /el-table-column propstate labelState width120 /el-table-column propcity labelCity width120 /el-table-column propaddress labelAddress width600 /el-table-column propzip labelZip width120 /el-table-column fixedright labelOperations width120template #defaultscopeel-button link typeprimary sizesmall clickhandleEdit(scope)Edit/el-buttonel-button link typeprimary sizesmall clickhandleDelete(scope)Delete/el-button/template/el-table-column/el-table!-- 更新数据时对话框 --el-dialog v-modeldialogUpdateFormVisible titleUpdate Shipping address ?el-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogUpdateFormVisible falseCancel/el-buttonel-button typeprimary clickdoUpdate()Confirm/el-button/span/template/el-dialog!-- 删除数据时对话框 --el-dialog v-modeldialogDeleteFormVisible titleDelete Shipping address ?el-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input disabled v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input disabled v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input disabled v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input disabled v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input disabled v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input disabled v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input disabled v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogDeleteFormVisible falseCancel/el-buttonel-button typeprimary clickdoDelete()Confirm/el-button/span/template/el-dialog/el-mainel-headerel-row classrow-bg justifyendel-col :span2el-button clickhandleSaveData typeprimarySaveel-icon classel-icon--rightDocument //el-icon/el-button/el-colel-col :span2el-button clickhandlePrintData typeprimaryPrintel-icon classel-icon--rightPrinter //el-icon/el-button/el-col/el-row/el-header/el-container/div /templatescript langts setup import { ref, onMounted, reactive } from vue import { getData } from ../api/DataUtil import { saveAsExcel } from ../api/ExcelUtil import { printPdf } from ../api/PrinterUtil import { ElMessage } from element-plus import { Document, Printer } from element-plus/icons-vue// 表格数据加载标志 const loading ref(true) const tableData reactive([])// 更新数据对话框 const dialogUpdateFormVisible ref(false) const dialogDeleteFormVisible ref(false) const formLabelWidth 140px// 当前选中行数据 const currentRow reactive({date: please input date,name: please input name,state: please input state,city: please input city,address: please input address,zip: please input zip,tag: please input tag, })const currentRowIndex ref(1)// 更新事件 const doUpdate () {//console.log( doUpdate , currentRow, currentRowIndex.value)Object.assign(tableData[currentRowIndex.value], currentRow)dialogUpdateFormVisible.value falseElMessage({message: Update success.,type: success,}) }// 删除事件 const doDelete () {// console.log(doDelete , currentRowIndex.value)tableData.splice(currentRowIndex.value, 1)dialogDeleteFormVisible.value falseElMessage({message: Delete success.,type: success,}) }// 索引规则 const indexMethod (index: number) {return index 1 } // Delete 事件 const handleDelete (scope: any) {Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogDeleteFormVisible.value true }// Edit 事件 const handleEdit (scope: any) {//console.log(edit,scope.$index,scope.row)Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogUpdateFormVisible.value true }// 保存事件 const handleSaveData () {saveAsExcel(tableData).then((res: any) {if (res.isSuccess) {ElMessage({message: Save success.,type: success,})} else {ElMessage({message: res.msg,type: error,})}}) }// 打印事件 const handlePrintData () {printPdf(tableData).then((res: any) {if (res.isSuccess) {ElMessage({message: Save success.,type: success,})} else {ElMessage({message: res.msg,type: error,})}}) }// 挂载方法 onMounted(() {// 获取数据后将加载标志位位置 false并且绑定到表格getData().then((res: any) {//console.log( getData , res)loading.value falseObject.assign(tableData, res)})})/script style .el-button--text {margin-right: 15px; }.el-select {width: 300px; }.el-input {width: 300px; }.dialog-footer button:first-child {margin-right: 10px; }.el-row {margin-bottom: 20px; }.el-row:last-child {margin-bottom: 0; }.el-col {border-radius: 4px; } /style 二、后端设计与实现 1、新建 WimForm 项目 2、安装 CefSharp 程序包 CefSharp.WinForms 3、窗体无边框设置可选 3.1、FormBorderStyle 属性置为 NONE可选 3.2、实现窗体事件可选 通过窗体 MouseDown、MouseMove、MouseUp 鼠标事件实现窗体移动 // DataToolForm.cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;namespace DataToolApp {public partial class DataToolForm : Form{/// summary/// 鼠标按下时的点/// /summaryprivate Point point;/// summary/// 拖动标识/// /summaryprivate bool isMoving false;public DataToolForm(){InitializeComponent();}/// summary/// 鼠标按下时启用拖动/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_MouseDown(object sender, MouseEventArgs e){point e.Location;isMoving true;}/// summary/// 鼠标移动计算移动的位置/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_MouseMove(object sender, MouseEventArgs e){if (e.Button MouseButtons.Left isMoving){Point pNew new Point(e.Location.X - point.X, e.Location.Y - point.Y);Location new Size(pNew);}}/// summary/// 鼠标停下/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_MouseUp(object sender, MouseEventArgs e){isMoving false;}} }3.3、窗体拖拽效果可选 4、窗体页面配置 4.1、在 UI 线程上异步执行 Action 新建文件夹添加类 ControlExtensions // DataToolApp\Controls\ControlExtensions.cs using System; using System.Windows.Forms;namespace DataToolApp.Controls {public static class ControlExtensions{/// summary/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread./// /summary/// param namecontrolthe control for which the update is required/param/// param nameactionaction to be performed on the control/parampublic static void InvokeOnUiThreadIfRequired(this Control control, Action action){//If you are planning on using a similar function in your own code then please be sure to//have a quick read over https://stackoverflow.com/questions/1874728/avoid-calling-invoke-when-the-control-is-disposed//No actionif (control.Disposing || control.IsDisposed || !control.IsHandleCreated){return;}if (control.InvokeRequired){control.BeginInvoke(action);}else{action.Invoke();}}} }// 异步调用示例在控件 outputLabel 中显示文本 output this.InvokeOnUiThreadIfRequired(() outputLabel.Text output); 4.2、全屏设置可选 在窗体构造方法中将 WindowState 置为最大分辨率 public DataToolForm(){InitializeComponent();Text title;// 这里将窗体设置为最大屏幕分辨率WindowState FormWindowState.Maximized;browser new ChromiumWebBrowser(www.baidu.com);this.Controls.Add(browser);} 5、弹窗选择文件夹 安装 Ookii 包这里的版本是 4.0.0实现弹窗选择文件夹 弹窗示例代码如下 var folderDialog new Ookii.Dialogs.WinForms.VistaFolderBrowserDialog {Description 选择文件夹 };if (folderDialog.ShowDialog() ! DialogResult.OK) {Debug.WriteLine(res); } 也可以使用原生方法 FolderBrowserDialog folderBrowserDialog new FolderBrowserDialog() {Description请选择文件夹,ShowNewFolderButton true, }; if(folderBrowserDialog.ShowDialog() DialogResult.OK) {string selectedFolderPath folderBrowserDialog.SelectedPath;MessageBox.Show(选择的文件夹路径为 selectedFolderPath); } 效果如下 使用同步委托逻辑上是先获取文件夹路径再保存文件 // DataToolApp\Dialogs\CustomerFolderBrowserDialog.cs using System.Windows.Forms;namespace DataToolApp.Dialogs {public class CustomerFolderBrowserDialog{/// summary/// 委托实现显示文件夹浏览器返回选中的文件夹路径/// /summary/// returns/returnspublic static string ShowFolderBrowserDialog(){FolderBrowserDialog folderBrowserDialog new FolderBrowserDialog(){Description 请选择文件夹,ShowNewFolderButton true,};if (folderBrowserDialog.ShowDialog() DialogResult.OK){return folderBrowserDialog.SelectedPath;}return ;}} }// 主窗体 DataToolForm.cs// 自定义委托public delegate string MyFolderBrowserDialog();/// summary/// 获取选中的文件夹路径/// /summarypublic Object GetSelectedFolderPath(){MyFolderBrowserDialog myFolderBrowserDialog CustomerFolderBrowserDialog.ShowFolderBrowserDialog;return this.Invoke(myFolderBrowserDialog);}6、ExcelUtil 工具类封装 安装 NPOI 包这里的版本是 2.6.2 封装 SaveAsExcel 方法 using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO;namespace DataToolApp.Utils {public class ExcelUtil{public Object SaveAsExcel(Object obj){// (IDictionaryString, Object) obj// System.Collections.Generic.ICollectionSystem.Collections.Generic.KeyValuePairstring, object obj// 结果DictionaryString, Object res new DictionaryString, Object(3);// 获取保存文件夹string selectedPath Program.dataToolForm.GetSelectedFolderPath().ToString();if (string.IsNullOrEmpty(selectedPath)){// 返回结果res.Add(code, 0);res.Add(msg, fail);res.Add(isSuccess, false);return res;}string filename Guid.NewGuid().ToString() .xls;// 创建 workbookIWorkbook workbook new HSSFWorkbook();// 添加一个 sheetISheet sheet1 workbook.CreateSheet(sheet1);// 写入 Excelbool isHeader true;Liststring header new Liststring();int rowCounter 0;ICollectionKeyValuePairstring, object entities (ICollectionKeyValuePairstring, object)obj;foreach (var entity in entities){IDictionaryString, Object entityInfo (IDictionaryString, object)entity.Value;// 写入表头if (isHeader){foreach (var key in entityInfo.Keys){header.Add(key);}// 第一行IRow firstRow sheet1.CreateRow(0);for (int j 0; j header.Count; j){firstRow.CreateCell(j).SetCellValue(header[j]);}isHeader false;}rowCounter;// 第 N 行IRow row sheet1.CreateRow(rowCounter);// 写入内容for (int k 0; k header.Count; k){row.CreateCell(k).SetCellValue(entityInfo[header[k]].ToString());}}// 写入文件using (FileStream file new FileStream(selectedPath \\ filename, FileMode.Create)){workbook.Write(file);}// 返回结果res.Add(code, 1);res.Add(msg, ok);res.Add(isSuccess, true);return res;}} }7、PrinterUitl 工具类封装 安装 Spire.XLS  包这里的版本是 13.10.1 安装 Spire.PDF 包收费这里的版本是 9.10.2 // PrinterlUtil.cs using iTextSharp.text; using iTextSharp.text.pdf; using System; using System.Collections.Generic; using System.IO;namespace DataToolApp.Utils {public class PrinterlUtil{/// summary/// 创建一个 PDF 文档/// /summary/// param namefilename/parampublic void CreateDocument(string filename){// 创建新的PDF文档Document document new Document(PageSize.A4);// 创建PDF写入器PdfWriter.GetInstance(document, new FileStream(filename, FileMode.Create));// 打开文档document.Open();// 创建一个PdfPTable对象设置表格的列数和列宽PdfPTable table new PdfPTable(3);table.SetWidths(new float[] { 1, 2, 3 });// 创建一个PdfPCell对象设置单元格的内容和样式PdfPCell cell new PdfPCell(new Phrase(Header));cell.Colspan 3;cell.HorizontalAlignment 1;table.AddCell(cell);table.AddCell(Col 1 Row 1);table.AddCell(Col 2 Row 1);table.AddCell(Col 3 Row 1);table.AddCell(Col 1 Row 2);table.AddCell(Col 2 Row 2);table.AddCell(Col 3 Row 2);//将表格添加到Document对象中document.Add(table);//关闭Document对象document.Close();}/// summary/// 打印 PDF 文档/// /summary/// param nameobj/param/// returns/returnspublic Object PrintPdf(Object obj){string tempfile E:\Test.pdf;string savefile E:\Test2.pdf;string printerName Microsoft Print to PDF;CreateDocument(tempfile);// 加载 PDF 文档Spire.Pdf.PdfDocument doc new Spire.Pdf.PdfDocument();doc.LoadFromFile(tempfile);// 选择 Microsoft Print to PDF 打印机doc.PrintSettings.PrinterName printerName;// 打印 PDF 文档doc.PrintSettings.PrintToFile(savefile);doc.Print();// 删除缓存文件File.Delete(tempfile);// 结果DictionaryString, Object res new DictionaryString, Object(3);res.Add(code, 1);res.Add(msg, ok);res.Add(isSuccess, true);return res;}} }8、DataUtil 工具类封装 // DataUtil.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace DataToolApp.Utils {public class DataUtil{// 模拟从数据库中返回数据public ListDataEntity getData(){int length 100;ListDataEntity dataEntities new ListDataEntity(length);for (int i 0; i length; i){DataEntity e new DataEntity(){date 2023-10-31,name Guid.NewGuid().ToString(),state Guid.NewGuid().ToString(),city Guid.NewGuid().ToString(),address Guid.NewGuid().ToString(),zip Guid.NewGuid().ToString(),tag Guid.NewGuid().ToString(),};dataEntities.Add(e);}return dataEntities;}public class DataEntity{public string date { get; set; }public string name { get; set; }public string state { get; set; }public string city { get; set; }public string address { get; set; }public string zip { get; set; }public string tag { get; set; } }} }9、导出 .Net 方法 注意以下两点 导出的 .Net 方法有限制不能导出 Form/Window/Control必须使用委托实现窗体异步事件否则会出现报错“在可以调用 OLE 之前必须将当前线程设置为单线程单元(STA)模式” // DataToolForm.cs using System; using System.Diagnostics; using System.Drawing; using System.Windows.Forms; using CefSharp; using CefSharp.JavascriptBinding; using CefSharp.WinForms; using DataToolApp.Controls; using DataToolApp.Dialogs; using DataToolApp.Utils;namespace DataToolApp {public partial class DataToolForm : Form{/// summary/// 鼠标按下时的点/// /summaryprivate Point point;/// summary/// 拖动标识/// /summaryprivate bool isMoving false;/// summary/// 打包编译类型/// /summary #if DEBUGprivate const string Build Debug; #elseprivate const string Build Release; #endif/// summary/// 应用标题/// /summaryprivate readonly string title DataToolApp ( Build );/// summary/// ChromiumWebBrowser/// /summaryprivate static ChromiumWebBrowser browser;// 委托public delegate string MyFolderBrowserDialog();/// summary/// 获取选中的文件夹路径/// /summarypublic Object GetSelectedFolderPath(){MyFolderBrowserDialog myFolderBrowserDialog CustomerFolderBrowserDialog.ShowFolderBrowserDialog;return this.Invoke(myFolderBrowserDialog);}public DataToolForm(){InitializeComponent();Text title;WindowState FormWindowState.Maximized;AddChromiumWebBrowser();}/// summary/// Create a new instance in code or add via the designer/// /summaryprivate void AddChromiumWebBrowser(){browser new ChromiumWebBrowser(http://datatool.test);browser.MenuHandler new CustomContextMenuHandler();// 导出 .Net 方法ExposeDotnetClass();this.Controls.Add(browser);}/// summary/// 鼠标按下时启用拖动/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_MouseDown(object sender, MouseEventArgs e){point e.Location;isMoving true;}/// summary/// 鼠标移动计算移动的位置/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_MouseMove(object sender, MouseEventArgs e){if (e.Button MouseButtons.Left isMoving){Point pNew new Point(e.Location.X - point.X, e.Location.Y - point.Y);Location new Size(pNew);}}/// summary/// 鼠标停下/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_MouseUp(object sender, MouseEventArgs e){isMoving false;}/// summary/// 导出类方法/// /summarypublic static void ExposeDotnetClass(){browser.JavascriptObjectRepository.ResolveObject (sender, e) {// 注册 ExcelUtil 实例DoRegisterDotNetFunc(e.ObjectRepository, e.ObjectName, excelUtil, new ExcelUtil());// 注册 PrinterlUtil 实例DoRegisterDotNetFunc(e.ObjectRepository, e.ObjectName, printerlUtil, new PrinterlUtil());// 注册其他实例 ...};browser.JavascriptObjectRepository.ObjectBoundInJavascript (sender, e) {var name e.ObjectName;Debug.WriteLine($Object {e.ObjectName} was bound successfully.);};}/// summary/// 注册 DoNet 实例/// /summary/// param namerepo IJavascriptObjectRepository /param/// param nameeventObjectName事件对象名/param/// param namefuncName方法名/param/// param nameobjectToBind需要绑定的DotNet对象/paramprivate static void DoRegisterDotNetFunc(IJavascriptObjectRepository repo, string eventObjectName, string funcName, object objectToBind){if (eventObjectName.Equals(funcName)){BindingOptions bindingOptions null;bindingOptions BindingOptions.DefaultBinder;repo.NameConverter null;repo.NameConverter new CamelCaseJavascriptNameConverter();repo.Register(funcName, objectToBind, isAsync: true, options: bindingOptions);}}/// summary/// 自定义右键菜单/// /summarypublic class CustomContextMenuHandler : IContextMenuHandler{/// summary/// 上下文菜单列表在这里加菜单/// /summary/// param namechromiumWebBrowser/param/// param namebrowser/param/// param nameframe/param/// param nameparameters/param/// param namemodel/paramvoid IContextMenuHandler.OnBeforeContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){if (model.Count 0){// 添加分隔符model.AddSeparator();}model.AddItem((CefMenuCommand)29501, Show DevTools);}/// summary/// 上下文菜单指令这里实现菜单要做的事情/// /summary/// param namechromiumWebBrowser/param/// param namebrowser/param/// param nameframe/param/// param nameparameters/param/// param namecommandId/param/// param nameeventFlags/param/// returns/returnsbool IContextMenuHandler.OnContextMenuCommand(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){if (commandId (CefMenuCommand)29501){browser.GetHost().ShowDevTools();return true;}return false;}void IContextMenuHandler.OnContextMenuDismissed(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame){var webBrowser (ChromiumWebBrowser)chromiumWebBrowser;Action setContextAction delegate (){webBrowser.ContextMenu null;};webBrowser.Invoke(setContextAction);}bool IContextMenuHandler.RunContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){// 必须返回 falsereturn false;}}/// summary/// 窗体加载事件/// /summary/// param namesender/param/// param namee/paramprivate void DataToolForm_Load(object sender, System.EventArgs e){browser.LoadUrl(http://datatool.test);}} }三、整合前后端 1、前端打包 Vite 配置 ESLint否则打包的时候会报错 # 安装 eslint cnpm i -D eslint babel/eslint-parser # 初始化配置 npx eslint --init # 安装依赖 cnpm i typescript-eslint/eslint-pluginlatest eslint-plugin-vuelatest typescript-eslint/parserlatest # 安装插件 cnpm i -D vite-plugin-eslint 配置 vite // vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers import eslintPlugin from vite-plugin-eslint// https://vitejs.dev/config/ export default defineConfig({plugins: [vue(),// ESLint 插件配置eslintPlugin({include: [src/**/*.js, src/**/*.vue, src/*.js, src/*.vue]}),AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),], })配置 eslint 规则 // .eslintrc.cjs module.exports {env: {browser: true,es2021: true,node: true},extends: [eslint:recommended,plugin:typescript-eslint/recommended,plugin:vue/vue3-essential],overrides: [{env: {node: true},files: [.eslintrc.{js,cjs}],parserOptions: {sourceType: script}}],parserOptions: {ecmaVersion: latest,parser: typescript-eslint/parser,sourceType: module},plugins: [typescript-eslint,vue],rules: {typescript-eslint/no-explicit-any: 1,no-console: 1,no-debugger: 1,no-undefined: 1,} }修改 vite 打包指令 // package.json {name: myapp,private: true,version: 0.0.0,type: module,scripts: {dev: vite,build: vite build, // 修改这里preview: vite preview},dependencies: {element-plus/icons-vue: ^2.1.0,typescript-eslint/eslint-plugin: latest,typescript-eslint/parser: latest,element-plus: ^2.4.1,eslint-plugin-vue: latest,vue: ^3.3.4},devDependencies: {babel/eslint-parser: ^7.22.15,vitejs/plugin-vue: ^4.2.3,eslint: ^8.52.0,typescript: ^5.0.2,unplugin-auto-import: ^0.16.7,unplugin-vue-components: ^0.25.2,vite: ^4.4.5,vite-plugin-eslint: ^1.8.1,vue-tsc: ^1.8.5} }打包 npm run build 2、引入静态资源 项目新建文件夹 Vite把前端打包好的资源引入进来并设为“嵌入的资源” 3、配置 CEF 程式主入口配置本地网页的访问域、缓存目录等信息 // Program.cs using CefSharp; using CefSharp.SchemeHandler; using CefSharp.WinForms; using System; using System.IO; using System.Windows.Forms;namespace DataToolApp {static class Program{/// summary/// 应用程序的主入口点。/// /summary[STAThread]static void Main(){InitCefSettings();Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new DataToolForm());}private static void InitCefSettings(){#if ANYCPUCefRuntime.SubscribeAnyCpuAssemblyResolver(); #endif// Pseudo code; you probably need more in your CefSettings also.var settings new CefSettings(){//By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist dataCachePath Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), CefSharp\\Cache)};//Example of setting a command line argument//Enables WebRTC// - CEF Doesnt currently support permissions on a per browser basis see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access// - CEF Doesnt currently support displaying a UI for media access permissions////NOTE: WebRTC Device Ids arent persisted as they are in Chrome see https://bitbucket.org/chromiumembedded/cef/issues/2064/persist-webrtc-deviceids-across-restartsettings.CefCommandLineArgs.Add(enable-media-stream);//https://peter.sh/experiments/chromium-command-line-switches/#use-fake-ui-for-media-streamsettings.CefCommandLineArgs.Add(use-fake-ui-for-media-stream);//For screen sharing add (see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access#comment-58677180)settings.CefCommandLineArgs.Add(enable-usermedia-screen-capturing);settings.RegisterScheme(new CefCustomScheme{SchemeName http,DomainName datatool.test,SchemeHandlerFactory new FolderSchemeHandlerFactory(rootFolder: ..\..\..\DataToolApp\Vite,hostName: datatool.test, //Optional param no hostname/domain checking if nulldefaultPage: index.html) //Optional param will default to index.html});//Perform dependency check to make sure all relevant resources are in our output directory.Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);}} }4、配置右键菜单 右键显示控制台菜单需要实现 IContextMenuHandler 接口 /// summary/// 自定义右键菜单/// /summarypublic class CustomContextMenuHandler : IContextMenuHandler{/// summary/// 上下文菜单列表在这里加菜单/// /summary/// param namechromiumWebBrowser/param/// param namebrowser/param/// param nameframe/param/// param nameparameters/param/// param namemodel/paramvoid IContextMenuHandler.OnBeforeContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){if (model.Count 0){// 添加分隔符model.AddSeparator();}model.AddItem((CefMenuCommand)29501, Show DevTools);}/// summary/// 上下文菜单指令这里实现菜单要做的事情/// /summary/// param namechromiumWebBrowser/param/// param namebrowser/param/// param nameframe/param/// param nameparameters/param/// param namecommandId/param/// param nameeventFlags/param/// returns/returnsbool IContextMenuHandler.OnContextMenuCommand(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){if (commandId (CefMenuCommand)29501){browser.GetHost().ShowDevTools();return true;}return false;}void IContextMenuHandler.OnContextMenuDismissed(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame){var webBrowser (ChromiumWebBrowser)chromiumWebBrowser;Action setContextAction delegate (){webBrowser.ContextMenu null;};webBrowser.Invoke(setContextAction);}bool IContextMenuHandler.RunContextMenu(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){// 必须返回 falsereturn false;}} 然后绑定浏览器的 MenuHandler  browser.MenuHandler new CustomContextMenuHandler(); 5、关闭窗口事件补充 5.1、顶部栏菜单补充 // myapp\src\api\WindowsUtil.ts export const closeWindows async () {await CefSharp.BindObjectAsync(windowsUtil)windowsUtil.Close() } // myapp\src\components\DataViewer.vue templateel-menu :default-activeactiveIndex classel-menu-demo :ellipsisfalse modehorizontal selecthandleSelectel-menu-item index1Processing Center/el-menu-itemdiv classflex-grow /el-sub-menu index2template #titleWorkspace/templateel-menu-item index2-1item one/el-menu-itemel-menu-item index2-2item two/el-menu-itemel-menu-item index2-3item three/el-menu-itemel-sub-menu index2-4template #titleitem four/templateel-menu-item index2-4-1item one/el-menu-itemel-menu-item index2-4-2item two/el-menu-itemel-menu-item index2-4-3item three/el-menu-item/el-sub-menu/el-sub-menuel-menu-item index3 disabledInfo/el-menu-itemel-menu-item index4Exit/el-menu-item/el-menudiv classcommon-layoutel-containerel-main!-- 获取数据后展示 --el-table v-loadingloading :datatableData height400 stylewidth: 100%el-table-column fixed typeindex :indexindexMethod /el-table-column propdate labelDate width150 /el-table-column propname labelName width120 /el-table-column propstate labelState width120 /el-table-column propcity labelCity width120 /el-table-column propaddress labelAddress width600 /el-table-column propzip labelZip width120 /el-table-column fixedright labelOperations width120template #defaultscopeel-button link typeprimary sizesmall clickhandleEdit(scope)Edit/el-buttonel-button link typeprimary sizesmall clickhandleDelete(scope)Delete/el-button/template/el-table-column/el-table!-- 更新数据时对话框 --el-dialog v-modeldialogUpdateFormVisible titleUpdate Shipping address ?el-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogUpdateFormVisible falseCancel/el-buttonel-button typeprimary clickdoUpdate()Confirm/el-button/span/template/el-dialog!-- 删除数据时对话框 --el-dialog v-modeldialogDeleteFormVisible titleDelete Shipping address ?el-form :modelcurrentRowel-form-item labeldate :label-widthformLabelWidthel-input disabled v-modelcurrentRow.date autocompleteoff //el-form-itemel-form-item labelname :label-widthformLabelWidthel-input disabled v-modelcurrentRow.name autocompleteoff //el-form-itemel-form-item labelstate :label-widthformLabelWidthel-input disabled v-modelcurrentRow.state autocompleteoff //el-form-itemel-form-item labelcity :label-widthformLabelWidthel-input disabled v-modelcurrentRow.city autocompleteoff //el-form-itemel-form-item labeladdress :label-widthformLabelWidthel-input disabled v-modelcurrentRow.address autocompleteoff //el-form-itemel-form-item labelzip :label-widthformLabelWidthel-input disabled v-modelcurrentRow.zip autocompleteoff //el-form-itemel-form-item labeltag :label-widthformLabelWidthel-input disabled v-modelcurrentRow.tag autocompleteoff //el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickdialogDeleteFormVisible falseCancel/el-buttonel-button typeprimary clickdoDelete()Confirm/el-button/span/template/el-dialog!-- 关闭窗口时 --el-dialog v-modeldialogVisible title提示 width30% :before-closehandleClosespan确认关闭窗口/spantemplate #footerspan classdialog-footerel-button clickdialogVisible false取消/el-buttonel-button typeprimary clickdoClose确认/el-button/span/template/el-dialog/el-mainel-headerel-row classrow-bg justifyendel-col :span2el-button clickhandleSaveData() typeprimarySaveel-icon classel-icon--rightDocument //el-icon/el-button/el-colel-col :span2el-button clickhandlePrintData() typeprimaryPrintel-icon classel-icon--rightPrinter //el-icon/el-button/el-col/el-row/el-header/el-container/div /templatescript langts setup import { ref, onMounted, reactive } from vue import { getData } from ../api/DataUtil import { saveAsExcel } from ../api/ExcelUtil import { printPdf } from ../api/PrinterUtil import { closeWindows } from ../api/WindowsUtil import { ElMessage, ElMessageBox } from element-plus import { Document, Printer } from element-plus/icons-vue// 表格数据加载标志 const loading ref(true) const tableData reactive([])// 更新数据对话框 const dialogUpdateFormVisible ref(false) const dialogDeleteFormVisible ref(false) const formLabelWidth 140px// 当前选中行数据 const currentRow reactive({date: please input date,name: please input name,state: please input state,city: please input city,address: please input address,zip: please input zip,tag: please input tag, })const currentRowIndex ref(1)const dialogVisible ref(false)// 确认关闭 const doClose () {dialogVisible.value falsecloseWindows() }// 关闭窗口 const handleClose (done: () void) {ElMessageBox.confirm(Are you sure to close this dialog?).then(() {done()}).catch(() {// catch error}) } // 顶部栏菜单 const activeIndex ref(1) const handleSelect (key: string, keyPath: string[]) {console.log(key, keyPath)if (key 4) {dialogVisible.value true} }// 更新事件 const doUpdate () {//console.log( doUpdate , currentRow, currentRowIndex.value)Object.assign(tableData[currentRowIndex.value], currentRow)dialogUpdateFormVisible.value falseElMessage({message: Update success.,type: success,}) }// 删除事件 const doDelete () {// console.log(doDelete , currentRowIndex.value)tableData.splice(currentRowIndex.value, 1)dialogDeleteFormVisible.value falseElMessage({message: Delete success.,type: success,}) }// 索引规则 const indexMethod (index: number) {return index 1 } // Delete 事件 const handleDelete (scope: any) {Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogDeleteFormVisible.value true }// Edit 事件 const handleEdit (scope: any) {//console.log(edit,scope.$index,scope.row)Object.assign(currentRow, scope.row)currentRowIndex.value scope.$indexdialogUpdateFormVisible.value true }// 保存事件 const handleSaveData () {console.log(handleSaveData)saveAsExcel(tableData).then((res: any) {console.log(res, res)if (res.isSuccess) {ElMessage({message: Save success.,type: success,})} else {ElMessage({message: res.msg,type: error,})}}).catch((err: any) {console.log(err, err)}) }// 打印事件 const handlePrintData () {printPdf(tableData).then((res: any) {if (res.isSuccess) {ElMessage({message: Save success.,type: success,})} else {ElMessage({message: res.msg,type: error,})}}) }// 挂载方法 onMounted(() {// 获取数据后将加载标志位位置 false并且绑定到表格getData().then((res: any) {//console.log( getData , res)loading.value falseObject.assign(tableData, res)})})/script style .el-button--text {margin-right: 15px; }.el-select {width: 300px; }.el-input {width: 300px; }.dialog-footer button:first-child {margin-right: 10px; }.el-row {margin-bottom: 20px; }.el-row:last-child {margin-bottom: 0; }.el-col {border-radius: 4px; }.flex-grow {flex-grow: 1; } /style 顶部栏菜单效果 5.2、关闭方法补充 // WindowsUtil.cs namespace DataToolApp.Utils {public class WindowsUtil{public void Close(){Program.dataToolForm.DoCloseWindows();}} }// DataToolForm.cs /// summary /// 关闭窗口 /// /summary public void DoCloseWindows() {this.InvokeOnUiThreadIfRequired((){rowser.Dispose();Cef.Shutdown();Close();}); }/// summary /// 导出类方法 /// /summary public static void ExposeDotnetClass() {browser.JavascriptObjectRepository.ResolveObject (sender, e) {// 注册 ExcelUtil 实例DoRegisterDotNetFunc(e.ObjectRepository, e.ObjectName, excelUtil, new ExcelUtil());// 注册 PrinterlUtil 实例DoRegisterDotNetFunc(e.ObjectRepository, e.ObjectName, printerlUtil, new PrinterlUtil());// 注册 WindowsUtil 实例DoRegisterDotNetFunc(e.ObjectRepository, e.ObjectName, windowsUtil, new WindowsUtil());// 注册其他实例 ...};browser.JavascriptObjectRepository.ObjectBoundInJavascript (sender, e) {var name e.ObjectName;Debug.WriteLine($Object {e.ObjectName} was bound successfully.);};} 6、调整 DoRegisterDotNetFunc NameConverter 只能赋值一次 /// summary/// 注册 DoNet 实例/// /summary/// param namerepo IJavascriptObjectRepository /param/// param nameeventObjectName事件对象名/param/// param namefuncName方法名/param/// param nameobjectToBind需要绑定的DotNet对象/paramprivate static void DoRegisterDotNetFunc(IJavascriptObjectRepository repo, string eventObjectName, string funcName, object objectToBind){if (eventObjectName.Equals(funcName)){if (!IsSetNameConverter){repo.NameConverter new CamelCaseJavascriptNameConverter();IsSetNameConverter true;}BindingOptions bindingOptions null;bindingOptions BindingOptions.DefaultBinder;//repo.NameConverter null;//repo.NameConverter new CamelCaseJavascriptNameConverter();repo.Register(funcName, objectToBind, isAsync: true, options: bindingOptions);}} 四、效果测试 1、查询 2、修改 3、删除 4、保存 Excel 5、打印 PDF 6、关闭 五、窗口属性配置补充 1、自适应分辨率 2、动态边框长宽 3、显示任务栏图标 4、窗口屏幕居中 六、Demo 最终成品
http://www.dnsts.com.cn/news/87302.html

相关文章:

  • 浦东新区建设局网站全屏幕网站模板
  • 沧州公司网站建设今科网站建设
  • 网站首页页面设计多少钱把货卖到国外有哪些平台
  • wordpress 不同站点福州网站关键词推广
  • 明薇通网站建设价格wordpress 中文链接
  • 乐清网站网络公司东莞电子网站建设
  • 小网站的制作网站开发如可使用支付宝
  • 网站建设策划实训总结wordpress 外观菜单
  • 网站建设的重要指标住建厅特种作业证全国通用吗
  • 什么是php网站开发哪里教做网站的
  • 网站群建设北京注册公司需要什么资料
  • 官网建设银行网站抖音产品推广方案
  • 长沙市师德师风建设网站网站建设j基本步骤
  • 巴中建设银行网站wordpress访问不了
  • 网站如何转做app郑州做网站九零后网络
  • 西宁网站建设最好的公司九龙坡区建设二校有网站吗
  • 福州帮人建网站公司推广普通话的方法
  • 网站浏览历史记录恢复方法是什么企业建设银行网站登录不了
  • 建站公司见客户没话说陌陌引流推广软件
  • 专业柳州网站建设旅游电子商务网站建设目的
  • 哪里可以学企业管理培训佛山市seo推广
  • 苏州网站开发的企业桥头镇网站仿做
  • WordPress客户端汕头网站优化公司
  • 免费的个人的网站wordpress网站生成app
  • 国内十大4a广告公司seo优化网站建设哪家好
  • 门户网站快速制作做一个公司的网站应做哪些准备工作内容
  • 自己可以做类似拓者的网站吗商品展示页面设计模板
  • 2016做砸了的小网站微信小程序怎么做成链接
  • 网站推广的软文陕西省建设厅网站月报
  • 手机网站要求怎么做虚拟网站