使用Vue写单页应用环境一般都在nodejs和webpack等环境中进行开发,接下要介绍的是完全不依赖于这两者去做Vue单页面应用的BeetleX服务组件。可能有朋友好奇服务应用框架为什么和前端框架搭上边的呢?其实主要原因是希望BeetleX的Webapi组件可以更好地和Vue集成,所以针对性开发了相关服务插件。
在插件的支持下依旧可以使用模块化来开发Vue应用,同样需要编写*.vue文件;但不同的是不需要nodejs和webpack的支持,使用的而是vuejs的基础包;编写*.vue文件也有些不同,但总体来说vue文件编写起来会简单一些,不用考虑包引用导入问题。
搭建开发项目
可以使用vs.net或vscode来开发vue单页面项目(无须安装相关插件),建议使用vs.net毕竟它在不安装javascript和html相关插件也可以得到很好的编写体验效果。
首先要创建一个控制台项目,然后引用Beetlex.FastHttpApi和BeetleX.FastHttpApi.VueExtend组件。引用完成后就可以使用组件构建Webapi服务
class Program { static void Main(string[] args) { HttpApiServer server = new HttpApiServer(); server.Options.SetDebug(); server.Options.Port = 80; server.Options.LogLevel = EventArgs.LogType.Warring; server.Options.LogToConsole = true; server.Options.SSL = true; server.Options.CertificateFile = "ssl.pfx"; server.Options.CertificatePassword = "123456"; server.AddExts("woff;ttf"); //添加EFCore数据库 server.AddEFCoreDB(); //注册webapi控制器 server.Register(typeof(Program).Assembly); //定义Vue资源加载路径 server.Vue().JsRewrite("/js/{group}.js") .CssRewrite("/css/{group}.css") .Debug(); //定义vuebase的Vue资源项 var websource = server.Vue().CreateWebResorce("vuebase"); websource.AddAssemblies(typeof(Program).Assembly); //加载基础css websource.AddCss("index.css", "site.css"); //加载基础javascript websource.AddScript("axios.js", "vue.js", "element.js", "beetlex4axios.js"); server.Open(); System.Threading.Thread.Sleep(-1); } }
组件是通过传统的方式打包css和javascript,在创建Vue包资源的时候只需要添加基础的javascript和css文件即可。对于项目里的*.vue文件组件则以动态打包运行打包。在Release编译模式下,组件会自行对生成的js文件进行版本缓存和gzip输出管理。
文件布局
构建完成服务后就定义文件存储方式,以下是一个简单示例。
所有文件必须存放在views目录下,它是web服务的根目录;之后的目录布局则可以根据自己喜欢来定义。文件发布配置上可以根据自己需要来选择,一种是文件嵌入到资源最终打包的DLL中;另一种就是复制在编译后会复制到发布目录的views目录下。详细可查看:BeetleX之web静态文件处理
页面定义
在访问服务时,组件默认会输出当前目录下的index.html文件,只需要在这页面做Vue的应用页面即可。
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"><head> <meta charset="utf-8" /> <title>title> <link href="/css/vuebase.css" rel="stylesheet" /> <script src="/js/vuebase.js">script>head><body> <div id="app"> <page-header>page-header> <div id="main"> <page-menu @select="select">page-menu> <div id="content"> <component :is="module">component> div> div> div> <script> var page = new Vue({ el: '#app', data: { items: [], module:'customers', }, methods: { select(module) { this.module = module; }, } });script>body>html>
在这里需要关注是css和js的引用路径问题,这个路径是在开始部署服务配置的时候定义
server.Vue().JsRewrite("/js/{group}.js").CssRewrite("/css/{group}.css").Debug();
实际上这些路径可以根据需求来定义,group部分是用于描述对应相应的Vue资源。
var websource = server.Vue().CreateWebResorce("vuebase");websource.AddAssemblies(typeof(Program).Assembly);
如果应用是划分多个页面,而可以定义不同资源块在不同页面中引用,这样就防止统一用一个vue资源导致加载过重。
再回到这个示例上,这个单页定义两大块内容,一块功能菜单和内容功能模块显示。
菜单模块
<page-menu @select="select">page-menu>
这个模块对应的是page-menu.vue文件,它提供了一个select事件,用于告诉页面切换内容显示的模块,其具体实现如下:
<div id="menus"> <el-menu default-active="1" size="mini" @select="onSelect"> <el-menu-item index="1"> <i class="el-icon-menu">i> <span slot="title">用户span> el-menu-item> <el-menu-item index="2"> <i class="el-icon-document">i> <span slot="title">雇员span> el-menu-item> <el-menu-item index="3"> <i class="el-icon-setting">i> <span slot="title">订单span> el-menu-item> el-menu>div><script> { data(){ return {} }, methods: { onSelect(i){ console.log(i); var module = 'employees'; if (i == 2) { module = 'employees'; } else if (i == 3) { module = 'orders'; } else { module = 'customers'; } this.$emit('select', module); } } }script>
组件支持的*.Vue是一个html+javascript的混合体,而javascript部分只需要定义Vue组件的Setting部,相信写过vue组件应该不会陌生了。
内容模块
在页面中定义了component标签来动态显示对应的功能模块
"content"> :is="module">
</div>
Vue可以通过:is来指定component展示的内容,所以可以根据需示定义不同的展示模块然后在菜单中切换即可。*.vue的定义规则是【模块名.vue】,模块名对应组件的html标签.
构建WebApi
组件是支持Webapi定义的,可以直接在当前服务中定义相关webapi数据接口,并且无须考虑跨域访问问题。针对当前示例实现的服务如下:
[Controller] public class Webapi { public DBObjectListEmployees(EFCoreDB db) { return (db.DBContext, "select * from employees"); } public async Task<object> Customers(EFCoreDB db, int size, int index, string country) { DBRegionData result = new DBRegionData(index, size); Selectselect = new Select(); if (!string.IsNullOrEmpty(country)) select &= c => c.Country == country; await result.ExecuteAsync(db.DBContext, select); return result; } public async Task<object> Orders(EFCoreDB db, int size, int index, string customer, int employee) { DBRegionData result = new DBRegionData(index, size); SQL sql = @"select Orders.*,Employees.FirstName,Employees.LastName,Customers.CompanyName from Orders inner join Employees on Employees.EmployeeID=Orders.EmployeeID inner join Customers on Customers.CustomerID= Orders.CustomerID where 1=1"; if (!string.IsNullOrEmpty(customer)) sql.And().Where(o => o.CustomerID == customer); if (employee > 0) sql.And().Where(o => o.EmployeeID == employee); await result.ExecuteAsync(db.DBContext, sql); return result; } public DBValueList<string> CustomerCountry(EFCoreDB db) { return (db.DBContext, "select distinct country from customers"); } public DBObjectListListCustomerName(EFCoreDB db) { return (db.DBContext, "select CustomerID,CompanyName from customers"); } public DBObjectListListEmployeeName(EFCoreDB db) { return (db.DBContext, "select EmployeeID,FirstName,LastName from employees"); } }
由于组件也集成了EFCore插件,所以在数据访问上也同样方便。
订单模块
基于单页面处理后,所有功能都基于模块开发,接下来介绍一下订单查询这一模块的实现。
<div> <el-form :inline="true" size="mini"> <el-form-item label="Employee"> <el-select v-model="listOrders.data.employee" placeholder="Employee"> <el-option label="Null" value="">el-option> <el-option v-for="item in listEmployee.result" :label="item.FirstName+' '+item.LastName" :value="item.EmployeeID">el-option> el-select> el-form-item> <el-form-item label="Customer"> <el-select v-model="listOrders.data.customer" placeholder="Customer"> <el-option label="Null" value="">el-option> <el-option v-for="item in listCustomer.result" :label="item.CompanyName" :value="item.CustomerID">el-option> el-select> el-form-item> <el-form-item> <el-button type="primary" @click="onSearch">Searchel-button> el-form-item> el-form> <el-table :data="listOrders.result.Items" style="width: 100%" size="mini"> <el-table-column prop="OrderID" label="OrderID" width="180"> el-table-column> <el-table-column prop="CompanyName" label="Customer" width="180"> el-table-column> <el-table-column label="Employee"> <template slot-scope="scope"> {{scope.row.FirstName}} {{scope.row.LastName}} template> el-table-column> <el-table-column prop="OrderDate" label="OrderDate"> el-table-column> <el-table-column prop="RequiredDate" label="RequiredDate"> el-table-column> <el-table-column prop="ShippedDate" label="ShippedDate"> el-table-column> el-table> <el-pagination background layout="prev, pager, next" :total="listOrders.result.Count" :page-size="listOrders.result.Size" @current-change="onPageChange"> el-pagination>div><script> { data(){ return { listCustomer: new beetlexAction("/ListCustomerName", null, []), listEmployee: new beetlexAction("ListEmployeeName", null, []), listOrders: new beetlexAction("/Orders", { index: 0, customer: '', employee: '' }, { Size: 20, Items: [], Count: 0 }) }; }, methods: { onPageChange(e){ this.listOrders.data.index = e - 1; this.listOrders.get(); }, onSearch(){ this.listOrders.data.index =0; this.listOrders.get(); }, }, mounted(){ this.listCustomer.get(); this.listEmployee.get(); this.listOrders.get(); }, }script>
发布
编译项后即可以运行在安装有对应版本.net core的linux或windows系统上。如果你不想使用BeetleX服务运行,只需要在本地运行服务访问一下,运行目录上就会生成对应js和css文件;这两个文件是针对vue打包好的脚本和样式文件,可以把index.html和相关的js,css文件放到其他web服务中运。
行。
总结
在BeetleX的不同插件支持下,可以快速地搭建Vue应用,并且在开发完成后直接发布部署,无须再依赖于其他环境插件。以下是基于BeetleX搭建的vue单页面应用服务案例:
https://beetlex.io/__system/bumblebee/index.html
http://webbenchmark.beetlex.io/
下载示例
链接:
https://pan.baidu.com/s/15lpeZc7fGDvOdVcTtpqaUg
提取码:
3xf1
【BeetleX通讯框架代码详解】
【WebApi示例扩展】
BeetleX
开源跨平台通讯框架(支持TLS)
轻松实现高性能:tcp、http、websocket、redis、rpc和网关等服务应用
https://beetlex.io
如果你想了解某方面的知识或文章可以把想法发送到
henryfan@msn.com|admin@beetlex.io