精华内容
下载资源
问答
  • mui模板移动端

    2018-05-31 16:46:53
    mui前端模板,框架实例。
  • 这是带登录和设置功能的mui模板项目,主要为了演示登录流程及设置界面div窗口切换效果;
  • 一、什么是模板引擎模板引擎是为了解决用户界面(显示)与业务数据(内容)分离而产生的。他可以生成特定格式的文档,常用的如格式如HTML、xml以及其他格式的文本格式。其工作模式如下:二、java常用的模板引擎有哪些jsp...

    一、什么是模板引擎

    模板引擎是为了解决用户界面(显示)与业务数据(内容)分离而产生的。他可以生成特定格式的文档,常用的如格式如HTML、xml以及其他格式的文本格式。其工作模式如下:

    72a3ff48510bf8d4d0040ac2258b2b59.png

    二、java常用的模板引擎有哪些

    jsp:是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。

    Thymeleaf : 主要渲染xml,HTML,HTML5而且与springboot整合。

    Velocity:不仅可以用于界面展示(HTML.xml等)还可以生成输入java代码,SQL语句等文本格式。

    FreeMarker:功能与Velocity差不多,但是语法更加强大,使用方便。

    三、常用模板引擎对比

    由于jsp与thymeleaf主要偏向于网页展示,而我们的需求是生成java代码与mybatis配置文件xml。顾这里只对Velocity与FreeMarker进行对比。

    示例:1万次调用动态生成大小为25kb左右的mybatisxml文件

    1、Velocity 模板文件

    namespace="${mapperName}">

    #foreach($map in $methodList)

    #if(${map.sqlType} == "select")

    id="${map.methodName}" resultType="${map.type}">

    ${map.desc}

    #elseif(${map.sqlType} == "insert")

    id="${map.methodName}" resultType="${map.type}">

    ${map.desc}

    #else

    #end

    #end

    2、Velocity java执行代码

    public class VelocityTest {

    public static void main(String[] args) {

    //得到VelocityEngine

    VelocityEngine ve = new VelocityEngine();

    //得到模板文件

    ve.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "/Users/huhaiquan/project/database-proxy/database-proxy-server/src/test/resources");

    ve.init();

    Template template = ve.getTemplate("velocity.vm", "UTF-8");

    VelocityContext data = new VelocityContext();

    // Map data = new HashMap<>();

    data.put("mapperName", "com.xxx.mapperName");

    List methodList = DataUtils.createData(200);

    data.put("methodList", methodList);

    //

    try {

    //生成xml

    //调用merge方法传入context

    int num = 1;

    int total=10000;

    for (int i=0;i

    StringWriter stringWriter = new StringWriter();

    long curr = System.currentTimeMillis();

    template.merge(data, stringWriter);

    long end = System.currentTimeMillis();

    // stringWriter.flush();

    total+=(end-curr);

    }

    System.out.println("total="+total+",vag="+(total*1f/num));

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    3、FreeMarker 模板文件

    namespace="${mapperName}">

    methodList as method>

    method.sqlType}" =="select">

    id="${method.methodName}" resultType="${method.type}">

    ${method.desc}

    method.sqlType}" == "insert">

    id="${method.methodName}" resultType="${method.type}">

    ${method.desc}

    #if>

    #list>

    4、FreeMarker 执行代码

    public class FreeMTest {

    public static Template getDefinedTemplate(String templateName) throws Exception{

    //配置类

    Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);

    cfg.setDirectoryForTemplateLoading(new File("/Users/huhaiquan/project/database-proxy/database-proxy-server/src/test/resources/"));

    cfg.setDefaultEncoding("UTF-8");

    cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

    return cfg.getTemplate(templateName);

    }

    public static void main(String[] args){

    Map data = new HashMap<>();

    data.put("mapperName", "com.xxx.mapperName");

    List methodList =DataUtils.createData(200);

    data.put("methodList", methodList);

    try {

    Template template = getDefinedTemplate("freemarker.ftl");

    long total = 0;

    int num = 10000;

    for (int i=0;i

    StringWriter stringWriter = new StringWriter();

    long curr = System.currentTimeMillis();

    template.process(data,stringWriter);

    long end = System.currentTimeMillis();

    total+=(end-curr);

    // stringWriter.flush();

    // System.out.println(stringWriter.toString());

    }

    System.out.println("total="+total+",vag="+(total/num));

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    四、特性对比

    项目名称版本10000次执行耗时社区支持文件语法功能Velocity2.112833ms较差较少简单,接近java一般FreeMarker2.3.284599ms较好较多简单强大,在日期、数字,国际化方面有健全的处理机制。

    结果:虽然网上对比结果一致为Velocity的性能高于FreeMarker,但是我的测试结果却完全相反,可能跟版本有关。语法方面,Velocity更接近java语法,学习成本低,FreeMarker本身提供的语法也相对简单。FreeMarker在社区支持,功能方面要比Velocity强大的多。

    热门阅读美团 GIT Commit Log规范突发!阿里巴巴大调整后端,你再不懂vue就out了

    一个CEO的忠告:你那么牛逼,怎么还是打工人

    关于年薪百万,聊聊年薪380万的研发人是什么样子的

    超详细280页Docker实战文档!开放下载

    程序员,为什么不建议你写框架

    044deb9b1b4d85317f0f7dafbcaa0add.png

    展开全文
  • 1. 前言前几篇文章中我们介绍了...下一个阶段就进入了模板编译阶段,该阶段所做的主要工作是获取到用户传入的模板内容并将其编译成渲染函数。模板编译阶段并不是存在于Vue的所有构建版本中,它只存在于完整版(即vue...

    1. 前言

    前几篇文章中我们介绍了生命周期的初始化阶段,我们知道,在初始化阶段各项工作做完之后调用了vm.$mount方法,该方法的调用标志着初始化阶段的结束和进入下一个阶段,从官方文档给出的生命周期流程图中可以看到,下一个阶段就进入了模板编译阶段,该阶段所做的主要工作是获取到用户传入的模板内容并将其编译成渲染函数。

    e38d6cd12d5b7a8b4299adf430e17f59.png

    模板编译阶段并不是存在于Vue的所有构建版本中,它只存在于完整版(即vue.js)中。在只包含运行时版本(即vue.runtime.js)中并不存在该阶段,这是因为当使用vue-loadervueify时,*.vue文件内部的模板会在构建时预编译成渲染函数,所以是不需要编译的,从而不存在模板编译阶段,由上一步的初始化阶段直接进入下一阶段的挂载阶段。

    在这里,我们有必要介绍一下什么是完整版和只包含运行时版。

    vue基于源码构建的有两个版本,一个是runtime only(一个只包含运行时的版本),另一个是runtime + compiler(一个同时包含编译器和运行时的完整版本)。而两个版本的区别仅在于后者包含了一个编译器。

    完整版本

    一个完整的Vue版本是包含编译器的,我们可以使用template选项进行模板编写。编译器会自动将template选项中的模板字符串编译成渲染函数的代码,源码中就是render函数。如果你需要在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),就需要一个包含编译器的版本。如下:

    // 需要编译器的版本new Vue({  template: '
    {{ hi }}
    '})

    只包含运行时版本

    只包含运行时的版本拥有创建Vue实例、渲染并处理Virtual DOM等功能,基本上就是除去编译器外的完整代码。该版本的适用场景有两种:

    1.我们在选项中通过手写render函数去定义渲染过程,这个时候并不需要包含编译器的版本便可完整执行。

    // 不需要编译器new Vue({  render (h) {    return h('div', this.hi)  }})

    2.借助vue-loader这样的编译工具进行编译,当我们利用webpack进行Vue的工程化开发时,常常会利用vue-loader*.vue文件进行编译,尽管我们也是利用template模板标签去书写代码,但是此时的Vue已经不需要利用编译器去负责模板的编译工作了,这个过程交给了插件去实现。

    很明显,编译过程对性能会造成一定的损耗,并且由于加入了编译的流程代码,Vue代码的总体积也更加庞大(运行时版本相比完整版体积要小大约 30%)。因此在实际开发中,我们需要借助像webpackvue-loader这类工具进行编译,将Vue对模板的编译阶段合并到webpack的构建流程中,这样不仅减少了生产环境代码的体积,也大大提高了运行时的性能,一举两得。

    为了完整的学习源码,本篇文章将会分析完整版中的模板编译阶段到底做了些什么。

    2. 模板编译阶段分析

    上文中说了,完整版和只包含运行时版之间的差异主要在于是否有模板编译阶段,而是否有模板编译阶段主要表现在vm.$mount方法的实现上。此时你可能会有疑问:照这么说,$mount方法也有两个版本?对的,你可以这么理解,但归根结底来说还是一种。我们分别来看一下。

    2.1 两种$mount方法对比

    只包含运行时版本的$mount代码如下:

    Vue.prototype.$mount = function (el,hydrating) {  el = el && inBrowser ? query(el) : undefined;  return mountComponent(this, el, hydrating)};

    在该版本中的$mount方法内部获取到el选项对应的DOM元素后直接调用mountComponent函数进行挂载操作,关于该函数我们会在挂载阶段详细介绍。

    而完整版本的$mount代码如下:

    var mount = Vue.prototype.$mount;Vue.prototype.$mount = function (el,hydrating) {  // 省略获取模板及编译代码  return mount.call(this, el, hydrating)}

    注意,在完整版本的$mount定义之前,先将Vue原型上的$mount方法先缓存起来,记作变量mount。此时你可能会问了,这$mount方法还没定义呢,怎么先缓存起来了。

    其实在源码中,是先定义只包含运行时版本的$mount方法,再定义完整版本的$mount方法,所以此时缓存的mount变量就是只包含运行时版本的$mount方法。

    为什么要这么做呢?上文我们说了,完整版本和只包含运行时版本之间的差异主要在于是否有模板编译阶段,只包含运行时版本没有模板编译阶段,初始化阶段完成后直接进入挂载阶段,而完整版本是初始化阶段完成后进入模板编译阶段,然后再进入挂载阶段。也就是说,这两个版本最终都会进入挂载阶段。所以在完整版本的$mount方法中将模板编译完成后需要回头去调只包含运行时版本的$mount方法以进入挂载阶段。

    这也就是在完整版本的$mount方法中先把只包含运行时版本的$mount方法缓存下来,记作变量mount,然后等模板编译完成,再执行mount方法(即只包含运行时版本的$mount方法)。

    所以分析模板编译阶段其实就是分析完整版的vm.$mount方法的实现。

    2.2 完整版的vm.$mount方法分析

    完整版的vm.$mount方法定义位于源码的dist/vue.js中,如下:

    var mount = Vue.prototype.$mount;Vue.prototype.$mount = function (el,hydrating) {  el = el && query(el);  if (el === document.body || el === document.documentElement) {    warn(      "Do not mount Vue to  or  - mount to normal elements instead."    );    return this  }  var options = this.$options;  // resolve template/el and convert to render function  if (!options.render) {    var template = options.template;    if (template) {      if (typeof template === 'string') {          if (template.charAt(0) === '#') {            template = idToTemplate(template);            /* istanbul ignore if */            if (!template) {              warn(                ("Template element not found or is empty: " + (options.template)),                this              );            }          }      } else if (template.nodeType) {        template = template.innerHTML;      } else {        {          warn('invalid template option:' + template, this);        }        return this      }    } else if (el) {      template = getOuterHTML(el);    }    if (template) {      if (config.performance && mark) {        mark('compile');      }      var ref = compileToFunctions(template, {        outputSourceRange: "development" !== 'production',        shouldDecodeNewlines: shouldDecodeNewlines,        shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,        delimiters: options.delimiters,        comments: options.comments      }, this);      var render = ref.render;      var staticRenderFns = ref.staticRenderFns;      options.render = render;      options.staticRenderFns = staticRenderFns;      if (config.performance && mark) {        mark('compile end');        measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');      }    }  }  return mount.call(this, el, hydrating)};

    从代码中可以看到,该函数可大致分为三部分:

    • 根据传入的el参数获取DOM元素;

    • 在用户没有手写render函数的情况下获取传入的模板template

    • 将获取到的template编译成render函数;

    接下来我们就逐一分析。

    首先,根据传入的el参数获取DOM元素。如下:

    el = el && query(el);function query (el) {  if (typeof el === 'string') {    var selected = document.querySelector(el);    if (!selected) {      warn(        'Cannot find element: ' + el      );      return document.createElement('div')    }    return selected  } else {    return el  }}

    由于el参数可以是元素,也可以是字符串类型的元素选择器,所以调用query函数来获取到el对应的DOM元素。由于query函数比较简单,就是根据传入的el参数是否为字符串从而以不同方式获取到对应的DOM元素,这里就不逐行展开介绍了。

    另外,这里还多了一个判断,就是判断获取到el对应的DOM元素如果是bodyhtml元素时,将会抛出警告。这是因为Vue会将模板中的内容替换el对应的DOM元素,如果是bodyhtml元素时,替换之后将会破坏整个DOM文档,所以不允许elbodyhtml。如下:

    if (el === document.body || el === document.documentElement) {  warn(    "Do not mount Vue to  or  - mount to normal elements instead."  );  return this}

    接着,在用户没有手写render函数的情况下获取传入的模板template;如下:

    if (!options.render) {  var template = options.template;  if (template) {    if (typeof template === 'string') {      if (template.charAt(0) === '#') {        template = idToTemplate(template);        /* istanbul ignore if */        if (!template) {          warn(            ("Template element not found or is empty: " + (options.template)),            this          );        }      }    } else if (template.nodeType) {        template = template.innerHTML;    } else {      {        warn('invalid template option:' + template, this);      }      return this    }  } else if (el) {    template = getOuterHTML(el);  }}

    首先获取用户传入的template选项赋给变量template,如果变量template存在,则接着判断如果template是字符串并且以##开头,则认为templateid选择符,则调用idToTemplate函数获取到选择符对应的DOM元素的innerHTML作为模板,如下:

    if (template) {  if (typeof template === 'string') {    if (template.charAt(0) === '#') {      template = idToTemplate(template);    }  }}var idToTemplate = cached(function (id) {  var el = query(id);  return el && el.innerHTML});

    如果template不是字符串,那就判断它是不是一个DOM元素,如果是,则使用该DOM元素的innerHTML作为模板,如下:

    if (template.nodeType) {  template = template.innerHTML;}

    如果既不是字符串,也不是DOM元素,此时会抛出警告:提示用户template选项无效。如下:

    else {  {    warn('invalid template option:' + template, this);  }  return this}

    如果变量template不存在,表明用户没有传入template选项,则根据传入的el参数调用getOuterHTML函数获取外部模板,如下:

    if (el) {  template = getOuterHTML(el);}function getOuterHTML (el) {  if (el.outerHTML) {    return el.outerHTML  } else {    var container = document.createElement('div');    container.appendChild(el.cloneNode(true));    return container.innerHTML  }}

    不管是从内部的template选项中获取模板,还是从外部获取模板,总之就是要获取到用户传入的模板内容,有了模板内容接下来才能将模板编译成渲染函数。

    获取到模板之后,接下来要做的事就是将其编译成渲染函数,如下:

    if (template) {  var ref = compileToFunctions(template, {    outputSourceRange: "development" !== 'production',    shouldDecodeNewlines: shouldDecodeNewlines,    shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,    delimiters: options.delimiters,    comments: options.comments  }, this);  var render = ref.render;  var staticRenderFns = ref.staticRenderFns;  options.render = render;  options.staticRenderFns = staticRenderFns;}

    关于将模板编译成渲染函数的具体步骤在前面文章模板编译篇中已经做了详细介绍,在这里,我们仅做简单回顾。

    把模板编译成渲染函数是在compileToFunctions函数中进行的,该函数接收待编译的模板字符串和编译选项作为参数,返回一个对象,对象里面的render属性即是编译好的渲染函数,最后将渲染函数设置到$options上。

    3. 总结

    本篇文章介绍了生命周期中的第二个阶段——模板编译阶段。

    首先介绍了Vue源码构建的两种版本:完整版本和只包含运行时版本。并且我们知道了模板编译阶段只存在于完整版中,在只包含运行时版本中不存在该阶段,这是因为在只包含运行时版本中,当使用vue-loadervueify时,*.vue文件内部的模板会在构建时预编译成渲染函数,所以是不需要编译的,从而不存在模板编译阶段。

    然后对比了两种版本$mount方法的区别。它们的区别在于在$mount方法中是否进行了模板编译。在只包含运行时版本的$mount方法中获取到DOM元素后直接进入挂载阶段,而在完整版本的$mount方法中是先将模板进行编译,然后回过头调只包含运行时版本的$mount方法进入挂载阶段。

    最后,我们知道了分析模板编译阶段其实就是分析完整版的vm.$mount方法的实现,我们将完整版的vm.$mount方法源码进行了逐行分析。知道了在该阶段中所做的工作就是:从用户传入的el选项和template选项中获取到用户传入的内部或外部模板,然后将获取到的模板编译成渲染函数。

    展开全文
  • else {% endif %} 模板继承 与方法继承相似 语法 {% extends '继承文件路径及后缀' %} 继承的好处 可以复用父类代码,节省开发时间 可以根据需求进行重写,比较灵活 如果想让子模板实现一些自定义内容,只需要使用...

    测试器

    测试器即对文件内变量名、变量类型等文件进行判断

    • 语法
    {% if 判断条件 %}    ...代码块...{% elif 判断条件 %}    ...代码块...{% else %}    ...代码块...{% endif %}
    • 实例
        Title    {% set name='孟' %}    {% if names %}        

    有name:{{ names }}

    {% elif name %}

    有name:{{ name }}

    {% else %}

    没有name;else

    {% endif %}

    执行代码,可以看到页面打印:

    574e29c34b1728a0d55d1ebed750cc13.png


    也就是说代码走了elif。

    上面代码也可这样写:

        Title    {% set name='孟' %}    {% if names is undefined %}        

    有name:{{ names }}

    {% elif name is defined %}

    有name:{{ name }}

    {% else %}

    没有name;else

    {% endif %}

    模板继承

    与方法继承相似

    语法

    {% extends '继承文件路径及后缀' %}
    • 继承的好处
    • 可以复用父类代码,节省开发时间
    • 可以根据需求进行重写,比较灵活
    • 如果想让子模板实现一些自定义内容,只需要使用block标签

    实例

    新建如下页面:

    6cda53c4b71470f43d72cd2ae429f280.png

    命名为base.html

        模板继承
    新闻 音乐 贴吧 视频
    左面的盒子
    右面的盒子

    现在我们想增加两个页面,分别为detail.html和front_page.html,如果把代码原封不动的复制过去也可以,但是一旦页面有改动,那这三个文件你就得分别取改代码,所以这里就用继承就会方便很多了:

    detail.html

    {% extends 'base.html' %}

    front_page.html同上,这样就通过继承复制出了两个相同的页面了。在app.py文件分别新增方法即可:

    @app.route('/detail/')def detail():    return flask.render_template('detail.html')@app.route('/frontpage/')def frontPage():    return flask.render_template('front_page.html')
    e07c73f641fb99a34d29d86d2dd66d1d.png

    现在如果在detail.html页面要增加新内容怎么办呢?就是之前提过的,block标签上场了。

    • 语法{% block 变量名 %}{% endblock %}
    • 实例

    将之前部分代码改为:

    {% block left %}左面的盒子{% endblock %}
    {% block right %}右面的盒子{% endblock %}

    然后在detail.html中修改代码为:

    {% extends 'base.html' %}{% block left %}    
    编号 课程 1 Flask
    {% endblock %}

    在detail.html中的block添加代码后,就相当于把里面的代码添加到了base.html文件的block里面。

    保存,detail.html页面变为:

    7ad0ae4bbef000a581fec08e6395f5e7.png

    以上内容即为模板继承。但是大家也发现左面盒子里面的内容全部被重写了,这时候只需要继承父类即可:

    {{ super() }}

    在detail.html中增加上面代码即可:

    {% extends 'base.html' %}{% block left %}    {{ super() }}    
    编号 课程 1 Flask
    {% endblock %}
    ea500899955104ad058ea5f2c25e1ba2.png

    现在如果说右侧也要有一个相同的table该怎么办呢?当然不需要再重复代码,只需要在对应的block中调用上一个block的名字:{{ self.block名字 }}即可。

    • 实例

    detail.html

    {# 模板继承 #}{% extends 'base.html' %}{# 利用block修改模板内容 #}{% block left %}    {{ super() }}    
    编号 课程 1 Flask
    {% endblock %}{% block right %} {{ super() }} {{ self.left() }}{% endblock %}

    执行后右侧盒子就会和左侧一样了。

    07b0a07a969ff918816554b9106355c3.png

    如果对接口、性能、自动化测试、面试经验交流等感兴趣的,可以关注我的头条号,我会不定期的发放免费的资料,这些资料都是从各个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处之后分享给大家。欢迎分享,欢迎评论,欢迎转发。需要资料的同学可以关注小编+转发文章+私信【测试资料】

    展开全文
  • 模板基于MUI开发尽量保证MUI的原有功能并结合了iconfont图标库、大大提升填补了MUI缺少及美化页面,美化页面如下: 主页美化、产品列表(筛选)、产品详情(加入购物车弹层、右上角下拉)、商家详情(基于MUI多...
  • mui移动微商城模板h5模板 较完整的一套基于MUI框架做的商城模板,分享出来大家学习借鉴
  • MUI商城简洁模板

    2019-11-06 10:42:56
    非常完整的一套基于MUI框架做的商城模板,花钱买的,分享出来大家学习借鉴...
  • mui框架手机网站模板

    2019-09-19 15:22:06
    mui框架手机网站模板
  • 蓝色精美简洁MUI后台管理模板,蓝色精美简洁MUI后台管理模板
  • mui仿小米商城模板

    2018-10-05 15:33:18
    mui仿小米商城模板,可以直接拿来练手和学习调试,希望对大家学习mui框架有帮助
  • mui登录模板源码解

    2020-09-15 16:53:48
    模板的登录核心代码写在login.html页面里 <script> (function($, doc) { $.init({ statusBarBackground: '#f7f7f7' }); $.plusReady(function() { plus.screen.lockOrientation("portrait-primary"); ...

    登录模板页面样式(该页面包含账户、密码输入栏,具有自动登录功能)

    该页面包含账户、密码输入栏,具有自动登录功能

    模板的登录核心代码写在login.html页面里
    <script>
       (function($, doc) {
        $.init({
         statusBarBackground: '#f7f7f7'
        });
        $.plusReady(function() {
         plus.screen.lockOrientation("portrait-primary");
         var settings = app.getSettings();
         var state = app.getState();
         var mainPage = plus.webview.getWebviewById("main");
         var main_loaded_flag = false;
         if(!mainPage){
          mainPage = $.preload({
           "id": 'main',
           "url": 'main.html'
          });
         }else{
          main_loaded_flag = true;
         }
    
         mainPage.addEventListener("loaded",function () {
          main_loaded_flag = true;
         });
         var toMain = function() {
          //使用定时器的原因:
          //可能执行太快,main页面loaded事件尚未触发就执行自定义事件,此时必然会失败
          var id = setInterval(function () {
           if(main_loaded_flag){
            clearInterval(id);
            $.fire(mainPage, 'show', null);
            mainPage.show("pop-in");
           }
          },20);
         };
         //检查 "登录状态/锁屏状态" 开始
         if (settings.autoLogin && state.token && settings.gestures) {
          $.openWindow({
           url: 'unlock.html',
           id: 'unlock',
           show: {
            aniShow: 'pop-in'
           },
           waiting: {
            autoShow: false
           }
          });
         } else if (settings.autoLogin && state.token) {
          toMain();
         } else {
          app.setState(null);
          //第三方登录
          var authBtns = ['qihoo', 'weixin', 'sinaweibo', 'qq']; //配置业务支持的第三方登录
          var auths = {};
          var oauthArea = doc.querySelector('.oauth-area');
          plus.oauth.getServices(function(services) {
           for (var i in services) {
            var service = services[i];
            auths[service.id] = service;
            if (~authBtns.indexOf(service.id)) {
             var isInstalled = app.isInstalled(service.id);
             var btn = document.createElement('div');
             //如果微信未安装,则为不启用状态
             btn.setAttribute('class', 'oauth-btn' + (!isInstalled && service.id === 'weixin' ? (' disabled') : ''));
             btn.authId = service.id;
             btn.style.backgroundImage = 'url("images/' + service.id + '.png")'
             oauthArea.appendChild(btn);
            }
           }
           $(oauthArea).on('tap', '.oauth-btn', function() {
            if (this.classList.contains('disabled')) {
             plus.nativeUI.toast('您尚未安装微信客户端');
             return;
            }
            var auth = auths[this.authId];
            var waiting = plus.nativeUI.showWaiting();
            auth.login(function() {
             waiting.close();
             plus.nativeUI.toast("登录认证成功");
             auth.getUserInfo(function() {
              plus.nativeUI.toast("获取用户信息成功");
              var name = auth.userInfo.nickname || auth.userInfo.name;
              app.createState(name, function() {
               toMain();
              });
             }, function(e) {
              plus.nativeUI.toast("获取用户信息失败:" + e.message);
             });
            }, function(e) {
             waiting.close();
             plus.nativeUI.toast("登录认证失败:" + e.message);
            });
           });
          }, function(e) {
           oauthArea.style.display = 'none';
           plus.nativeUI.toast("获取登录认证失败:" + e.message);
          });
         }
         // close splash
         setTimeout(function() {
          //关闭 splash
          plus.navigator.closeSplashscreen();
         }, 600);
         //检查 "登录状态/锁屏状态" 结束
         var loginButton = doc.getElementById('login');
         var accountBox = doc.getElementById('account');
         var passwordBox = doc.getElementById('password');
         var autoLoginButton = doc.getElementById("autoLogin");
         var regButton = doc.getElementById('reg');
         var forgetButton = doc.getElementById('forgetPassword');
         loginButton.addEventListener('tap', function(event) {
          var loginInfo = {
           account: accountBox.value,
           password: passwordBox.value
          };
          app.login(loginInfo, function(err) {
           if (err) {
            plus.nativeUI.toast(err);
            return;
           }
           toMain();
          });
         });
         $.enterfocus('#login-form input', function() {
          $.trigger(loginButton, 'tap');
         });
         autoLoginButton.classList[settings.autoLogin ? 'add' : 'remove']('mui-active')
         autoLoginButton.addEventListener('toggle', function(event) {
          setTimeout(function() {
           var isActive = event.detail.isActive;
           settings.autoLogin = isActive;
           app.setSettings(settings);
          }, 50);
         }, false);
         regButton.addEventListener('tap', function(event) {
          $.openWindow({
           url: 'reg.html',
           id: 'reg',
           preload: true,
           show: {
            aniShow: 'pop-in'
           },
           styles: {
            popGesture: 'hide'
           },
           waiting: {
            autoShow: false
           }
          });
         }, false);
         forgetButton.addEventListener('tap', function(event) {
          $.openWindow({
           url: 'forget_password.html',
           id: 'forget_password',
           preload: true,
           show: {
            aniShow: 'pop-in'
           },
           styles: {
            popGesture: 'hide'
           },
           waiting: {
            autoShow: false
           }
          });
         }, false);
         //
         window.addEventListener('resize', function() {
          oauthArea.style.display = document.body.clientHeight > 400 ? 'block' : 'none';
         }, false);
         //
         var backButtonPress = 0;
         $.back = function(event) {
          backButtonPress++;
          if (backButtonPress > 1) {
           plus.runtime.quit();
          } else {
           plus.nativeUI.toast('再按一次退出应用');
          }
          setTimeout(function() {
           backButtonPress = 0;
          }, 1000);
          return false;
         };
        });
       }(mui, document));
      </script>
    
    登录模板源码分析
    源码中首先是读取本地存储的用户登录状态信息,其中app.getSettings()读取用户是否开启自动登录状态,对应上图中的自动登录按钮;app.getState()读取用户上一次登陆时存储在本地的状态。(其中app为引入的app.js,将在下面介绍)
    var settings = app.getSettings();
    var state = app.getState();
    
    接着检查登录状态/锁屏状态,settings.autoLogin检查自动登录,state.token为用户上一次存储在本地的信息,settings.gestures检查是否启动手势登录。当用户设置自动登录,手势登录,且上一次登录成功,则执行if语句;否则,如果用户设置自动登录,且上一次登录成功,则自动登录,跳转到主页面。(对手势登录感兴趣的同学可以自行阅读源码)
    //检查 "登录状态/锁屏状态" 开始
         if (settings.autoLogin && state.token && settings.gestures) {
          $.openWindow({
           url: 'unlock.html',
           id: 'unlock',
           show: {
            aniShow: 'pop-in'
           },
           waiting: {
            autoShow: false
           }
          });
         } else if (settings.autoLogin && state.token) {
          toMain();
         }
    
    跳转到主页面的代码如下
    var toMain = function() {
          //使用定时器的原因:
          //可能执行太快,main页面loaded事件尚未触发就执行自定义事件,此时必然会失败
          var id = setInterval(function () {
           if(main_loaded_flag){
            clearInterval(id);
            $.fire(mainPage, 'show', null);
            mainPage.show("pop-in");
           }
          },20);
         };
    
    用户初次登录,或者没有设置自动登录,则需要用户输入用户名、密码登录。得到用户输入的用户名、密码在app.js中进行校验,校验成功,则执行toMain()跳转到主页面。
    //检查 "登录状态/锁屏状态" 结束
         var loginButton = doc.getElementById('login');
         var accountBox = doc.getElementById('account');
         var passwordBox = doc.getElementById('password');
         var autoLoginButton = doc.getElementById("autoLogin");
         var regButton = doc.getElementById('reg');
         var forgetButton = doc.getElementById('forgetPassword');
         loginButton.addEventListener('tap', function(event) {
          var loginInfo = {
           account: accountBox.value,
           password: passwordBox.value
          };
          app.login(loginInfo, function(err) {
           if (err) {
            plus.nativeUI.toast(err);
            return;
           }
           toMain();
          });
         });
    
    下面的代码块,将用户是否自动登录存储在本地
    autoLoginButton.addEventListener('toggle', function(event) {
          setTimeout(function() {
           var isActive = event.detail.isActive;
           settings.autoLogin = isActive;
           app.setSettings(settings);
          }, 50);
         }, false);
    

    app.js源码分析

    这段代码为对用户输入的账号、密码进行校验
    /**
      * 用户登录
      **/
     owner.login = function(loginInfo, callback) {
      callback = callback || $.noop;
      loginInfo = loginInfo || {};
      loginInfo.account = loginInfo.account || '';
      loginInfo.password = loginInfo.password || '';
      if (loginInfo.account.length < 5) {
       return callback('账号最短为 5 个字符');
      }
      if (loginInfo.password.length < 6) {
       return callback('密码最短为 6 个字符');
      }
      var users = JSON.parse(localStorage.getItem('$users') || '[]');
      var authed = users.some(function(user) {
       return loginInfo.account == user.account && loginInfo.password == user.password;
      });
      if (authed) {
       return owner.createState(loginInfo.account, callback);
      } else {
       return callback('用户名或密码错误');
      }
     };
    
    以下代码块用于读取和设置用户存储在本地的登录状态信息
    /**   
    * 获取当前状态   
    **/  
    owner.getState = function() {   
      var stateText = localStorage.getItem('$state') || "{}";   
      return JSON.parse(stateText);  }; 
     /**
     * 设置当前状态
     **/
     owner.setState = function(state) {
      state = state || {};
      localStorage.setItem('$state', JSON.stringify(state));
      //var settings = owner.getSettings();
      //settings.gestures = '';
      //owner.setSettings(settings);
     };
    
    以下代码块用于读取和设置用户应用本地配置,包括上文提到的自动登录信息
    /**
      * 获取应用本地配置
      **/
    owner.setSettings = function(settings) {
      settings = settings || {};
      localStorage.setItem('$settings', JSON.stringify(settings));
     }
     /**
      * 设置应用本地配置
      **/
     owner.getSettings = function() {
      var settingsText = localStorage.getItem('$settings') || "{}";
      return JSON.parse(settingsText);
     }
    

    如有不对,欢迎留言指正

    展开全文
  • 该资源为一套精美简洁MUI后台管理模板,均为html文件。
  • mui + vue 模板

    2018-01-03 15:30:00
    (function(mui, doc) { // 定义全局变量(计时器) var timer; // mui初始化 mui.init(); // 创建vue的实例 var app = new Vue({ el:'#app', data:{ token: '', paramId: '' ...
  • MUI手机wap商城模板

    2017-11-16 22:51:59
    非常完整的一套基于MUI框架做的商城模板,花钱买的,分享出来大家学习借鉴
  • 微商城模板mui+html

    2020-07-13 10:36:33
    微商城+模板+mall+html+mui+js+css,一套不错的源码,是使用mui进行开发的商城模板
  • 蓝色精美简洁MUI后台管理模板.rar 蓝色精美简洁MUI后台管理模板.rar
  • Mui-遮罩模板

    2019-06-23 10:12:00
    修改自定义模板样式 */ .mui-backdrop { position : fixed ; top : 0 ; right : 0 ; bottom : 0 ; left : 0 ; z-index : 998 ; background-color : rgba(255,0,0,.3) ; } style > ...
  • 前端后台模板页面前端后台模板页面前端后台模板页面前端后台模板页面前端后台模板页面前端后台模板页面前端后台模板页面前端后台模板页面
  • 基于mui移动微商城APP模板源码包括 功能:首页,分类,购物车,登录,注册,个人中心 前端运用mui框架布局,模板完整,可以借鉴学习,首页有搜索功能,购物车,图片展示盒详情展示
  • mui框架下的商城模板,直接运行即可,实现基本功能,
  • SSM(SpringMVC Spring Mybatis) 蓝色精典MUI后台管理模板
  • MUI手机app前端页面开发框架模板下载 MUI手机app前端页面开发框架模板下载

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 235
精华内容 94
关键字:

mui模板