前后端开发配合
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