python web开发实战(7)--前端页面编写

    技术2022-07-21  90

    1、通过前面的课程我们把一个web application的框架结构都搭好了,后续就是前端页面的编写,让显示的页面更加丰度。

    我们前端渲染用uikit,uikit首页下载打包的资源文件,解压到static文件夹下

    其中awesome开头的文件以及js下有几个文件是我们自定义的,可以直接拷贝复制。

    2、templates文件夹下页面添加

    所有页面都加载的基础模板 __base__.html

    <!DOCTYPE html> <!--处理分页导航栏代码--> {% macro pagination(page) %} <ul class="uk-pagination uk-flex-center uk-margin-medium-top uk-margin-large-bottom"> {% if page.has_previous %} <li><a href="?page={{ page.page_index - 1 }}"><span uk-pagination-previous></span></a></li> {% else %} <li class="uk-disabled"><a href="#"><span uk-pagination-previous></span></a></li> {% endif %} <li class="uk-active"><span>{{ page.page_index }}</span></li> {% if page.has_next %} <li><a href="?page={{ page.page_index + 1 }}"><span uk-pagination-next></span></a></li> {% else %} <li class="uk-disabled"><a href="#"><span uk-pagination-next></span></a></li> {% endif %} </ul> {% endmacro %} <!--导航页代码--> <html> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="HandheldFriendly" content="True"> <meta name="viewport" content="width=device-width,initial-scale=0.9,minimum-scale=0.9,maximum-scale=0.9,user-scalable=no"> <meta name="wap-font-scale" content="no"> <!--jinja2 meta块--> {% block meta %}<!-- block meta -->{% endblock %} <!--jinja2 title块--> <title>{% block title %} ? {% endblock %}| AwesomeLeeYYBlog</title> <link rel="stylesheet" href="/static/css/uikit.min.css"> <link rel="stylesheet" href="/static/css/awesome.css" /> <script src="/static/js/jquery.min.js"></script> <script src="/static/js/sha1.min.js"></script> <script src="/static/js/uikit.min.js"></script> <script src="/static/js/icons.min.js"></script> <script src="/static/js/sticky.min.js"></script> <script src="/static/js/vue.min.js"></script> <script src="/static/js/awesome.js"></script> <!--jinja2 beforehead块--> {% block beforehead %}<!-- before head -->{% endblock %} </head> <!--导航页正文内容--> <body> <!--"uk-"开头的都是UIkit里的组件,具体请参考UIkit官网的Documents详解--> <!--uk-visible@m是大于中等尺寸屏幕时显示的UI--> <div class="uk-margin uk-visible@m" style="background-color:rgba(100,150,185,0);"> <div class="uk-container uk-container-medium"> <!--导航栏UI--> <nav class="uk-navbar-container" uk-navbar style="background-color:rgba(255,255,255,0);"> <div class="uk-navbar-left uk-margin-medium-top uk-margin-medium-bottom"> <a class="uk-navbar-item uk-logo uk-margin-left" href="/"> <!--此处uk-icon为图标,读者可以选UIkit自带icon,也可以添加自定义icon重新打包uk-icon.js,详见官网Documentation--> <span class="uk-icon uk-margin-small-right" uk-icon="pagekit" ratio="2"></span> LEEYY </a> <ul class="uk-navbar-nav"> <li><a href="/"> Article | 日志</a></li> <li><a href="https://blog.csdn.net/BurstLinking/article/details/107023806"> Tutorial | 教程</a></li> <li><a href="https://github.com/burstlink/awesome-python3-webapp2/"> SourceCode | 源码</a></li> </ul> </div> <div class="uk-navbar-right uk-margin-medium-top uk-margin-medium-bottom"> <ul class="uk-navbar-nav"> {% if __user__ %} <li> <a href="#0"> {{ __user__.name }}</a> <div class="uk-navbar-dropdown"> <ul class="uk-nav uk-navbar-dropdown-nav"> <li><a href="/manage/"> Manage</a></li> <li><a href="/signout"> Logout</a></li> </ul> </div> </li> {% else %} <li><a href="/signin"> Login | 登陆</a></li> <li><a href="/register"> Register | 注册</a></li> {% endif %} </ul> </div> </nav> </div> </div> <!--uk-hidden@m是小于中等尺寸屏幕时显示的UI--> <nav class="uk-navbar-container uk-margin-medium uk-hidden@m" uk-navbar style="background-color:rgba(255,255,255,0);"> <div class="uk-navbar-left"> <a class="uk-navbar-item uk-logo" href="/"> <span class="uk-icon uk-margin-small-right" uk-icon="pagekit" ratio="2"></span> LEEYY </a> </div> <div class="uk-navbar-right"> <ul class="uk-navbar-nav"> <li> <a class="uk-navbar-toggle" uk-toggle="target: #offcanvas-nav" uk-navbar-toggle-icon></a> <div id="offcanvas-nav" uk-offcanvas="overlay: true; flip: true"> <div class="uk-offcanvas-bar uk-flex uk-flex-column"> <ul class="uk-nav uk-nav-default uk-margin-auto-vertical"> <li><a href="/"> Article | 日志</a></li> <li><a href="https://blog.csdn.net/BurstLinking/article/details/107023806"> Tutorial | 教程</a></li> <li><a href="https://github.com/burstlink/awesome-python3-webapp2/"> SourceCode | 源码</a></li> {% if __user__ %} <li><a href="/manage/">Manage | 管理</a></li> <li><a href="/signout"> Logout | 注销</a></li> {% else %} <li><a href="/signin"> Login | 登陆</a></li> <li><a href="/register"> Register | 注册</a></li> {% endif %} </ul> </div> </div> </li> </ul> </div> </nav> <div class="uk-container uk-container-medium"> <!-- jinja2 content块 --> {% block content %} {% endblock %} </div> <!-- 页面底部图标栏和网站信息 --> <div class="uk-margin-medium"> <div class="uk-container uk-container-center uk-text-center"> <p> <a target="_blank" href="https://github.com/burstlink" class="uk-icon-button uk-margin-small-right" ratio="1.1" uk-icon="github"></a> <a target="_blank" href="#" class="uk-icon-button uk-margin-small-right" ratio="1.1" uk-icon="instagram"></a> <a target="_blank" href="#" class="uk-icon-button uk-margin-small-right" ratio="1.2" uk-icon="twitter"></a> <a target="_blank" href="#" class="uk-icon-button uk-margin-small-right" ratio="1.2" uk-icon="google-plus"></a> <a target="_blank" href="#" class="uk-icon-button uk-margin-small-right" ratio="1.1" uk-icon="linkedin"></a> </p> <p class="uk-text-meta" style="line-height: 10px; padding: 10px 0; margin: 8px 0;">Powered by <a href="/">AwesomePythonWebBlog!</a> Copyright © 2020.</p> <p class="uk-text-meta" style="line-height: 0px; padding: 0px 0; margin: 0px 0;"><a href="/" target="_blank">Leeyy</a>. All rights reserved.</p> </div> </div> </body> </html>

    blog.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}{{ blog.name }}{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交日志评论相关数据--> <script> var comment_url = '/api/blogs/{{ blog.id }}/comments'; $(function () { var $form = $('#form-comment'); $form.submit(function (e) { e.preventDefault(); $form.showFormError(''); var content = $form.find('textarea').val().trim(); if (content==='') { return $form.showFormError('请输入评论内容!'); } $form.postJSON(comment_url, { content: content }, function (err, result) { if (err) { return $form.showFormError(err); } refresh(); }); }); }); </script> {% endblock %} <!--jinja2 content 块内容替换--> {% block content %} <div class="uk-grid uk-visible@m"> <div class="uk-width-3-4"> <!--日志内容详情--> <article class="uk-article"> <h2>{{ blog.name }}</h2> <p class="uk-article-meta">发表于{{ blog.created_at|datetime }}</p> <p>{{ blog.html_content|safe }}</p> </article> <hr> <!--日志评论区--> {% if __user__ %} <h3>发表评论</h3> <article class="uk-comment"> <header class="uk-comment-header"> <img class="uk-comment-avatar uk-border-circle" width="50" height="50" src="{{ __user__.image }}"> <h4 class="uk-comment-title">{{ __user__.name }}</h4> </header> <div class="uk-comment-body"> <form id="form-comment" class="uk-form"> <fieldset class="uk-fieldset"> <div class="uk-alert uk-alert-danger uk-hidden"></div> <div class="uk-margin"> <textarea class="uk-textarea" rows="6" placeholder="说点什么吧"></textarea> </div> <div class="uk-margin"> <button type="submit" class="uk-button uk-button-primary"> 发表评论</button> </div> </fieldset> </form> </div> </article> <hr> {% endif %} <h3>最新评论</h3> <ul class="uk-comment-list"> {% for comment in comments %} <li> <article class="uk-comment"> <header class="uk-comment-header"> <img class="uk-comment-avatar uk-border-circle" width="50" height="50" src="{{ comment.user_image }}"> <h4 class="uk-comment-title">{{ comment.user_name }} {% if comment.user_id==blog.user_id %}(作者){% endif %}</h4> <p class="uk-comment-meta">{{ comment.created_at|datetime }}</p> </header> <div class="uk-comment-body"> {{ comment.html_content|safe }} </div> </article> </li> {% else %} <p>还没有人评论...</p> {% endfor %} </ul> </div> <div class="uk-width-1-4 uk-visible@m"> <div class="uk-card uk-card-default"> <div class="uk-card-body"> <div class="uk-text-center"> <img class="uk-border-circle" width="120" height="120" src="{{ blog.user_image }}"> <h4>{{ blog.user_name }}</h4> </div> </div> </div> </div> </div> <div class="uk-hidden@m"> <article class="uk-article"> <h3>{{ blog.name }}</h3> <p class="uk-article-meta">{{ blog.user_name }} 发表于{{ blog.created_at|datetime }}</p> <p>{{ blog.html_content|safe }}</p> </article> <hr> {% if __user__ %} <h4>发表评论</h4> <article class="uk-comment"> <header class="uk-comment-header"> <img class="uk-comment-avatar uk-border-circle" width="50" height="50" src="{{ __user__.image }}"> <h5 class="uk-comment-title">{{ __user__.name }}</h5> </header> <div class="uk-comment-body"> <form id="form-comment" class="uk-form"> <fieldset class="uk-fieldset"> <div class="uk-alert uk-alert-danger uk-hidden"></div> <div class="uk-margin"> <textarea class="uk-textarea" rows="6" placeholder="说点什么吧"></textarea> </div> <div class="uk-margin"> <button type="submit" class="uk-button uk-button-primary"> 发表评论</button> </div> </fieldset> </form> </div> </article> <hr> {% endif %} <h4>最新评论</h4> <ul class="uk-comment-list"> {% for comment in comments %} <li> <article class="uk-comment"> <header class="uk-comment-header"> <img class="uk-comment-avatar uk-border-circle" width="50" height="50" src="{{ comment.user_image }}"> <h5 class="uk-comment-title">{{ comment.user_name }} {% if comment.user_id==blog.user_id %}(作者){% endif %}</h5> <p class="uk-comment-meta">{{ comment.created_at|datetime }}</p> </header> <div class="uk-comment-body"> {{ comment.html_content|safe }} </div> </article> </li> {% else %} <p>还没有人评论...</p> {% endfor %} </ul> </div> {% endblock %}

    blogs.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}LEEYY{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} {% endblock %} <!--jinja2 content 块内容替换--> {% block content %} <!--uk-visible@m是大于中等尺寸屏幕时显示的UI--> <!--日志列表内容--> <div class="uk-grid uk-visible@m"> <div class="uk-width-3-4"> {% for blog in blogs %} <article class="uk-article"> <h3><a href="/blog/{{ blog.id }}">{{ blog.name }}</a></h3> <p class="uk-article-meta">发表于{{ blog.created_at|datetime }}</p> <p>{{ blog.summary }}</p> <p><a href="/blog/{{ blog.id }}">继续阅读 <i class="uk-icon-angle-double-right"></i></a></p> </article> <hr> {% endfor %} <!--分页导航栏,在父模板的开头定义过--> {{ pagination(page) }} </div> <!--uk-visible@m是大于中等尺寸屏幕时显示的UI--> <!--右边侧导航栏--> <div class="uk-width-1-4 uk-visible@m"> <h4>站内搜索</h4> <FORM method=GET action="https://www.google.com/search"> <div class="uk-inline"> <a class="uk-form-icon uk-form-icon-flip" href="#" uk-icon="search"></a> <INPUT class="uk-input" TYPE=text name=q placeholder="站内搜索" size=31 maxlength=255 value=""> </div> <font size=-1> <INPUT TYPE=hidden name=domains value="/"><br> <INPUT TYPE=hidden name=sitesearch value="/"></br> </font> <button TYPE=submit name=btnG class="uk-button uk-button-default"> SEARCH</button> </FORM> <h4>亲密链接</h4> <ul class="uk-list uk-list-divider"> <li><a target="_blank" href="https://www.liaoxuefeng.com/wiki/1016959663602400">廖大的python教程</a></li> </ul> </div> </div> <!--uk-hidden@m是小于中等尺寸屏幕时显示的UI--> <!--移动屏幕时日志列表排版--> <div class="uk-hidden@m"> {% for blog in blogs %} <article class="uk-article"> <h5><a href="/blog/{{ blog.id }}">{{ blog.name }}</a></h5> <p class="uk-article-meta">发表于{{ blog.created_at|datetime }}</p> <p>{{ blog.summary }}</p> <p><a href="/blog/{{ blog.id }}">继续阅读 <i class="uk-icon-angle-double-right"></i></a></p> </article> <hr> {% endfor %} <!--分页导航栏,在父模板的开头定义过--> {{ pagination(page) }} </div> {% endblock %}

    manage_blog_edit.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}编辑日志{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交日志相关数据,包括创建新日志和修改旧日志--> <script> var ID = '{{ id }}', action = '{{ action }}'; function initVM(blog) { var vm = new Vue({ el: '#vm', data: blog, methods: { submit: function (event) { event.preventDefault(); var $form = $('#vm').find('form'); $form.postJSON(action, this.$data, function (err, r) { if (err) { $form.showFormError(err); } else { return location.assign('/manage/blogs'); } }); } } }); $('#vm').show(); } $(function () { if (ID) { getJSON('/api/blogs/' + ID, function (err, blog) { if (err) { return fatal(err); } $('#loading').hide(); initVM(blog); }); } else { $('#loading').hide(); initVM({ name: '', summary: '', content: '' }); } }); </script> {% endblock %} <!--jinja2 content 块内容替换,构建日志编写页面UI主要内容--> {% block content %} <div class="uk-grid"> <div class="uk-width-1-1 uk-margin-bottom"> <ul class="uk-breadcrumb"> <li><a href="/manage/comments">评论</a></li> <li><a href="/manage/blogs">日志</a></li> <li><a href="/manage/users">用户</a></li> </ul> </div> <div id="error" class="uk-width-1-1"> </div> <div id="loading" class="uk-width-1-1 uk-text-center"> <span><i class="uk-icon-spinner uk-icon-medium uk-icon-spin"></i> 正在加载...</span> </div> <div id="vm" class="uk-width-2-3"> <form v-on="submit: submit" class="uk-form-stacked"> <div class="uk-alert uk-alert-danger uk-hidden"></div> <div class="uk-margin-top"> <label class="uk-form-label">标题:</label> <div class="uk-form-controls"> <input v-model="name" name="name" type="text" placeholder="标题" class="uk-input uk-form-width-large"> </div> </div> <div class="uk-margin-top"> <label class="uk-form-label">摘要:</label> <div class="uk-form-controls"> <textarea v-model="summary" rows="4" name="summary" placeholder="摘要" class="uk-textarea" style="resize:none;"></textarea> </div> </div> <div class="uk-margin-top"> <label class="uk-form-label">内容:</label> <div class="uk-form-controls"> <textarea v-model="content" rows="12" name="content" placeholder="内容" class="uk-textarea" style="resize:none;"></textarea> </div> </div> <div class="uk-margin-top"> <button type="submit" class="uk-button uk-button-primary"><i class="uk-icon-save"></i> 保存</button> <a href="/manage/blogs" class="uk-button"><i class="uk-icon-times"></i> 取消</a> </div> </form> </div> </div> {% endblock %}

    manage_blogs.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}日志{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交日志管理操作相关数据--> <script> function initVM(data) { var vm = new Vue({ el: '#vm', data: { blogs: data.blogs, page: data.page }, methods: { previous: function () { gotoPage(this.page.page_index - 1); }, next: function () { gotoPage(this.page.page_index + 1); }, edit_blog: function (blog) { location.assign('/manage/blogs/edit?id=' + blog.id); }, delete_blog: function (blog) { if (confirm('确认要删除“' + blog.name + '”?删除后不可恢复!')) { postJSON('/api/blogs/' + blog.id + '/delete', function (err, r) { if (err) { return alert(err.message || err.error || err); } refresh(); }); } } } }); $('#vm').show(); } $(function() { getJSON('/api/blogs', { page: {{ page_index }} }, function (err, results) { if (err) { return fatal(err); } $('#loading').hide(); initVM(results); }); }); </script> {% endblock %} <!--jinja2 content 块内容替换--> {% block content %} <div class="uk-grid"> <div class="uk-width-1-1 uk-margin-bottom"> <ul class="uk-breadcrumb"> <li><a href="/manage/comments">评论</a></li> <li class="uk-active"><span>日志</span></li> <li><a href="/manage/users">用户</a></li> </ul> </div> <div id="error" class="uk-width-1-1"> </div> <div id="loading" class="uk-width-1-1 uk-text-center"> <span><i class="uk-icon-spinner uk-icon-medium uk-icon-spin"></i> 正在加载...</span> </div> <div id="vm" class="uk-width-1-1"> <a href="/manage/blogs/create" class="uk-button uk-button-primary"><i class="uk-icon-plus"></i> 新日志</a> <table class="uk-table uk-table-divider"> <thead> <tr> <th class="uk-table-expand uk-text-left"> 标题</th> <th class="uk-text-left">作者</th> <th class="uk-text-left">标签</th> <th class="uk-text-left">创建时间</th> <th class="uk-text-left">操作</th> </tr> </thead> <tbody> <tr v-repeat="blog: blogs" > <td> <a target="_blank" v-attr="href: '/blog/'+blog.id" v-text="blog.name"></a> </td> <td> <a target="_blank" v-attr="href: '/user/'+blog.user_id" v-text="blog.user_name"></a> </td> <td> <a target="_blank" v-attr="href: '/blogs/'+blog.tag" v-text="blog.tag"></a> </td> <td> <span v-text="blog.created_at.toDateTime()"></span> </td> <td> <a href="#0" v-on="click: edit_blog(blog)">编辑</a> <a href="#0" v-on="click: delete_blog(blog)">删除</a> </td> </tr> </tbody> </table> <div class="uk-width-1-1 uk-text-center"> <ul class="uk-pagination"> <li v-if="! page.has_previous" class="uk-disabled"><span><i uk-icon="chevron-left"></i></span></li> <li v-if="page.has_previous"><a v-on="click: previous()" href="#0"><i uk-icon="chevron-left"></i></a></li> <li class="uk-active"><span v-text="page.page_index"></span></li> <li v-if="! page.has_next" class="uk-disabled"><span><i uk-icon="chevron-right"></i></span></li> <li v-if="page.has_next"><a v-on="click: next()" href="#0"><i uk-icon="chevron-right"></i></a></li> </ul> </div> </div> </div> {% endblock %}

    manage_comments.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}评论{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交评论管理操作相关数据--> <script> function initVM(data) { $('#vm').show(); var vm = new Vue({ el: '#vm', data: { comments: data.comments, page: data.page }, methods: { previous: function () { gotoPage(this.page.page_index - 1); }, next: function () { gotoPage(this.page.page_index + 1); }, delete_comment: function (comment) { var content = comment.content.length > 20 ? comment.content.substring(0, 20) + '...' : comment.content; if (confirm('确认要删除评论“' + comment.content + '”?删除后不可恢复!')) { postJSON('/api/comments/' + comment.id + '/delete', function (err, r) { if (err) { return error(err); } refresh(); }); } } } }); } $(function() { getJSON('/api/comments', { page: {{ page_index }} }, function (err, results) { if (err) { return fatal(err); } $('#loading').hide(); initVM(results); }); }); </script> {% endblock %} <!--jinja2 content 块内容替换--> {% block content %} <div class="uk-width-1-1 uk-margin-bottom"> <ul class="uk-breadcrumb"> <li class="uk-active"><span>评论</span></li> <li><a href="/manage/blogs">日志</a></li> <li><a href="/manage/users">用户</a></li> </ul> </div> <div id="error" class="uk-width-1-1"> </div> <div id="loading" class="uk-width-1-1 uk-text-center"> <span><i class="uk-icon-spinner uk-icon-medium uk-icon-spin"></i> 正在加载...</span> </div> <div id="vm" class="uk-width-1-1"> <table class="uk-table uk-table-justify uk-table-divider"> <thead> <tr> <th class="uk-text-left uk-width-small">作者</th> <th class="uk-text-left">内容</th> <th class="uk-text-left uk-table-expand">创建时间</th> <th class="uk-text-left uk-width-small">操作</th> </tr> </thead> <tbody> <tr v-repeat="comment: comments" > <td> <span v-text="comment.user_name"></span> </td> <td> <span v-text="comment.content"></span> </td> <td> <span v-text="comment.created_at.toDateTime()"></span> </td> <td> <a href="#0" v-on="click: delete_comment(comment)">删除</a> </td> </tr> </tbody> </table> <div class="uk-width-1-1 uk-text-center"> <ul class="uk-pagination"> <li v-if="! page.has_previous" class="uk-disabled"><span><i uk-icon="chevron-left"></i></span></li> <li v-if="page.has_previous"><a v-on="click: previous()" href="#0"><i uk-icon="chevron-left"></i></a></li> <li class="uk-active"><span v-text="page.page_index"></span></li> <li v-if="! page.has_next" class="uk-disabled"><span><i uk-icon="chevron-right"></i></span></li> <li v-if="page.has_next"><a v-on="click: next()" href="#0"><i uk-icon="chevron-right"></i></a></li> </ul> </div> </div> {% endblock %}

    manage_users.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}用户{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交用户管理操作相关数据--> <script> function initVM(data) { $('#vm').show(); var vm = new Vue({ el: '#vm', data: { users: data.users, page: data.page }, methods: { previous: function () { gotoPage(this.page.page_index - 1); }, next: function () { gotoPage(this.page.page_index + 1); }, delete_user: function (user) { if (confirm('确认要删除用户“' + user.name + '”?删除后不可恢复!')) { postJSON('/api/users/' + user.id + '/delete', function (err, r) { if (err) { return error(err); } refresh(); }); } } } }); } $(function() { getJSON('/api/users', { page: {{ page_index }} }, function (err, results) { if (err) { return fatal(err); } $('#loading').hide(); initVM(results); }); }); </script> {% endblock %} <!--jinja2 content 块内容替换--> {% block content %} <div class="uk-grid"> <div class="uk-width-1-1 uk-margin-bottom"> <ul class="uk-breadcrumb"> <li><a href="/manage/comments">评论</a></li> <li><a href="/manage/blogs">日志</a></li> <li class="uk-active"><span>用户</span></li> </ul> </div> <div id="error" class="uk-width-1-1"> </div> <div id="loading" class="uk-width-1-1 uk-text-center"> <span><i class="uk-icon-spinner uk-icon-medium uk-icon-spin"></i> 正在加载...</span> </div> <div id="vm" class="uk-width-1-1"> <table class="uk-table uk-table-divider"> <thead> <tr> <th class="uk-table-expand uk-text-left">名字</th> <th class="uk-text-left">电子邮件</th> <th class="uk-text-left">注册时间</th> <th class="uk-text-left">操作</th> </tr> </thead> <tbody> <tr v-repeat="user: users"> <td> <span v-text="user.name"></span> <span v-if="user.admin" style="color:#d05">管理员</span> </td> <td> <a v-attr="href: 'mailto:'+user.email" v-text="user.email"></a> </td> <td> <span v-text="user.created_at.toDateTime()"></span> </td> <td> <a href="#0" v-on="click: delete_user(user)">删除</a> </td> </tr> </tbody> </table> <div class="uk-width-1-1 uk-text-center"> <ul class="uk-pagination"> <li v-if="! page.has_previous" class="uk-disabled"><span><i uk-icon="chevron-left"></i></span></li> <li v-if="page.has_previous"><a v-on="click: previous()" href="#0"><i uk-icon="chevron-left"></i></a></li> <li class="uk-active"><span v-text="page.page_index"></span></li> <li v-if="! page.has_next" class="uk-disabled"><span><i uk-icon="chevron-right"></i></span></li> <li v-if="page.has_next"><a v-on="click: next()" href="#0"><i uk-icon="chevron-right"></i></a></li> </ul> </div> </div> </div> {% endblock %}

    register.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}Register/注册{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交合格的注册信息数据--> <script> function validateEmail(email) { var re = /^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$/; return re.test(email.toLowerCase()); } $(function () { var vm = new Vue({ el: '#vm', data: { name: '', email: '', password1: '', password2: '' }, methods: { submit: function (event) { event.preventDefault(); var $form = $('#vm'); if (! this.name.trim()) { return $form.showFormError('NAME/请输入名字'); } if (! validateEmail(this.email.trim().toLowerCase())) { return $form.showFormError('CORRECT EMAIL/请输入正确的Email地址'); } if (this.password1.length < 6) { return $form.showFormError('PASSWORD AT LEAST 6 CHAR/口令长度至少为6个字符'); } if (this.password1 !== this.password2) { return $form.showFormError('PASSWORD INCONSIST/两次输入的口令不一致'); } var email = this.email.trim().toLowerCase(); $form.postJSON('/api/users', { name: this.name.trim(), email: email, passwd: CryptoJS.SHA1(email + ':' + this.password1).toString() }, function (err, r) { if (err) { return $form.showFormError(err); } return location.assign('/'); }); } } }); $('#vm').show(); }); </script> {% endblock %} <!--jinja2 content 块内容替换,构建注册页面UI主要内容--> {% block content %} <div class="uk-grid"> <div class="uk-width-1-1"> <h4>REGISTER/欢迎注册!</h4> <form id="vm" v-on="submit: submit" class="uk-form-stacked"> <div class="uk-alert uk-alert-danger uk-hidden"></div> <div class="uk-margin-top"> <label class="uk-form-label">NAME/名字:</label> <div class="uk-form-controls"> <input class="uk-input uk-form-width-medium" v-model="name" type="text" maxlength="50" placeholder="名字"> </div> </div> <div class="uk-margin-top"> <label class="uk-form-label">EMAIL/电子邮件:</label> <div class="uk-form-controls"> <input class="uk-input uk-form-width-medium" v-model="email" type="text" maxlength="50" placeholder="your-name@example.com"> </div> </div> <div class="uk-margin-top"> <label class="uk-form-label">PASSWORD/输入口令:</label> <div class="uk-form-controls"> <input class="uk-input uk-form-width-medium" v-model="password1" type="password" maxlength="50" placeholder="输入口令"> </div> </div> <div class="uk-margin"> <label class="uk-form-label">REPEAT PASSWORD/重复口令:</label> <div class="uk-form-controls"> <input class="uk-input uk-form-width-medium" v-model="password2" type="password" maxlength="50" placeholder="重复口令"> </div> </div> <div class="uk-margin-large"> <button type="submit" class="uk-button uk-button-primary"><i class="uk-icon-user"></i>REGISTER/注册</button> </div> </form> </div> </div> {% endblock %}

    signin.html

    <!-- 继承父模板 '__base__.html' --> {% extends '__base__.html' %} <!--jinja2 title 块内容替换--> {% block title %}Signin/登陆{% endblock %} <!--jinja2 beforehead 块内容替换--> {% block beforehead %} <!--script中构建vue,向后端API提交登录验证信息数据--> <script> $(function() { var vmAuth = new Vue({ el: '#vm', data: { email: '', passwd: '' }, methods: { submit: function(event) { event.preventDefault(); var $form = $('#vm'); var email = this.email.trim().toLowerCase(); var data = { email: email, passwd: this.passwd==='' ? '' : CryptoJS.SHA1(email + ':' + this.passwd).toString() }; $form.postJSON('/api/authenticate', data, function(err, result) { if (! err) { location.assign('/'); } }); } } }); $('#vm').show(); }); </script> {% endblock %} <!--jinja2 content 块内容替换,构建登录页面UI主要内容--> {% block content %} <div class="uk-grid"> <div class="uk-width-1-1"> <h4>SIGNIN/欢迎登陆!</h4> <form id="vm" v-on="submit: submit" class="uk-form-stacked"> <div class="uk-alert uk-alert-danger uk-hidden"></div> <div class="uk-margin-top"> <label class="uk-form-label">EMAIL/电子邮箱:</label> <div class="uk-inline"> <span class="uk-form-icon" uk-icon="user"></span> <input class="uk-input uk-form-width-medium" v-model="email" type="text" maxlength="50" placeholder="Email"> </div> </div> <div class="uk-margin-top"> <label class="uk-form-label">PASSWORD/输入口令:</label> <div class="uk-inline"> <span class="uk-form-icon uk-form-icon-flip" uk-icon="lock"></span> <span class="uk-form-icon uk-form-icon-flip" uk-icon="lock"></span> <input class="uk-input uk-form-width-medium" v-model="passwd" type="password" maxlength="50" placeholder="口令"> </div> </div> <div class="uk-margin-top"> <button type="submit" class="uk-button uk-button-primary">SIGNIN/登陆</button> </div> </form> </div> </div> {% endblock %}

    2、app.py的文件补充所有的中间件

    async def init(loop): await orm.create_pool(loop=loop, **configs.db) app = web.Application(middlewares=[ logger_factory, auth_factory, data_factory, response_factory ])

    3、执行app.py文件,我们的blog网站就搭建好了

    完整代码参考:https://github.com/burstlink/awesome-python3-webapp2/tree/day14

    Processed: 0.013, SQL: 9