.net core + vue开发单页应用(二)

上一篇中已将完成了基础结构的搭建,这一篇将开始正式开发。页面直接使用了一位小伙伴的源码,可以在https://github.com/taylorchen709/vue-admin下载

修改入口main.js

在入口函数中添加对element-ui,vue-router,vuex,vue-source等组件的引用

 
 
  1. import Vue from 'vue'
  2. import App from './App'
  3. import ElementUI from 'element-ui'
  4. import 'element-ui/lib/theme-default/index.css'
  5. import VueRouter from 'vue-router'
  6. import store from './vuex/store'
  7. import Vuex from 'vuex'
  8. import VueSource from 'vue-resource'
  9. import routes from './routes'
  10. import 'font-awesome/css/font-awesome.min.css'
  11. Vue.use(ElementUI)
  12. Vue.use(VueRouter)
  13. Vue.use(Vuex)
  14. Vue.use(VueSource)
  15. //创建路由实例
  16. const router = new VueRouter({
  17. routes
  18. })
  19. router.beforeEach((to, from, next) => {
  20. //这里进行了简单的登录验证
  21. //访问login时直接清除user
  22. if (to.path == '/login') {
  23. sessionStorage.removeItem('user');
  24. }
  25. let user = JSON.parse(sessionStorage.getItem('user'));
  26. if (!user && to.path != '/login') {
  27. next({ path: '/login' })
  28. } else {
  29. next()
  30. }
  31. })
  32. new Vue({
  33. router,
  34. store,
  35. render: h => h(App)
  36. }).$mount('#app')

修改App.vue

 
 
  1. <template>
  2. <div id="app">
  3. <transition name="fade"
  4. mode="out-in">
  5. <router-view></router-view>
  6. </transition>
  7. </div>
  8. </template>
  9. <script>
  10. export default {
  11. name: 'app',
  12. components: {
  13. }
  14. }
  15. </script>

增加viewes文件夹,并增加模块视图

login.vue

 
 
  1. <template>
  2. <el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px" class="demo-ruleForm login-container">
  3. <h3 class="title">系统登录</h3>
  4. <el-form-item prop="account">
  5. <el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="账号"></el-input>
  6. </el-form-item>
  7. <el-form-item prop="checkPass">
  8. <el-input type="password" v-model="ruleForm2.checkPass" auto-complete="off" placeholder="密码"></el-input>
  9. </el-form-item>
  10. <el-checkbox v-model="checked" checked class="remember">记住密码</el-checkbox>
  11. <el-form-item style="width:100%;">
  12. <el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit2" :loading="logining">登录</el-button>
  13. </el-form-item>
  14. </el-form>
  15. </template>
  16. <script>
  17. export default {
  18. data() {
  19. return {
  20. logining: false,
  21. ruleForm2: {
  22. account: 'admin',
  23. checkPass: '123456'
  24. },
  25. rules2: {
  26. account: [
  27. { required: true, message: '请输入账号', trigger: 'blur' },
  28. //{ validator: validaePass }
  29. ],
  30. checkPass: [
  31. { required: true, message: '请输入密码', trigger: 'blur' },
  32. //{ validator: validaePass2 }
  33. ]
  34. },
  35. checked: true
  36. };
  37. },
  38. methods: {
  39. handleReset2() {
  40. this.$refs.ruleForm2.resetFields();
  41. },
  42. handleSubmit2(ev) {
  43. var _this = this;
  44. this.$refs.ruleForm2.validate((valid) => {
  45. if (valid) {
  46. this.logining = true;
  47. //NProgress.start();
  48. var loginParams = { username: this.ruleForm2.account, password: this.ruleForm2.checkPass };
  49. if (loginParams.username != 'admin') {
  50. this.$message({
  51. message: '用户不存在',
  52. type: 'error'
  53. });
  54. this.logining = false;
  55. return false;
  56. }
  57. if (loginParams.password != '123456') {
  58. this.$message({
  59. message: '密码不正确',
  60. type: 'error'
  61. });
  62. this.logining = false;
  63. return;
  64. }
  65. let user = {
  66. id: 1,
  67. username: 'admin',
  68. password: '123456',
  69. avatar: 'resources/img/user.png',
  70. name: '管理员'
  71. }
  72. sessionStorage.setItem('user', JSON.stringify(user));
  73. this.$router.push({ path: '/' });
  74. } else {
  75. return false;
  76. }
  77. });
  78. }
  79. }
  80. }
  81. </script>
  82. <style scoped>
  83. .login-container {
  84. /*box-shadow: 0 0px 8px 0 rgba(0, 0, 0, 0.06), 0 1px 0px 0 rgba(0, 0, 0, 0.02);*/
  85. -webkit-border-radius: 5px;
  86. border-radius: 5px;
  87. -moz-border-radius: 5px;
  88. background-clip: padding-box;
  89. margin: 180px auto;
  90. width: 350px;
  91. padding: 35px 35px 15px 35px;
  92. background: #fff;
  93. border: 1px solid #eaeaea;
  94. box-shadow: 0 0 25px #cac6c6;
  95. }
  96. .title {
  97. margin: 0px auto 40px auto;
  98. text-align: center;
  99. color: #505458;
  100. }
  101. .remember {
  102. margin: 0px 0px 35px 0px;
  103. }
  104. </style>

home.vue

 
 
  1. <template>
  2. <el-row class="container">
  3. <el-col :span="24" class="header">
  4. <el-col :span="10" :class="collapsed?'logo-collapse-width logo-collapsed':'logo-width logo'">
  5. {{collapsed?'':sysName}}
  6. <!--<img :src="logo" v-show="collapsed" />-->
  7. </el-col>
  8. <el-col :span="10">
  9. <div class="tools" @click.prevent="collapse">
  10. <i class="fa fa-align-justify"></i>
  11. </div>
  12. </el-col>
  13. <el-col :span="4" class="userinfo">
  14. <el-dropdown trigger="hover">
  15. <span class="el-dropdown-link userinfo-inner"><img :src="this.sysUserAvatar" /> {{sysUserName}}</span>
  16. <el-dropdown-menu slot="dropdown">
  17. <el-dropdown-item>我的消息</el-dropdown-item>
  18. <el-dropdown-item>设置</el-dropdown-item>
  19. <el-dropdown-item divided @click.native="logout">退出登录</el-dropdown-item>
  20. </el-dropdown-menu>
  21. </el-dropdown>
  22. </el-col>
  23. </el-col>
  24. <el-col :span="24" class="main">
  25. <aside :class="collapsed?'menu-collapsed':'menu-expanded'">
  26. <!--导航菜单-->
  27. <el-menu :default-active="$route.path" class="el-menu-vertical-demo" @open="handleopen" @close="handleclose" @select="handleselect"
  28. unique-opened router v-show="!collapsed">
  29. <template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">
  30. <el-submenu :index="index+''" v-if="!item.leaf">
  31. <template slot="title">
  32. <i :class="item.iconCls"></i>{{item.name}}
  33. </template>
  34. <el-menu-item v-for="child in item.children" :index="child.path" :key="child.path" v-if="!child.hidden">{{child.name}}</el-menu-item>
  35. </el-submenu>
  36. <el-menu-item v-if="item.leaf&&item.children.length>0" :index="item.children[0].path"><i :class="item.iconCls"></i>{{item.children[0].name}}</el-menu-item>
  37. </template>
  38. </el-menu>
  39. <!--导航菜单-折叠后-->
  40. <ul class="el-menu el-menu-vertical-demo collapsed" v-show="collapsed" ref="menuCollapsed">
  41. <li v-for="(item,index) in $router.options.routes" v-if="!item.hidden" class="el-submenu item">
  42. <template v-if="!item.leaf">
  43. <div class="el-submenu__title" style="padding-left: 20px;" @mouseover="showMenu(index,true)" @mouseout="showMenu(index,false)"><i :class="item.iconCls"></i></div>
  44. <ul class="el-menu submenu" :class="'submenu-hook-'+index" @mouseover="showMenu(index,true)" @mouseout="showMenu(index,false)">
  45. <li v-for="child in item.children" v-if="!child.hidden" :key="child.path" class="el-menu-item" style="padding-left: 40px;" :class="$route.path==child.path?'is-active':''" @click="$router.push(child.path)">{{child.name}}</li>
  46. </ul>
  47. </template>
  48. <template v-else>
  49. <li class="el-submenu">
  50. <div class="el-submenu__title el-menu-item" style="padding-left: 20px;height: 56px;line-height: 56px;padding: 0 20px;" :class="$route.path==item.children[0].path?'is-active':''" @click="$router.push(item.children[0].path)"><i :class="item.iconCls"></i></div>
  51. </li>
  52. </template>
  53. </li>
  54. </ul>
  55. </aside>
  56. <section class="content-container">
  57. <div class="grid-content bg-purple-light">
  58. <el-col :span="24" class="breadcrumb-container">
  59. <!--<strong class="title">{{$route.name}}</strong>-->
  60. <el-breadcrumb separator="/" class="breadcrumb-inner">
  61. <el-breadcrumb-item v-for="item in $route.matched" :key="item.path">
  62. {{ item.name }}
  63. </el-breadcrumb-item>
  64. </el-breadcrumb>
  65. </el-col>
  66. <el-col :span="24" class="content-wrapper">
  67. <transition name="fade" mode="out-in">
  68. <router-view></router-view>
  69. </transition>
  70. </el-col>
  71. </div>
  72. </section>
  73. </el-col>
  74. </el-row>
  75. </template>
  76. <script>
  77. export default {
  78. data() {
  79. return {
  80. sysName:'Simple',
  81. logo:'dist/resources/img/logo.png',
  82. collapsed:false,
  83. sysUserName: '',
  84. sysUserAvatar: '',
  85. form: {
  86. name: '',
  87. region: '',
  88. date1: '',
  89. date2: '',
  90. delivery: false,
  91. type: [],
  92. resource: '',
  93. desc: ''
  94. }
  95. }
  96. },
  97. methods: {
  98. onSubmit() {
  99. console.log('submit!');
  100. },
  101. handleopen() {
  102. //console.log('handleopen');
  103. },
  104. handleclose() {
  105. //console.log('handleclose');
  106. },
  107. handleselect: function (a, b) {
  108. },
  109. //退出登录
  110. logout: function () {
  111. var _this = this;
  112. this.$confirm('确认退出吗?', '提示', {
  113. //type: 'warning'
  114. }).then(() => {
  115. sessionStorage.removeItem('user');
  116. _this.$router.push('/login');
  117. }).catch(() => {
  118. });
  119. },
  120. //折叠导航栏
  121. collapse:function(){
  122. this.collapsed=!this.collapsed;
  123. },
  124. showMenu(i,status){
  125. this.$refs.menuCollapsed.getElementsByClassName('submenu-hook-'+i)[0].style.display=status?'block':'none';
  126. }
  127. },
  128. mounted() {
  129. var user = sessionStorage.getItem('user');
  130. if (user) {
  131. user = JSON.parse(user);
  132. this.sysUserName = user.name || '';
  133. this.sysUserAvatar = user.avatar || '';
  134. }
  135. }
  136. }
  137. </script>
  138. <style scoped >
  139. .container {
  140. position: absolute;
  141. top: 0px;
  142. bottom: 0px;
  143. width: 100%;
  144. }
  145. .container .header {
  146. height: 60px;
  147. line-height: 60px;
  148. background: #20a0ff;
  149. color: #fff;
  150. }
  151. .container .header .userinfo {
  152. text-align: right;
  153. padding-right: 35px;
  154. float: right;
  155. }
  156. .container .header .userinfo .userinfo-inner {
  157. cursor: pointer;
  158. color: #fff;
  159. }
  160. .container .header .userinfo .userinfo-inner img {
  161. width: 40px;
  162. height: 40px;
  163. border-radius: 20px;
  164. margin: 10px 0px 10px 10px;
  165. float: right;
  166. }
  167. .container .header .logo {
  168. height: 60px;
  169. font-size: 22px;
  170. padding-left: 20px;
  171. padding-right: 20px;
  172. border-color: rgba(238, 241, 146, 0.3);
  173. border-right-width: 1px;
  174. border-right-style: solid;
  175. }
  176. .container .header .logo img {
  177. width: 40px;
  178. float: left;
  179. margin: 10px 10px 10px 18px;
  180. }
  181. .container .header .logo .txt {
  182. color: #fff;
  183. }
  184. .container .header .logo-collapsed {
  185. padding: 0;
  186. font-size: 22px;
  187. padding-left: 0px;
  188. padding-top: 10px;
  189. border-color: rgba(238, 241, 146, 0.3);
  190. border-right-width: 1px;
  191. border-right-style: solid;
  192. }
  193. .container .header .logo-collapsed img {
  194. width: 60px;
  195. float: left;
  196. margin: 0px;
  197. }
  198. .container .header .logo-collapsed .txt {
  199. color: #fff;
  200. }
  201. .container .header .logo-width {
  202. width: 230px;
  203. }
  204. .container .header .logo-collapse-width {
  205. width: 60px;
  206. }
  207. .container .header .tools {
  208. padding: 0px 23px;
  209. width: 14px;
  210. height: 60px;
  211. line-height: 60px;
  212. cursor: pointer;
  213. }
  214. .container .main {
  215. display: flex;
  216. position: absolute;
  217. top: 60px;
  218. bottom: 0px;
  219. overflow: hidden;
  220. }
  221. .container .main aside {
  222. flex: 0 0 230px;
  223. width: 230px;
  224. }
  225. .container .main aside .el-menu {
  226. height: 100%;
  227. }
  228. .container .main aside .collapsed {
  229. width: 60px;
  230. }
  231. .container .main aside .collapsed .item {
  232. position: relative;
  233. }
  234. .container .main aside .collapsed .submenu {
  235. position: absolute;
  236. top: 0px;
  237. left: 60px;
  238. z-index: 99999;
  239. height: auto;
  240. display: none;
  241. }
  242. .container .main .menu-collapsed {
  243. flex: 0 0 60px;
  244. width: 60px;
  245. }
  246. .container .main .menu-expanded {
  247. flex: 0 0 230px;
  248. width: 230px;
  249. }
  250. .container .main .content-container {
  251. flex: 1;
  252. overflow-y: scroll;
  253. padding: 20px;
  254. }
  255. .container .main .content-container .breadcrumb-container .title {
  256. width: 200px;
  257. float: left;
  258. color: #475669;
  259. }
  260. .container .main .content-container .breadcrumb-container .breadcrumb-inner {
  261. float: left;
  262. padding-bottom: 10px;
  263. }
  264. .container .main .content-container .content-wrapper {
  265. background-color: #fff;
  266. box-sizing: border-box;
  267. }
  268. </style>

此时编译运行可以看到下面的页面,由于还没有开发子页面,所以只显示主页和菜单: 

添加模拟的后端API

这里模拟用户管理的功能。为.net开发,具体的开发流程不在赘述。 
UserInfo.cs

 
 
  1. public class UserInfo
  2. {
  3. public string uuid { get; set; }
  4. public string login_name { get; set; }
  5. public string real_name { get; set; }
  6. public string email { get; set; }
  7. public string birthday { get; set; }
  8. public int age { get; set; }
  9. }

UserInfoRepository.cs

 
 
  1. public class UserInfoRepository
  2. {
  3. static List<UserInfo> db_users = new List<UserInfo>() {
  4. };
  5. public static IList<UserInfo> LoadAll() {
  6. return db_users;
  7. }
  8. public static string Insert(UserInfo u)
  9. {
  10. u.uuid = Guid.NewGuid().ToString();
  11. db_users.Add(u);
  12. return u.uuid;
  13. }
  14. public static string Update(UserInfo u)
  15. {
  16. db_users.Remove(db_users.Where(m => m.uuid.Equals(u.uuid)).FirstOrDefault());
  17. db_users.Add(u);
  18. return u.uuid;
  19. }
  20. public static UserInfo Get(string uuid) {
  21. return db_users.Where(m=>m.uuid.Equals(uuid)).FirstOrDefault();
  22. }
  23. public static void Delete(string uuid)
  24. {
  25. var u = db_users.Where(m => m.uuid.Equals(uuid)).FirstOrDefault();
  26. db_users.Remove(u);
  27. }
  28. }

UserController.cs

 
 
  1. [Route("api/[controller]")]
  2. public class UsersController : Controller
  3. {
  4. [HttpGet]
  5. public string Get()
  6. {
  7. return JsonConvert.SerializeObject(UserInfoRepository.LoadAll());
  8. }
  9. [HttpGet("{uuid}")]
  10. public string Get(string uuid)
  11. {
  12. return JsonConvert.SerializeObject(UserInfoRepository.Get(uuid));
  13. }
  14. [HttpGet("p/")]
  15. public string Get(string name, int page = 1, int pagesize = 20)
  16. {
  17. long count = 0;
  18. var list = UserInfoRepository.LoadAll();
  19. count = list.Count;
  20. var obj = new
  21. {
  22. total = count,
  23. list = list.Where(m => m.real_name.Equals(name)).Skip((page - 1) * pagesize).Take(pagesize)
  24. };
  25. return JsonConvert.SerializeObject(obj);
  26. }
  27. [HttpPost]
  28. public void Post([FromBody]UserInfo user)
  29. {
  30. UserInfoRepository.Insert(user);
  31. }
  32. [HttpPut]
  33. public void Put([FromBody]UserInfo user)
  34. {
  35. UserInfoRepository.Update(user);
  36. }
  37. [HttpDelete("{uuid}")]
  38. public void Delete(string uuid)
  39. {
  40. UserInfoRepository.Delete(uuid);
  41. }
  42. }

添加列表页面

添加内容包括,users.vue页面、路由以及将登录后的默认页面修改为users 
users.vue

 
 
  1. <template>
  2. <section>
  3. <!--工具条-->
  4. <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
  5. <el-form :inline="true" :model="filters">
  6. <el-form-item>
  7. <el-input v-model="filters.name" placeholder="姓名"></el-input>
  8. </el-form-item>
  9. <el-form-item>
  10. <el-button type="primary" v-on:click="search">查询</el-button>
  11. </el-form-item>
  12. <el-form-item>
  13. <el-button type="success" v-on:click="add">添加</el-button>
  14. </el-form-item>
  15. </el-form>
  16. </el-col>
  17. <!--列表-->
  18. <el-table :data="infos" highlight-current-row v-loading="listLoading" style="width: 100%;">
  19. <el-table-column type="selection" width="55">
  20. </el-table-column>
  21. <el-table-column type="index" width="60">
  22. </el-table-column>
  23. <el-table-column prop="login_name" label="登录名" sortable>
  24. </el-table-column>
  25. <el-table-column prop="real_name" label="真实姓名" sortable>
  26. </el-table-column>
  27. <el-table-column prop="email" label="邮箱" sortable>
  28. </el-table-column>
  29. <el-table-column prop="birthday" label="生日" sortable>
  30. </el-table-column>
  31. <el-table-column prop="age" label="年龄" sortable>
  32. </el-table-column>
  33. <el-table-column label="操作" width="150">
  34. <template scope="scope">
  35. <el-button type="warning" size="small" @click="edit(scope.$index, scope.row)">编辑</el-button>
  36. <el-button type="danger" size="small" @click="del(scope.$index, scope.row)">删除</el-button>
  37. </template>
  38. </el-table-column>
  39. </el-table>
  40. <el-col :span="24" class="toolbar">
  41. <el-pagination layout="prev, pager, next" @current-change="handleCurrentChange" :page-size="10" :total="total" style="float:left;"></el-pagination>
  42. </el-col>
  43. </section>
  44. </template>
  45. <script>
  46. import ElCol from "element-ui/packages/col/src/col";
  47. export default {
  48. components: {ElCol}, data(){
  49. return {
  50. filters:{
  51. name:'',
  52. },
  53. infos:[],
  54. listLoading: false,
  55. page:1,
  56. total:0
  57. };
  58. },
  59. methods:{
  60. search:function(){
  61. var _self =this;
  62. _self.listLoading=true;
  63. this.$http.get('/api/users/s',{
  64. params:{
  65. name:_self.filters.name,
  66. page:_self.page,
  67. pagesize:10
  68. }
  69. }).then((response)=>{
  70. _self.infos=response.data.list;
  71. _self.total=response.data.total;
  72. _self.listLoading=false;
  73. },(response)=>{
  74. }).catch((response)=>{});
  75. },
  76. add:function(){
  77. this.$router.push('/useradd')
  78. },
  79. edit:function(index,row){
  80. this.$router.push(
  81. { path: '/useradd', query: { uuid: row.uuid }}
  82. )
  83. },
  84. del:function(index,row){
  85. var _self =this;
  86. this.$confirm('确定删除吗?', '提示', {
  87. confirmButtonText: '确定',
  88. cancelButtonText: '取消',
  89. type: 'warning'
  90. }).then(() => {
  91. _self.$http.delete('/api/users/'+row.Uuid).then((res)=>{
  92. _self.search();
  93. _self.$message({
  94. type: 'success',
  95. message: '删除成功!'
  96. });
  97. },(res)=>{
  98. _self.$message({
  99. type: 'srror',
  100. message: '删除失败!'
  101. });
  102. }).catch();
  103. });
  104. },
  105. handleCurrentChange:function(p){
  106. this.page = p;
  107. this.search();
  108. }
  109. },
  110. mounted() {
  111. this.search();
  112. }
  113. }
  114. </script>

添加路由,在系统管理的children下添加users

 
 
  1. {
  2. path: '/',
  3. component: Home,
  4. name: '系统管理',
  5. iconCls: 'el-icon-setting',//图标样式class
  6. children: [
  7. {path: '/users', component: Users, name: '用户管理' }
  8. ]
  9. }

同样的方式增加用户添加和编辑页面,完成用户管理小模块。

总结

我们完成了在.net core下基于vue开发单页应用,这种方法实际上是利用webpack的打包功能,编译时将应用打包好,.net应用的cshtml页面再引用已打包的js文件。方案缺陷之一为:每次修改页面都需要重新build,不能同使用Node开发时实时预览页面,在实际的项目中可能并不会使用这种方式,仅供折腾。下面附上源码地址: 
https://github.com/wenjq0911/simple.git

源博客地址使用的leanote,地址在此  http://blog.leanote.com/post/wenjq0911@gmail.com

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值