前后端开发配合
Drupal 项目开发前后端配合一般常见两种:
- 后端输出模板,前端根据 UI 设计稿修改模板结构,写样式和 JavaScript;
- 前端根据 UI 设计好组件,后端到静态组件中套前端组件结构;
缺点
- 第一种缺点是前端必须等后端输出数据,不能够很好的复用,难以维护;
- 第二种前后端都可以先行,不必互相等待,缺点是当前端组件 HTML 结构发生改变时,需要同时维护静态组件和后端输出的模板。
问题
- 有没有办法只维护一个前端组件,后端模板和前端静态组件同时生效?
- 在不同的页面中,组件是否不通过复制的方式使用同一个组件?
实践
这是一个经典的 showcase 组件,每个 showcase 组件还有几组子组件,子组件包含有图片,标题,内容和更多链接,正常的静态化开发流程:
- 设计好子组件,命名编号;
- 设计好父组件,命名编号,复制子组件,修改静态内容;
效果如图:
一、如何让静态模板在 Drupal 主题中可预览?
暂且把前端主题命名为:easy_ui,可以将以下文件命名为 showcase-v1.html.twig 放入主题的的 UI 目录下面,通过后端代码(省略)可以实现twig文件的静态预览。
<div class="showcase-1">
<div class="container">
<div class="row">
<div class="col-sm-4 col-md-4">
{#子组件#}
<div class="box-1">
<div class="big-icon bg"><i class="fa fa-picture-o"></i></div>
<h4 class="title">响应式设计</h4>
<div class="text-small">...<div class="clearfix"></div><br data-tomark-pass> <a class="btn btn-default" href="/contact" target="_blank">更多</a>
</div>
</div>
</div>
... </div>
</div></div>
二、如何解决只维护一个子组件?
使用 twig include 可以引入子组件,在 UI 目录中可以新建 box 文件夹存放子组件,当你的组件越来越多的时候可以很好的整理分类,并抽出子组件命名为:box-v1.html.twig
{# box/box-v1.html.twig #}<div class="box-1">
<div class="big-icon bg"><i class="fa fa-picture-o"></i></div>
<h4 class="title">响应式设计</h4>
<div class="text-small">...<div class="clearfix"></div><br data-tomark-pass> <a class="btn btn-default" href="/contact" target="_blank">更多</a>
</div></div></div>
父组件 include 引入子组件:
{# showcae-v1.html.twig #}<div class="container">
<div class="row">
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' %}
</div>
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' %}
</div>
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' %}
</div>
</div></div>
三、如何解决同一个子组件使用不同的数据?
当父组件使用 include 引用 box-v1.html.twig 的时候,三个子组件会显示同样的静态内容,让我们一步一步解决,先把静态内容改成变量:
twig 可在模板中声明局部变量
{% set item = {
'icon': 'fa-picture-o',
'title': '响应式设计',
'body': 'At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ',
'moreText': '更多',
'moreLink': '/content'
}
%}<div class="box-1">
<div class="big-icon bg"><i class="fa {{item.icon}}"></i></div>
<h4 class="title">{{item.title}}</h4>
<div class="text-small">{{item.body}}<div class="clearfix"></div><br data-tomark-pass> <a class="btn btn-default" href="{{item.moreLink}}" target="_blank">{{item.moreText}}</a>
</div></div>
下一步,数据从父组件传递到子组件,twig 的 with 可以做这个事情:),继续改造:
{# 父组件 showcase-v1.html.twig #}<div class="container">
<div class="row">
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' with {
'icon': 'fa-picture-o',
'title': '响应式设计',
'body': 'At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ',
'moreText': '更多',
'moreLink': '/content'
} %}
</div>
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' with {
'icon': 'fa-wrench',
'title': '组件化开发',
'body': 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat ',
'moreText': '更多',
'moreLink': '/content'
} %}
</div>
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' with {
'icon': 'fa-bug',
'title': '市场应用',
'body': 'Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. ',
'moreText': '更多',
'moreLink': '/content'
} %}
</div>
</div></div>{# 子组件 box-v1.html.twig #}<div class="box-1">
<div class="big-icon bg"><i class="fa {{icon}}"></i></div>
<h4 class="title">{{title}}</h4>
<div class="text-small">
{{body}}
<div class="clearfix"></div><br data-tomark-pass> <a class="btn btn-default" href="{{moreLink}}" target="_blank">{{moreText}}</a>
</div></div>
是不是很酷!
四、使用 for 循环继续提取改造,维护数据更加清晰
{# 父组件 showcase-v1.html.twig #}{% set items = [
{
'icon': 'fa-picture-o',
'title': '响应式设计',
'body': 'At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ',
'moreText': '更多',
'moreLink': '/content'
},
{
'icon': 'fa-wrench',
'title': '组件化开发',
'body': 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat ',
'moreText': '更多',
'moreLink': '/content'
},{
'icon': 'fa-bug',
'title': '市场应用',
'body': 'Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. ',
'moreText': '更多',
'moreLink': '/content'
}
]
%}<div class="container">
<div class="row">
{% for item in items %}
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' with item %}
</div>
{% endfor %}
</div></div>
五、数据从父组件传递到子组件
重点来了,后端数据如何使用同一个前端组件?又不影响前端组件的静态化预览?可以使用twig的默认值来优化:
我们模拟一下后端模板和数据,通过include引用前端showcase.html.twig组件,使用with传递数据:
{# modules template #}
{% set data = [
{
'icon': 'fa-picture-o',
'title': 'new',
'body': 'Lorem ipsum dolor sit amet consectetur, adipisicing elit. Neque, ipsa. Totam autem repellendus voluptatum atque accusantium!',
'moreText': '更多',
'moreLink': '/content'
},
{
'icon': 'fa-wrench',
'title': 'new',
'body': 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi amet numquam molestiae temporibus, aspernatur illum quas.',
'moreText': '更多',
'moreLink': '/content'
},{
'icon': 'fa-bug',
'title': 'new',
'body': 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Error, non laborum! Consequatur velit facere odit dolorem?',
'moreText': '更多',
'moreLink': '/content'
}
]
%}{% include '@easy_ui/ui/showcase-v1.html.twig' with data %}
前端组件定义好静态预览数据,使用 default 函数设置默认值,当父组件的 data 没有传数据时使用静态数据,意味着:
可以静态化预览前端组件;
后端可以传递数据给前端组件;
{# 父组件 showcase-v1.html.twig #}{% set items = [
{
'icon': 'fa-picture-o',
'title': '响应式设计',
'body': 'At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ',
'moreText': '更多',
'moreLink': '/content'
},
{
'icon': 'fa-wrench',
'title': '组件化开发',
'body': 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat ',
'moreText': '更多',
'moreLink': '/content'
},{
'icon': 'fa-bug',
'title': '市场应用',
'body': 'Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. ',
'moreText': '更多',
'moreLink': '/content'
}
]
%}<div class="container">
<div class="row">
{% for item in data|default(items) %}
<div class="col-sm-4 col-md-4">
{% include '@easy_ui/ui/box/box-v1.html.twig' with item %}
</div>
{% endfor %}
</div></div>
这样,带来怎样的好处:
前后端都可以使用include引入相同的showcase-v1.html.twig组件,谁给什么数据就渲染什么数据,没有数据使用静态数据;
父组件的多个子组件,只需要维护一个子组件
前端同学是不是和熟悉,这不就是类似Angular组件化开发吗:)
参考资料
HTTPS://TWIG.SYMFONY.COM/DOC/3.X/TAGS/INCLUDE.HTML
HTTPS://TWIG.SYMFONY.COM/DOC/3.X/TAGS/FOR.HTML
HTTPS://TWIG.SYMFONY.COM/DOC/3.X/FILTERS/DEFAULT.HTML
HTTPS://TWIG.SYMFONY.COM/DOC/3.X/TEMPLATES.HTM