距离上次撰写博文过了好一段时间,最近忙于写后端,又是写前端,还要肝游戏。全栈开发真的挺不容易的。

这次我就转载一些最近遇到问题时查阅的优质文章,出处我会标明的。

深入理解vue中的slot与slot-scope - 掘金

写在前面

vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项在使用频率、使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学,反正已经可以写基础组件了”的想法,于是就关闭了vue的说明文档。

实际上,插槽的概念很简单,下面通过分三部分来讲。这三部分也是按照vue说明文档的顺序来写的。

进入这三部分之前,先让还没接触过插槽的同学对什么是插槽有一个简单的概念:插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题在这里就点出来了,是显示不显示和怎样显示。

由于插槽是一块模板,所以,对于任何一个组件,从模板种类的角度来分,其实都可以分为非插槽模板和插槽模板两大类。

非插槽模板指的是html模板,比如‘div、span、ul、table’这些,非插槽模板的显示与隐藏以及怎样显示由组件自身控制;插槽模板是slot,它是一个空壳子,因为它的显示与隐藏以及最后用什么样的html模板显示由父组件控制。但是插槽显示的位置却由子组件自身决定,slot写在组件template的什么位置,父组件传过来的模板将来就显示在什么位置。

单个插槽 | 默认插槽 | 匿名插槽

首先是单个插槽,单个插槽是vue的官方叫法,但是其实也可以叫它默认插槽,或者与具名插槽相对,我们可以叫它匿名插槽。因为它不用设置name属性。

单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。
下面通过一个例子来展示。
父组件:

<template>
    <div class="father">
        <h3>这里是父组件</h3>
        <child>
            <div class="tmpl">
              <span>菜单1</span>
              <span>菜单2</span>
              <span>菜单3</span>
              <span>菜单4</span>
              <span>菜单5</span>
              <span>菜单6</span>
            </div>
        </child>
    </div>
</template>

子组件:

<template>
    <div class="child">
        <h3>这里是子组件</h3>
        <slot></slot>
    </div>
</template>

在这个例子里,因为父组件在里面写了html模板,那么子组件的匿名插槽这块模板就是下面这样。也就是说,子组件的匿名插槽被使用了,是被下面这块模板使用了。

<div class="tmpl">
  <span>菜单1</span>
  <span>菜单2</span>
  <span>菜单3</span>
  <span>菜单4</span>
  <span>菜单5</span>
  <span>菜单6</span>
</div>

最终的渲染结果如图所示:

注:所有demo都加了样式,以方便观察。其中,父组件以灰色背景填充,子组件都以浅蓝色填充。

具名插槽

匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次,出现在不同的位置。下面的例子,就是一个有两个具名插槽和单个插槽的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。
父组件:

<template>
  <div class="father">
    <h3>这里是父组件</h3>
    <child>
      <div class="tmpl" slot="up">
        <span>菜单1</span>
        <span>菜单2</span>
        <span>菜单3</span>
        <span>菜单4</span>
        <span>菜单5</span>
        <span>菜单6</span>
      </div>
      <div class="tmpl" slot="down">
        <span>菜单-1</span>
        <span>菜单-2</span>
        <span>菜单-3</span>
        <span>菜单-4</span>
        <span>菜单-5</span>
        <span>菜单-6</span>
      </div>
      <div class="tmpl">
        <span>菜单->1</span>
        <span>菜单->2</span>
        <span>菜单->3</span>
        <span>菜单->4</span>
        <span>菜单->5</span>
        <span>菜单->6</span>
      </div>
    </child>
  </div>
</template>
子组件:
<template>
  <div class="child">
    // 具名插槽
    <slot name="up"></slot>
    <h3>这里是子组件</h3>
    // 具名插槽
    <slot name="down"></slot>
    // 匿名插槽
    <slot></slot>
  </div>
</template>

显示结果如图:

可以看到,父组件通过html模板上的slot属性关联具名插槽。没有slot属性的html模板默认关联匿名插槽。
作用域插槽 | 带数据的插槽
最后,就是我们的作用域插槽。这个稍微难理解一点。官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽。什么意思呢,就是前面两种,都是在组件的template里面写
匿名插槽

<slot></slot>

具名插槽

但是作用域插槽要求,在slot上面绑定数据。也就是你得写成大概下面这个样子。

<slot name="up" :data="data"></slot>
 export default {
    data: function(){
      return {
        data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
      }
    },
}

我们前面说了,插槽最后显示不显示是看父组件有没有在child下面写模板,像下面那样。

<child>
   html模板
</child>

写了,插槽就总得在浏览器上显示点东西,东西就是html该有的模样,没写,插槽就是空壳子,啥都没有。

OK,我们说有html模板的情况,就是父组件会往子组件插模板的情况,那到底插一套什么样的样式呢,这由父组件的html+css共同决定,但是这套样式里面的内容呢?

正因为作用域插槽绑定了一套数据,父组件可以拿来用。于是,情况就变成了这样:样式父组件说了算,但内容可以显示子组件插槽绑定的。

我们再来对比,作用域插槽跟单个插槽和具名插槽的区别,因为单个插槽和具名插槽不绑定数据,所以父组件提供的模板一般要既包括样式又包括内容,上面的例子中,你看到的文字,“菜单1”,“菜单2”都是父组件自己提供的内容;而作用域插槽,父组件只需要提供一套样式(在确实用作用域插槽绑定的数据的前提下)。

下面的例子,你就能看到,父组件提供了三种样式(分别是flex、ul、直接显示),都没有提供数据,数据使用的都是子组件插槽自己绑定的那个数组(一堆人名的那个数组)。

父组件:

<template>
  <div class="father">
    <h3>这里是父组件</h3>
    <!--第一次使用:用flex展示数据-->
    <child>
      <template slot-scope="user">
        <div class="tmpl">
          <span v-for="item in user.data">{{item}}</span>
        </div>
      </template>

    </child>

    <!--第二次使用:用列表展示数据-->
    <child>
      <template slot-scope="user">
        <ul>
          <li v-for="item in user.data">{{item}}</li>
        </ul>
      </template>

    </child>

    <!--第三次使用:直接显示数据-->
    <child>
      <template slot-scope="user">
       {{user.data}}
      </template>

    </child>

    <!--第四次使用:不使用其提供的数据, 作用域插槽退变成匿名插槽-->
    <child>
      我就是模板
    </child>
  </div>
</template>

子组件:

<template>
  <div class="child">

    <h3>这里是子组件</h3>
    // 作用域插槽
    <slot  :data="data"></slot>
  </div>
</template>

 export default {
    data: function(){
      return {
        data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
      }
    }
}

结果如图所示:

作者:云荒杯倾
链接:https://juejin.im/post/5a69ece0f265da3e5a5777ed
来源:掘金

express做登录验证获取req.body为空对象问题

地址:https://blog.csdn.net/TyrionJ/article/details/81990048

Express学习-模板引擎(Template Engine)

模板引擎(Template Engine), 是用来解析对应类型模板文件然后动态生成由数据和静态页面组成的视图文件的一个工具。 它通过标签(tag)来响应各种解析动作,通过变量占位的方式动态的将对应数据展示到指定位置。

在 express web框架中,ejsjade都有很好的集成支持。在express中,在模板引擎使用上大多数应该都会偏向于ejs吧,ejs在代码编写上更直观,更易于理解,让开发者更多的专注于数据处理,而jade将html和数据处理揉杂在了一起,而且语法也比较怪异,看起来。 我比较喜欢ejs。 -_-#

ejs

ejs,它是一个开源的javaScript模板库或工具,ejs将数据和模板整合最终生成html文件,ejs使用起来相比jade要简单很多,语法非常像在jsp中使用 EL表达式($)动态处理数据。在html中,使用ejs动态输出数据看起来像这样:

  var  o = {tag1:'hello,ejs'} ;
    <p> <%= o.tag1 %></p>

输出到页面是这样的 :

hello,ejs

在jsp中使用EL表达式$同样也是对象.属性获取数据。这让我过度非常的容易。这也许是我更喜欢ejs的原因吧。

ejs 也可以独立于 express 框架使用,比如直接在html页面中引入就像jquery一样使用,如:

<div id="output"></div>
<script src="ejs.min.js"></script>
<script>
  var people = ['geddy', 'neil', 'alex'],
      html = ejs.render('<%= people.join(", "); %>', {people: people});
  // With jQuery: 
  $('#output').html(html);
  // Vanilla JS: 
  document.getElementById('output').innerHTML = html;
</script> 

这里下载./ejs.js 或者./ejs.min.js, 这种方式在jsp页面需要动态的生成公用的类似表格的页面的时候非常有用!

ejs使用

  • ejs 安装
  npm install ejs
  ## npm i ejs  --i 是 install的别名
  • 在express中使用
  //设置模板引擎为ejs
  app.set('view engine','ejs') ; //app = express() ; 
  //设置模板文件位置 => 项目根路径下views目录为模板文件存放目录
  app.set('views', __dirname + '/views') ;
  • render函数

    在express框架中使用

    ejs.render(dataAndOptions)

    就可以由一个模板文件生成静态html文件,并将数据嵌入到html文件中,这个函数有如下参数:

    • ejs模板文件名
    • 动态数据
    • 渲染个性化参数 -例如模板文件缓存,函数执行环境,打开debug模式等

如:

app.get('/',function(req,res) {
    res.render('index',{
        name:'ejs case'
    }) ;
}) ;

index 表示模板目录下的index.ejs文件,这个文件看起来像这样:

<!DOCTYPE html>
<html>
  <head><title>ejs example</title></head>
  <body>
    <h1><%= name %></h1>
  </body>
</html>

html中的css 什么的,都不需要关心,静态页面是什么样,在index.ejs中还是什么样,甚至,不懂html语法都可以,只需要知道在哪儿插入有效的ejs #tag就可以了,真的很方便。

ejs 标签
ejs #Tags是ejs动态处理数据的重要工具,通过不同的标签,ejs将生成不同类型的html元素,方便浏览器等客户端正确解析html文件。ejs目前共有如下标签支持:

  • <% 'Scriptlet' tag, for control-flow, no output
  • <%_ 'Whitespace Slurping' Scriptlet tag, strips all whitespace before it
  • <%= Outputs the value into the template (escaped)
  • <%- Outputs the unescaped value into the template
  • <%# Comment tag, no execution, no output
  • <%% Outputs a literal '<%'
  • %%> Outputs a literal '%>'
  • %> Plain ending tag
  • -%> Trim-mode ('newline slurp') tag, trims following newline
  • _%> 'Whitespace Slurping' ending tag, removes all whitespace after it

这些标签一般情况下是以%>结束的,但是也可以使用别的标签结束,例如最后两个就是用来做特殊处理的结束标签。-%> 、_%>
这些标签看起来,很像在jsp编写java代码使用的标签,也像JSTL标签,因为ejs#Tags支持javaScript执行,和jsp中的<% System.out.print("hello")%> 一样。ejs使用<%来执行标签内的js代码,更多标签文档在这里

和jsp一样,ejs也支持include, 来达到页面服用的目的,例如,大多数网站的首页展示的东西都比较多,特殊要求也越来越多,页面变更相对也是最频繁的,所以,一般这种首页都会有最少三部分组成: head.htmlbody.htmlfoote.html 通过这种方式,不仅能达到页面复用的目的,还可以分开维护,是首页能更加灵活的多样化展示,也是首页更加稳定。不会因为某一块的变更导致另一块也需要跟着变化。

ejs中使用标签<%- include('head') %>来将head.ejs文件引入。 如:

//head.ejs
<!DOCTYPE html>
<html>
  <head>
      <title>ejs example</title>
  </head>
//body.ejs
  <body>
    <h1><%= name %></h1>
    <p>hello, <%= name %></p>
  </body>
//foote
<div style="height:2px;border-bottom:1px #ccc solid;"></div>
</html>
<%- include('head') %>
  <%- include('body',{name:'ejs'}) %>
<%- include('foote') %>

这样,通过include引入,功能上一模一样,结构明显更加清晰了,而且模板复用不能再爽了。

jade

jade 是一个非常强大的模板引擎,有别与传统的模板技术,jade可以实现模板继承,据说同时性能还很强,jade粉随处可见,但是她风骚的语法和代码风格,我一直不敢尝试去爱,可能是因为我的要求很低,我只是需要一个可以填充数据的东东就可以了,有ejs已经足够了。 #-_-

有比较多的语言都有jade的实现,来实现前后端统一渲染,例如:

  • java
  • php
  • python
  • ruby
  • scala

我记得之前遇到过,github上也有类似开源项目,例如jade4j。

jade 风骚的语法支持简介
在我看来,jade语法看起来有点像Markdown, 如:

html

会被解析为

<html></html>

又有一点像jQuery,如:

div#container

会被解析为

<div id="container"></div>

如添加class语法:

div.user-details

解析结果为

<div class="user-details"></div>

使用jade编写的模板长这样的:

html
  head
    title Example
    script
      if (foo) {
        bar();
      } else {
        baz();
      }

看着这样,总感觉别扭,都只有一半,特别想去给他补完整,有木有,像我这种强迫症重症患者如何能忍。

所以,我看了一点语法就放弃了,jade语法体系庞大,他似乎是专门为html定制的,html有的元素他都有对应的标签,html没有的元素,他也有对应的标签处理。ejs跟他相比,确实很弱,但是jade的学习成本也很可观。而且,用好也不是那么容易的。 我个人觉得,ejs才是正确的选择,很多时候静态html和动态数据处理真的应该分开,动态数据处理基本都是后端猿/媛,对html的了解大多不可能赶得上前端大婶,所以让一个业余的人来干正儿八经的事,想想都知道是什么结果了,只能是专业坑队友了。

有这想法,一方面也是因为我对jade不懂,路过的大神,请轻拍! @^_^@

在express中使用ejs*

一个简单的通过ejs模板输出的栗子:

  • 新建一个项目目录,进入安装expressejs支持:
mkdir express-ejs && cd express-ejs
  • 安装expressejs
npm i express
  • 检查express安装成功后安装ejs
npm i ejs
  • 同样检查node_modules目录中是否有ejs目录。
  • 然后新建路由目录和模板文件存放目录
mkdir {routers,views}
##routers 是业务路由js文件存放目录,views是模板文件存放目录
  • 然后新建一个入口函数文件 - app.js

然后整个项目目录是这个样子:

/express/express-ejs>$ ls
app.js  node_modules  routes  views

然后在routers目录下新建index.js用来处理首页访问(这个栗子只是首页处理),如:

var express = require('express') ;

var route = express.Router() ;

route.get('/',function(req,res) {
    //
    // res.send('hello ,ejs.') ;
    res.render('index',{o:{
        name:'ejs case',
        content:'ejs'
    }}) ;
}) ;

route.use(function(req,res) {
    res.send('404 miss route.') ;
}) ;

module.exports =route ;

然后在app.js中设置模板引擎、模板文件位置、路由设置、服务启动,如:

var express = require('express') ;
var app = express() ;

var index = require('./routes/index') ;

app.set('views', __dirname + '/views') ;
app.set('view engine','ejs') ;

app.use('/',index) ;

app.listen(8080,function() {
    console.log('server has started......') ;
}) ;

然后是ejs模板文件(在/views目录下),这里采用了include方式:

//head.ejs
<!DOCTYPE html>
<html>
  <head>
      <title><%= title %></title>
  </head>
//body.ejs
  <body>
    <h1><%= o.name %></h1>
    <p>hello, <%= o.content %></p>
  </body>
//foote.ejs
<div style="height:2px;border-bottom:1px #ccc solid;"></div>
</html>
//index.ejs
<%- include('head',{title:'ejs example'}) %>
  <%- include('body') %>
<%- include('foote') %>

然后运行node命令启动服务,访问http://localhost:8080 就可以看到效果了,

作者:_palm
链接:https://www.jianshu.com/p/021fdfe1b8d6
来源:简书