您的位置:首页 > 产品设计 > UI/UE

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

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


修改入口main.js

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

import App from './App'

import ElementUI from 'element-ui'

import 'element-ui/lib/theme-default/index.css'

import VueRouter from 'vue-router'

import store from './vuex/store'

import Vuex from<
4000
span class="pln" style="line-height:30px; word-wrap:break-word; color:rgb(72,72,76)"> 'vuex'

import VueSource from 'vue-resource'

import routes from './routes'

import 'font-awesome/css/font-awesome.min.css'



Vue.use(ElementUI)

Vue.use(VueRouter)

Vue.use(Vuex)

Vue.use(VueSource)


//创建路由实例

const router = new VueRouter({

routes

})

router.beforeEach((to, from, next) => {


//这里进行了简单的登录验证

//访问login时直接清除user

if (to.path == '/login') {

sessionStorage.removeItem('user');

}


let user = JSON.parse(sessionStorage.getItem('user'));

if (!user && to.path != '/login') {

next({ path: '/login' })

} else {

next()

}

})



new Vue({

router,

store,

render: h => h(App)

}).$mount('#app')

[/code]


修改App.vue

<template>

<div id="app">

<transition name="fade"

mode="out-in">

<router-view></router-view>

</transition>

</div>

</template>

<script>

export default {

name: 'app',

components: {

}

}

</script>

[/code]


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

login.vue
<template>

<el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px" class="demo-ruleForm login-container">

<h3 class="title">系统登录</h3>

<el-form-item prop="account">

<el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="账号"></el-input>

</el-form-item>

<el-form-item prop="checkPass">

<el-input type="password" v-model="ruleForm2.checkPass" auto-complete="off" placeholder="密码"></el-input>

</el-form-item>

<el-checkbox v-model="checked" checked class="remember">记住密码</el-checkbox>

<el-form-item style="width:100%;">

<el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit2" :loading="logining">登录</el-button>

</el-form-item>

</el-form>

</template>


<script>

export default {

data() {

return {

logining: false,

ruleForm2: {

account: 'admin',

checkPass: '123456'

},

rules2: {

account: [

{ required: true, message: '请输入账号', trigger: 'blur' },

//{ validator: validaePass }

],

checkPass: [

{ required: true, message: '请输入密码', trigger: 'blur' },

//{ validator: validaePass2 }

]

},

checked: true

};

},

methods: {

handleReset2() {

this.$refs.ruleForm2.resetFields();

},

handleSubmit2(ev) {

var _this = this;

this.$refs.ruleForm2.validate((valid) => {

if (valid) {

this.logining = true;

//NProgress.start();

var loginParams = { username: this.ruleForm2.account, password: this.ruleForm2.checkPass };


if (loginParams.username != 'admin') {

this.$message({

message: '用户不存在',

type: 'error'

});

this.logining = false;

return false;

}

if (loginParams.password != '123456') {

this.$message({

message: '密码不正确',

type: 'error'

});

this.logining = false;

return;

}

let user = {

id: 1,

username: 'admin',

password: '123456',

avatar: 'resources/img/user.png',

name: '管理员'

}

sessionStorage.setItem('user', JSON.stringify(user));

this.$router.push({ path: '/' });

} else {

return false;

}

});

}

}

}


</script>


<style  scoped>

.login-container {

/*box-shadow: 0 0px 8px 0 rgba(0, 0, 0, 0.06), 0 1px 0px 0 rgba(0, 0, 0, 0.02);*/

-webkit-border-radius: 5px;

border-radius: 5px;

-moz-border-radius: 5px;

background-clip: padding-box;

margin: 180px auto;

width: 350px;

padding: 35px 35px 15px 35px;

background: #fff;

border: 1px solid #eaeaea;

box-shadow: 0 0 25px #cac6c6;

}

.title {

margin: 0px auto 40px auto;

text-align: center;

color: #505458;

}


.remember {

margin: 0px 0px 35px 0px;

}

</style>

[/code]

home.vue
<template>

<el-row class="container">

<el-col :span="24" class="header">

<el-col :span="10" :class="collapsed?'logo-collapse-width logo-collapsed':'logo-width logo'">

{{collapsed?'':sysName}}

<!--<img :src="logo" v-show="collapsed" />-->

</el-col>

<el-col :span="10">

<div class="tools" @click.prevent="collapse">

<i class="fa fa-align-justify"></i>

        </div>

</el-col>

<el-col :span="4" class="userinfo">

<el-dropdown trigger="hover">

<span class="el-dropdown-link userinfo-inner"><img :src="this.sysUserAvatar" /> {{sysUserName}}</span>

<el-dropdown-menu slot="dropdown">

<el-dropdown-item>我的消息</el-dropdown-item>

<el-dropdown-item>设置</el-dropdown-item>

<el-dropdown-item divided @click.native="logout">退出登录</el-dropdown-item>

</el-dropdown-menu>

</el-dropdown>

</el-col>

</el-col>

<el-col :span="24" class="main">

<aside :class="collapsed?'menu-collapsed':'menu-expanded'">

<!--导航菜单-->

<el-menu :default-active="$route.path" class="el-menu-vertical-demo" @open="handleopen" @close="handleclose" @select="handleselect"

u
71ea4
nique-opened router v-show="!collapsed">

<template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">

<el-submenu :index="index+''" v-if="!item.leaf">

<template slot="title">

<i :class="item.iconCls"></i>{{item.name}}

</template>

<el-menu-item v-for="child in item.children" :index="child.path" :key="child.path" v-if="!child.hidden">{{child.name}}</el-menu-item>

</el-submenu>

<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>

</template>

</el-menu>

<!--导航菜单-折叠后-->

<ul class="el-menu el-menu-vertical-demo collapsed" v-show="collapsed" ref="menuCollapsed">

<li v-for="(item,index) in $router.options.routes" v-if="!item.hidden" class="el-submenu item">

<template v-if="!item.leaf">

<div class="el-submenu__title" style="padding-left: 20px;" @mouseover="showMenu(index,true)" @mouseout="showMenu(index,false)"><i :class="item.iconCls"></i></div>

<ul class="el-menu submenu" :class="'submenu-hook-'+index" @mouseover="showMenu(index,true)" @mouseout="showMenu(index,false)">

<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>

</ul>

    </template>

<template v-else>

<li class="el-submenu">

<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>

</li>

</template>

</li>

</ul>

</aside>

<section class="content-container">

<div class="grid-content bg-purple-light">

<el-col :span="24" class="breadcrumb-container">

<!--<strong class="title">{{$route.name}}</strong>-->

<el-breadcrumb separator="/" class="breadcrumb-inner">

<el-breadcrumb-item v-for="item in $route.matched" :key="item.path">

{{ item.name }}

</el-breadcrumb-item>

</el-breadcrumb>

</el-col>

<el-col :span="24" class="content-wrapper">

    <transition name="fade" mode="out-in">

    <router-view></router-view>

    </transition>

</el-col>

</div>

</section>

</el-col>

</el-row>

</template>


<script>

export default {

data() {

return {

sysName:'Simple',

logo:'dist/resources/img/logo.png',

collapsed:false,

sysUserName: '',

sysUserAvatar: '',

form: {

name: '',

region: '',

date1: '',

date2: '',

delivery: false,

type: [],

resource: '',

desc: ''

}

}

},

methods: {

onSubmit() {

console.log('submit!');

},

handleopen() {

//console.log('handleopen');

},

handleclose() {

//console.log('handleclose');

},

handleselect: function (a, b) {

},

//退出登录

logout: function () {

var _this = this;

this.$confirm('确认退出吗?', '提示', {

//type: 'warning'

}).then(() => {

            sessionStorage.removeItem('user');

_this.$router.push('/login');

}).catch(() => {


});



},

//折叠导航栏

collapse:function(){

this.collapsed=!this.collapsed;

},

showMenu(i,status){

this.$refs.menuCollapsed.getElementsByClassName('submenu-hook-'+i)[0].style.display=status?'block':'none';

}

},

mounted() {

var user = sessionStorage.getItem('user');

if (user) {

user = JSON.parse(user);

this.sysUserName = user.name || '';

this.sysUserAvatar = user.avatar || '';

}


}

}


</script>


<style scoped >

.container {

position: absolute;

top: 0px;

bottom: 0px;

width: 100%;

}


.container .header {

height: 60px;

line-height: 60px;

background: #20a0ff;

color: #fff;

}


.container .header .userinfo {

text-align: right;

padding-right: 35px;

float: right;

}


.container .header .userinfo .userinfo-inner {

cursor: pointer;

        color: #fff;

}


.container .header .userinfo .userinfo-inner img {

width: 40px;

height: 40px;

border-radius: 20px;

margin: 10px 0px 10px 10px;

        float: right;

}


.container .header .logo {

    height: 60px;

font-size: 22px;

padding-left: 20px;

padding-right: 20px;

border-color: rgba(238, 241, 146, 0.3);

border-right-width: 1px;

border-right-style: solid;

}


.container .header .logo img {

width: 40px;

float: left;

margin: 10px 10px 10px 18px;

}


.container .header .logo .txt {

        color: #fff;

}


.container .header .logo-collapsed {

padding: 0;

font-size: 22px;

padding-left: 0px;

padding-top: 10px;

border-color: rgba(238, 241, 146, 0.3);

border-right-width: 1px;

border-right-style: solid;

}


.container .header .logo-collapsed img {

width: 60px;

float: left;

margin: 0px;

}


.container .header .logo-collapsed .txt {

        color: #fff;

}


.container .header .logo-width {

width: 230px;

}


.container .header .logo-collapse-width {

width: 60px;

}


.container .header .tools {

padding: 0px 23px;

width: 14px;

    height: 60px;

    line-height: 60px;

cursor: pointer;

}


.container .main {

display: flex;

    position: absolute;

top: 60px;

    bottom: 0px;

overflow: hidden;

}


.container .main aside {

flex: 0 0 230px;

width: 230px;

}


.container .main aside .el-menu {

height: 100%;

}


.container .main aside .collapsed {

width: 60px;

}


.container .main aside .collapsed .item {

position: relative;

}


.container .main aside .collapsed .submenu {

    position: absolute;

                top: 0px;

left: 60px;

z-index: 99999;

height: auto;

display: none;

}


.container .main .menu-collapsed {

flex: 0 0 60px;

width: 60px;

}


.container .main .menu-expanded {

flex: 0 0 230px;

width: 230px;

}


.container .main .content-container {

flex: 1;

overflow-y: scroll;

padding: 20px;

}


.container .main .content-container .breadcrumb-container .title {

width: 200px;

float: left;

color: #475669;

}


.container .main .content-container .breadcrumb-container .breadcrumb-inner {

float: left;

padding-bottom: 10px;

}


.container .main .content-container .content-wrapper {

background-color: #fff;

box-sizing: border-box;

}

</style>

[/code]

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






添加模拟的后端API

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

UserInfo.cs
public class UserInfo

{

public string uuid { get; set; }

public string login_name { get; set; }

public string real_name { get; set; }

public string email { get; set; }

public string birthday { get; set; }

public int age { get; set; }

}

[/code]

UserInfoRepository.cs
public class UserInfoRepository

{

static List<UserInfo> db_users = new List<UserInfo>() {


};


public static IList<UserInfo> LoadAll() {

return db_users;

}

public static string Insert(UserInfo u)

{

u.uuid = Guid.NewGuid().ToString();

db_users.Add(u);

return u.uuid;

}

public static string Update(UserInfo u)

{

db_users.Remove(db_users.Where(m => m.uuid.Equals(u.uuid)).FirstOrDefault());

db_users.Add(u);

return u.uuid;

}

public static UserInfo Get(string uuid) {

return db_users.Where(m=>m.uuid.Equals(uuid)).FirstOrDefault();

}

public static void Delete(string uuid)

{

var u = db_users.Where(m => m.uuid.Equals(uuid)).FirstOrDefault();

db_users.Remove(u);

}


}

[/code]

UserController.cs
[Route("api/[controller]")]

public class UsersController : Controller

{

[HttpGet]

public string Get()

{

return JsonConvert.SerializeObject(UserInfoRepository.LoadAll());

}


[HttpGet("{uuid}")]

public string Get(string uuid)

{

return JsonConvert.SerializeObject(UserInfoRepository.Get(uuid));

}


[HttpGet("p/")]

public string Get(string name, int page = 1, int pagesize = 20)

{

long count = 0;

var list = UserInfoRepository.LoadAll();

count = list.Count;

var obj = new

{

total = count,

list = list.Where(m => m.real_name.Equals(name)).Skip((page - 1) * pagesize).Take(pagesize)

};

return JsonConvert.SerializeObject(obj);

}


[HttpPost]

public void Post([FromBody]UserInfo user)

{

UserInfoRepository.Insert(user);

}


[HttpPut]

public void Put([FromBody]UserInfo user)

{

UserInfoRepository.Update(user);

}


[HttpDelete("{uuid}")]

public void Delete(string uuid)

{

UserInfoRepository.Delete(uuid);

}

}

[/code]


添加列表页面

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

users.vue
<template>

<section>

<!--工具条-->

<el-col :span="24" class="toolbar" style="padding-bottom: 0px;">

<el-form :inline="true" :model="filters">

<el-form-item>

<el-input v-model="filters.name" placeholder="姓名"></el-input>

</el-form-item>

<el-form-item>

<el-button type="primary" v-on:click="search">查询</el-button>

</el-form-item>

<el-form-item>

<el-button type="success" v-on:click="add">添加</el-button>

</el-form-item>

        </el-form>

</el-col>

<!--列表-->

<el-table :data="infos" highlight-current-row v-loading="listLoading" style="width: 100%;">

<el-table-column type="selection" width="55">

</el-table-column>

<el-table-column type="index" width="60">

</el-table-column>

<el-table-column prop="login_name" label="登录名" sortable>

</el-table-column>

<el-table-column prop="real_name" label="真实姓名" sortable>

</el-table-column>

<el-table-column prop="email" label="邮箱" sortable>

</el-table-column>

<el-table-column prop="birthday" label="生日" sortable>

</el-table-column>

<el-table-column prop="age" label="年龄" sortable>

</el-table-column>

<el-table-column label="操作" width="150">

<template scope="scope">

<el-button type="warning" size="small" @click="edit(scope.$index, scope.row)">编辑</el-button>

<el-button type="danger" size="small" @click="del(scope.$index, scope.row)">删除</el-button>

</template>

</el-table-column>

</el-table>


<el-col :span="24" class="toolbar">

<el-pagination layout="prev, pager, next" @current-change="handleCurrentChange" :page-size="10" :total="total" style="float:left;"></el-pagination>

</el-col>

</section>

</template>

<script>

import ElCol from "element-ui/packages/col/src/col";

export default {

components: {ElCol}, data(){

return {

filters:{

name:'',

},

infos:[],

listLoading: false,

page:1,

total:0

};

},

methods:{

search:function(){

var _self =this;

_self.listLoading=true;

this.$http.get('/api/users/s',{

params:{

name:_self.filters.name,

page:_self.page,

pagesize:10

}

}).then((response)=>{

_self.infos=response.data.list;

_self.total=response.data.total;

_self.listLoading=false;

},(response)=>{


}).catch((response)=>{});


},

add:function(){

this.$router.push('/useradd')

},

edit:function(index,row){

this.$router.push(

{ path: '/useradd', query: { uuid: row.uuid }}

)

},

del:function(index,row){

var _self =this;

this.$confirm('确定删除吗?', '提示', {

confirmButtonText: '确定',

cancelButtonText: '取消',

type: 'warning'

}).then(() => {

_self.$http.delete('/api/users/'+row.Uuid).then((res)=>{

_self.search();

_self.$message({

type: 'success',

message: '删除成功!'

});

},(res)=>{

_self.$message({

type: 'srror',

message: '删除失败!'

});

}).catch();




});



},

handleCurrentChange:function(p){

this.page = p;

this.search();

}

},

mounted() {

this.search();

}

}

</script>

[/code]

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

path: '/',

component: Home,

name: '系统管理',

iconCls: 'el-icon-setting',//图标样式class

children: [

{path: '/users', component: Users, name: '用户管理' }

]

}

[/code]

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


总结

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

https://github.com/wenjq0911/simple.git

源博客地址使用的leanote,地址在此 http://blog.leanote.com/post/wenjq0911@gmail.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息