Mvc是近年比较流行的一种web开发模式 个人觉得MVC是一种简单易懂、高效的开发模式;关于开发模式还有MVVM, vue.js就是这种模式,这里就不讲什么是MVC、 MVVM了, 有兴趣可以百度了解一下。
主要用到的技术:
Asp.net MVC 5
IView + Vue.js(这两者是完美搭档, IView:基于Vue.js的UI)
require.js (按需加载js模块, 详解更多JS模块化工具requirejs教程,或进入require.js官网)
sql server 2017
Visual Studio 2017
下面我们将以一个(SecurityDemo)通用权限系统demo为例:
目录
第1章. 创建SecurityDemo项目
第2章 第一个实例
第3章: HtmlHelper类封装UI
1. 新建项目
点确定 -->
2. 添加RequireJs , IView + Vue.js到项目
菜单选择工具 --》 NuGet包管理器 --》 管理解决方案Nuget程序包:
a.安装requirejs:(也要安装require.css程序包,因为IView.css将作为IView的依赖引入)
找到Requirejs的程序包, 右边列表项目里勾选指定的项目,点击“安装“按钮
安装成功后,会看到多了下面几个文件
b.安装IView + Vue.js
这里版本并不是最新的, 安装成功后, 可以去官网拿最新的替换现在的,我们这里也是这样。(IView官网)
安装成功后, 多了下面这些文件:
这些文件我们也是要替换的,资源URL, 找到我们要替换的文件,下载后替换掉 ,官网好像不能打包下载,我们可以用迅雷批量下载:
右键菜单点击迅雷下载全部链接,取消下载html类型的文件
vue.js官网最新下载vue.js, vue.min.js
文件结构:
主要文件:
//index.cshtml
@{
ViewBag.Title = "Index";
Layout = null;
}
Index
Click me!
Welcome to iView
{{visible}}
Forward
//main.js
//配置模块
require.config({
waitSeconds: 15,
baseUrl: './',
paths: {
'jquery': '/Scripts/jquery-1.10.2.min.js',
'jqueryvalidate': '/Scripts/jquery.validate.min',
'modernizr': '/Scripts/modernizr-2.6.2',
'respond': '/Scripts/respond',
'iview': '/Scripts/IView/iview.min',
'vue': '/Scripts/vue.min',
'BaseApp': '/Scripts/Base/BaseApp',
'VueResource': '/Scripts/vue-resource.min',
'less': '/Scripts/less-1.5.1.min'
},
shim: {
'jqueryforval': {
exports: 'jquery'
},
'jqueryvalidate': {
exports: '$',
deps: ['/Scripts/jquery-1.10.2', '/Scripts/jquery.validate.unobtrusive']
},
'vue':{
exports: 'Vue'
},
'iview': {
exports: 'iview',
deps: ['css!/Content/Iview/iview.css','css!/Content/Iview/iviewplus.css', 'vue']
},
VueResource: {
exports: 'VueResource',
deps: ['vue']
}
},
map: {
'*': {
css: '/scripts/css.min.js'
}
}
////加上时间戳
//,urlArgs: "bust=" + (new Date()).getTime()
});
// 注册事件
require(['vue', 'iview'], function (Vue, iview) {
Vue.use(iview);
});
//BaseApp.js
define(['vue', 'less', 'iview'], function (Vue, less, iview) {
// 使用严格模式
'use strict';
var BaseApp = function () {
return {
Config: {},
Instance: {},
Run: function (appId) {
var self = this;
if (appId) {
self.Config.el = appId;
}
$(document).ready(function () {
Vue.use(iview);// 注册IView
self.Instance = new Vue(self.Config);
});
},
IsEmptyStr: function (str) {
if (!str) { str = ""; }
if (str.length <= 0) { return true; } else { return false; }
},
isEmpty: function (o) {
if (typeof (o) == "undefined") { return true; }
if (!o) { return true; }
if (typeof (o) == "object") {
for (var n in o) { return false; }
return true;
}
if (o instanceof Array) {
if (!o.length) { return true; }
}
return false;
}
}
}();
return BaseApp;
}
);
//index.js
define(['BaseApp'], function (BaseApp) {
// 使用严格模式
'use strict';
$(function () {
BaseApp.Config = {
el: '#app',
data: {
visible: false,
buttonSize: 'large',
myname:'LoveLearning',
columns1: [
{
title: 'Name',
key: 'name'
},
{
title: 'Age',
key: 'age'
},
{
title: 'Address',
key: 'address'
}
],
data1: [
{
name: 'John Brown',
age: 18,
address: 'New York No. 1 Lake Park',
date: '2016-10-03'
},
{
name: 'Jim Green',
age: 24,
address: 'London No. 1 Lake Park',
date: '2016-10-01'
},
{
name: 'Joe Black',
age: 30,
address: 'Sydney No. 1 Lake Park',
date: '2016-10-02'
},
{
name: 'Jon Snow',
age: 26,
address: 'Ottawa No. 2 Lake Park',
date: '2016-10-04'
}
]
},
methods: {
show: function () {
this.visible = !this.visible;
},
clicked: function () {
alert("Clicked!");
}
}
};
return BaseApp.Run();
});
});
运行后的效果如下:
这里我们已经初步完成了一个简单的IView的Demo,下一章将会将如何封装到.Net htmlhelper中。
先说一下上次的问题,main.js引入iview会有异常,requirejs异步加载文件,执行baseapp的时候,iview可能还没引入,会出错,
所以应该搬到baseapp.js里引入。
main.js之前已经引入了iview和vue对象了, 所以只需main.js里注释这段:
// 注册事件
require(['vue', 'iview'], function (Vue, iview) {
Vue.use(iview);
});
1. HtmlHelper封装
为什么要封装:主要目的还是为了高效编写代码,可以增加拓展属性或方法,使用更友好,特别对于后端开发人员来说,用代码实现更好理解。
现在,让我们正是开始实践吧
首先,在你的解决方案里,
解决方案里是之前已经写好的,所以我就不再新建了。
首先我们创建基类及其接口:
IBase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
namespace MvcIViewUI.BaseUI
{
public interface IBase : IHtmlString
{
string GetHtml();
T Id(string id);
T SetRef(string _ref);
T AddInnerUI(TInnerUI control) where TInnerUI : IBase;
// T SetUIName(string uiName);
}
}
Base.cs
using MvcIViewUI.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
namespace MvcIViewUI.BaseUI
{
public abstract class Base : IBase
{
protected T self;
protected string UIName;
protected string innerContent = "";
protected List bindModelProps = new List();
protected List slots = new List(); //分发到此控件的内容
protected string htmlAttribute = "";
protected Dictionary DefValueList = new Dictionary();
protected string style = "";
protected string slot = ""; //如果是嵌入的内容, 注意要设置
protected string text = "";
public bool isNoEndEle = false;//是否是原生无结束标志的元素
public bool isProp = false;
public string id { get; protected set; }
///
/// 起到定位的作用, 相当于id,注意不能重复
///
public string Ref { get; protected set; }
public string v_model { get; protected set; }
public string v_if { get; protected set; }
///
/// 标签文本
///
public virtual string label { get; protected set; }
public virtual string v_for { get; protected set; }
public virtual string key { get;protected set; }
///
/// 控件css类
///
public string cls { get; protected set; }
public Base() {
if (string.IsNullOrEmpty(UIName)) {
UIName = "base";
}
self = (T)Convert.ChangeType(this, typeof(T));
this.innerContent = "";
}
///
/// 构造此对象
///
/// 分发类型
public Base(string slot)
{
this.slot = slot;
if (string.IsNullOrEmpty(UIName))
{
UIName = "base";
}
self = (T)Convert.ChangeType(this, typeof(T));
this.innerContent = "";
}
///
/// 生成html内容
///
public virtual string GetHtml()
{
string ls_html = "", ls_propsEvnts = "";
#region 外层部分
//非属性
if (!isProp)
{
ls_html = "<" + UIName;
}
if (!string.IsNullOrEmpty(id))
{
ls_html += " id=\"" + this.id + "\"";
}
if (!string.IsNullOrEmpty(this.cls)) {
if (this.cls.StartsWith(":")) {
ls_html += " :class=\"" + this.cls.Substring(1, this.cls.Length-1) + "\"";
}
else {
ls_html += " class=\"" + this.cls + "\"";
}
}
if (!string.IsNullOrEmpty(this.Ref))
{
ls_html += " ref=\"" + this.Ref + "\"";
}
if (!string.IsNullOrEmpty(this.slot))
{
ls_html += " slot=\"" + this.slot + "\"";
}
if (!string.IsNullOrEmpty(this.htmlAttribute))
{
ls_html += " " + this.htmlAttribute.Trim();
}
//:style="{
if (!string.IsNullOrEmpty(this.style))
{
ls_html += " :style=\"{" + this.style.Trim() + "}\"";
}
ls_propsEvnts = GenPropsEvent();
if (!string.IsNullOrEmpty(ls_propsEvnts))
{
ls_html += " " + ls_propsEvnts;
}
//作为容器使用
if (isProp) {
return ls_html;
}
if (isNoEndEle) {
ls_html = ls_html + "/>";
}
else {
ls_html = ls_html + ">";
if (!string.IsNullOrEmpty(this.text))
{
ls_html += text;
}
}
#endregion
#region The end
if (!isNoEndEle)
{
if (UIName == "Upload" && string.IsNullOrEmpty(this.innerContent)) {
if (!string.IsNullOrEmpty(this.text)) {
this.innerContent = "" + this.text + " ";
}
else {
this.innerContent = "Upload files ";
}
}
if (!string.IsNullOrEmpty(this.innerContent))
{
ls_html += this.innerContent;
}
return ls_html + "" + UIName + ">";
}
else {
return ls_html;
}
#endregion
}
public T Id(string id)
{
this.id = id;return self;
}
public T SetRef(string _ref)
{
this.Ref = _ref; return self;
}
///
/// 设置分发类型
///
/// 分发类型
public virtual T Slot(string slot) {
this.slot = slot;
return self;
}
///
/// 即设置v-if属性
///
public T If(string v_if, bool isBindModel = false) {
if (isBindModel) { bindModelProps.Add("v_if"); }
this.v_if = v_if;
return self;
}
///
/// 设置控件css样式类
///
public T Cls(string cls) {
this.cls = cls;
return self;
}
///
/// 设置控件html属性,可以多个
///
public T HtmlAttribute(string htmlAttribute) {
this.htmlAttribute = htmlAttribute;
return self;
}
public string ToHtmlString()
{
return GetHtml();
}
///
/// 嵌入新的控件到此控件里
///
/// 将要嵌入的控件
public T AddInnerUI(TInnerUI control) where TInnerUI : IBase
{
if (";area;base;br;col;command;embed;img;hr;keygen;link;meta;param;source;track;input;wbr;".IndexOf(";" + UIName.ToLower() + ";") < 0 && control!= null)
{
this.innerContent += control.GetHtml();
}
return self;
}
///
/// 设置嵌入的内容(html/text)
///
public T AddContent(string content) {
if (string.IsNullOrEmpty(this.innerContent)) { this.innerContent = ""; }
this.innerContent += content;
return self;
}
///
/// 设置html属性, 可以多个,例子: 'value="value1" format="yyyy年MM月dd日" type="date"'
///
///
///
public T HtmlAttr(string htmlAttribute)
{
this.htmlAttribute = htmlAttribute;
return self;
}
public T BackColor(string color)
{
AddStyleItem("background", color);
return self;
}
///
/// 设置宽度
///
public T Width(int width)
{
AddStyleItem("width", width.ToString() + "px");
return self;
}
///
/// 设置宽度
///
public T Width(string width)
{
AddStyleItem("width", width);
return self;
}
///
/// 设置高度
///
public T Height(string height)
{
AddStyleItem("height", height);
return self;
}
public T Height(int height)
{
AddStyleItem("height", height.ToString() + "px");
return self;
}
public T Left(string left)
{
AddStyleItem("left", left);
return self;
}
public T Left(int left)
{
AddStyleItem("left", left.ToString() + "px");
return self;
}
public T Right(string right)
{
AddStyleItem("right", right);
return self;
}
public T Right(int right)
{
AddStyleItem("right", right.ToString()+"px");
return self;
}
public T Style(string styles)
{
if (string.IsNullOrEmpty(styles)) { return self; }
if (styles.StartsWith(",")) { this.style = this.style + styles; }
else
{
if (!string.IsNullOrEmpty(this.style))
{
this.style = this.style + "," + styles;
}
else
{
this.style = styles;
}
}
return self;
}
///
/// 使用 v-model 双向绑定数据
///
public T Model(string vModel) {
this.v_model = vModel;return self;
}
#region 受保护的方法
protected virtual void InitDefValue() {
}
protected virtual string GenPropsEvent()
{
string ls_return = "", ls_prefix = "";
var types = self.GetType();
var props = types.GetProperties(); //当前类的所有属性
InitDefValue();
foreach (var p in props)
{
var sList = p.CustomAttributes.ToList();
var propName = p.Name;
var propValue = p.GetValue(self); //p.GetValue(this);
var propType = p.PropertyType.FullName;
var orgPropName = propName;
if (string.IsNullOrEmpty(propName)) { continue; }
if (propName.Substring(0, 1) == "_") { propName = propName.Substring(1, propName.Length - 1).Trim(); }
propName = propName.Replace("_", "-").ToLower();
bool isEvent = false;
foreach (var cstAttr in sList)
{
//Event
if (cstAttr.AttributeType.FullName == "MvcIViewUI.BaseUI.EventAttribute")
{
isEvent = true;
break;
}
}
if (!isEvent)
{ //Prop
ls_prefix = "";
if (bindModelProps.FindIndex(m => m == orgPropName) > -1) { ls_prefix = ":"; }
if (propType == "System.String") {
propValue = propValue == null ? "" : ((string)propValue).Trim();
if (!string.IsNullOrEmpty((string)propValue)) {
if (((string)propValue).StartsWith(":")) {
ls_prefix = ":";
propValue = ((string)propValue).Substring(1, ((string)propValue).Length - 1).Trim();
}
}
}
if (!string.IsNullOrEmpty(ls_prefix))//绑定了模型
{
ls_return += " " + ls_prefix + propName + "=\"" + (string)propValue + "\"";
}
else if (propType == "System.Boolean")
{
if (DefValueList.ContainsKey(orgPropName))
{
if ((bool)DefValueList[orgPropName] == (bool)propValue)
{
continue;
}
}
if ((bool)propValue)
{
ls_return += " " + propName;
}
else
{
ls_return += " " + ls_prefix + propName + "=\"false\"";
}
}
else if (propType == "System.DateTime")
{
if (DefValueList.ContainsKey(orgPropName))
{
if (Convert.ToDateTime(DefValueList[orgPropName]) == Convert.ToDateTime(propValue))
{
continue;
}
}
if (Convert.ToDateTime(propValue) != null)
{
ls_return += " :" + propName + "=\"new Date('" + Convert.ToDateTime(propValue).ToString("yyyy-MM-dd hh:mm:ss") + "')\"";
}
}
else if (propType == "System.Int32")
{
if (DefValueList.ContainsKey(orgPropName))
{
if ((int)DefValueList[orgPropName] == (int)propValue)
{
continue;
}
}
if ((int)propValue > 0)
{
ls_return += " " + ls_prefix + propName + "=\"" + propValue.ToString() + "\"";
}
}
else if (propType == "System.String")
{
if (DefValueList.ContainsKey(orgPropName))
{
if ((string)DefValueList[orgPropName] == (string)propValue)
{
continue;
}
}
if (!string.IsNullOrEmpty((string)propValue))
{
ls_return += " " + ls_prefix + propName + "=\"" + (string)propValue + "\"";
}
}
else
{
if (DefValueList.ContainsKey(orgPropName))
{
if (DefValueList[orgPropName] == propValue)
{
continue;
}
}
if (propValue != null)
{
ls_return += " " + ls_prefix + propName + "=\"" + (string)propValue + "\"";
}
}
}
else
{
if (!string.IsNullOrEmpty((string)propValue))
{
ls_return += " @" + propName + "=\"" + (string)propValue + "\"";
}
}
}
return ls_return;
}
protected void AddStyleItem(string styleItem, string value)
{
if (string.IsNullOrEmpty(styleItem) || string.IsNullOrEmpty(value)) { return; }
if (!string.IsNullOrEmpty(this.style))
{
this.style += ", " + styleItem + ": '" + value + "'";
}
else
{
this.style = styleItem + ": '" + value + "'";
}
}
protected T SetUIName(string uiName)
{
this.UIName = uiName;
return self;
}
#endregion
}
}
2.创建第一个Asp.net Mvc UI, 以Button为例:
先在项目中新建"UI"文件夹, 这里要用来存放我们要封装的UI,然后创建
Button.cs
using MvcIViewUI.BaseUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace MvcIViewUI.UI
{
public class Button : Base
3.创建UI存储库类MvcIViewUIRsp,所有的UI都通过仓库输出,可以加个接口约束:
using MvcIViewUI.BaseUI;
using MvcIViewUI.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace MvcIViewUI.UIRsp
{
public interface IMvcIViewUIRsp
{
MvcHtmlString BaseAppUrl(string url);
T ParseUI(T uiControl) where T : IBase;
Button UIButton();
}
}
MvcIViewUIRsp.cs
using MvcIViewUI.BaseUI;
using MvcIViewUI.Chart;
using MvcIViewUI.ContainerUI;
using MvcIViewUI.ExtendUI;
using MvcIViewUI.NavUI;
using MvcIViewUI.UI;
using MvcIViewUI.ViewUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace MvcIViewUI.UIRsp
{
public class MvcIViewUIRsp : IMvcIViewUIRsp
{
///
/// 加载应用程序核心js文件
///
/// js文件路径
public MvcHtmlString BaseAppUrl(string url)
{
string sScript = "";
if (string.IsNullOrEmpty(url)) { url = ""; }
sScript = "";
return new MvcHtmlString(sScript);
}
///
/// 手动解析UI
///
///
public T ParseUI(T uiControl) where T : IBase
{
return uiControl;
}
public Button UIButton() {
return new Button();
}
public Button UIButton(string text, string icon = "", string slot = "")
{
return new Button(text, icon, slot);
}
}
}
4.将UI库挂载到HtmlHelper静态类中
在项目中创建静态类:UIHelper,
using MvcIViewUI.UIRsp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
namespace MvcIViewUI
{
public static class UIHelper
{
public static MvcIViewUIRsp IView(this HtmlHelper helper)
{
return new MvcIViewUIRsp();
}
}
}
5.编写cshtml页面
@using MvcIViewUI
@{
ViewBag.Title = "firstapp";
}
@Html.IView().UIButton("登录", "md-arrow-forward").Type("primary").Style("width:'100%'").OnClicked("ue_test")
@Html.IView().BaseAppUrl("../../Scripts/App/Home/firstapp")
Scripts/App/Home/firstapp.js
define(['BaseApp'], function (BaseApp) {
// 使用严格模式
'use strict';
$(function () {
BaseApp.Config = {
el: '#testapp',
data: {
},
methods: {
ue_test: function () {
alert("Tested!");
}
}
};
return BaseApp.Run();
});
});
运行后,就可以看到效果了。