子在川上曰

  逝者如斯夫不舍昼夜
随笔 - 71, 文章 - 0, 评论 - 915, 引用 - 0
数据加载中……

个性化页面布局的设计思考与Rails初步实现

象博客,以及google的iGoogle,都可以个性化页面布局---对页面模块增删改,以及调整位置。这种效果是如何实现的呢?在我的项目中也面临到 这个需求。我最初的解决方法是创建几个典型的rhtml布局组合。但这远远不够,而且不灵活,在形式上也不统一。于是我再次修改了设计,之后似乎可以基本 解决这个问题了。希望感兴趣的朋友一起来讨论。

这个设计其实很简单,就是“引擎+配置“--主体页面只定义一个rthml,可以把它看做页面引擎,然后用一个配置文件指定了页面所应具有的模块和数据。 页面模块就象一个个装有数据的盒子,通过“页面引擎 + 配置文件”把这些盒子组合起来,象搭积木一样。页面引擎是各用户共用的,配置文件是各用户独有的,这样一装配起来,就形成了用户的个性化页面。

剩下的重点就是怎么定义配置文件。首先是要划清配置文件的责任界线----它只负责定义盒子里的数据,还有盒子的嵌套关系,而大小和位置等布局方面则全部交给CSS去负责。

上面是初步想法,下面看看具体实现,代码仅供参考

以下是某个用户的配置文件(我没用XML,而是用YAML)。board_1是指ID=1这个栏目所用的配置定义。topContent是一个
<div>的id值,我把每个栏目的页面分成topContent顶、sideContent边(左或右由CSS决定)、primaryContent 主要、bottomContent底。topic是指添加一个模块(盒子),显示一个主题内容。和topic类似是还有显示图像的image、显示主题列 表的topics、显示分类列表的categories等等等等。它们各有不同的属性值,比如topic模块,它需要定指它的主题id,以及它所用的 view(topics/_show_hot.rhtml  or  topics/_show.rhtml等等)。

(虽然这个配置文件抽象得还不够,但这样子已经可以解决我的需要了,那
暂时这样先了。)

template.yml
 
  1. board_2:  
  2.   
  3. board_1:  
  4. - topContent:  
  5.   - topic:  
  6.       topic_id: 7  
  7.       view: topics/show_hot  
  8. - sideContent:  
  9.   - image:  
  10.       url: /images/news.jpg  
  11.   - categories:  
  12.       board: 5  
  13.       view: tree  
  14.   - topics:  
  15.       board: 5  
  16.       per_page: 4  
  17.       view: index_simple  
  18.   - topics:  
  19.       board: 6  
  20. - primaryContent:  
  21.   - topics:  
  22.       board: 4  
  23.       view: index  
  24.   - topic:  
  25.       topic_id: 7  
  26.       view: util/box  
  27.   
  28. board_3:  

然后在controller里把配置文件读入,再转化成模型类。我把各个界面模块看做一个个盒子Box
这是它的顶级Box
ruby 代码
 
  1. class Box  
  2.   attr_accessor :html_id:view:boxes  
  3.   def initialize
  4.     @boxes=[]  
  5.   end  
  6. end  

这是topic模块的
ruby 代码
 
  1. class TopicBox < Box  
  2.   attr_accessor :topic_id  
  3. end  

这是Image模块的
ruby 代码
 
  1. class ImageBox < Box  
  2.   attr_accessor :url  
  3. end    

.....等 等, 其他的Box子类大同小异

然后在一个controller里把这些配置信息转成Box模型类
ruby 代码
 
  1. templates =  YAML::load(File.read("public/uploads/#{user_id}/config/template.yml"))
  2. template = templates.find{|o| o[0]=="board_#{@board.id}" }  
  3. args = template[1]  
  4.   
  5. @boxes = []  
  6. args.each do |arg1_hash|  
  7.   arg1_hash.each do |key1, value1|  
  8.     board_box = BoardBox.new  
  9.     board_box.html_id = key1  
  10.     @boxes << board_box  
  11.     value1.each do |arg2_hash|  
  12.       arg2_hash.each do |key2, value2|  
  13.         case key2  
  14.         when 'topics'  
  15.           box = TopicsBox.new  
  16.           box.board_id = value2['board']  
  17.           box.per_page = value2['per_page']||2  
  18.           box.view = value2['view']||'index_simple'  
  19.           board_box.boxes << box   
  20.         when 'categories'  
  21.           box = CategoriesBox.new  
  22.           box.board_id = value2['board']  
  23.           box.view = value2['view']||'list'  
  24.           board_box.boxes << box   
  25.         when 'image'  
  26.           box = ImageBox.new  
  27.           box.url = value2['url']  
  28.           board_box.boxes << box   
  29.         when 'topic'  
  30.           box = TopicBox.new  
  31.           box.topic_id = value2['topic_id']  
  32.           box.view = value2['view']||'util/box'  
  33.           board_box.boxes << box   
  34.         end  
  35.       end  
  36.     end  
  37.   end  
  38. end 

最后是它页面引擎(逻辑代码和页面代码混在一起,比较丑陋)
ruby 代码
 
  1. <% @boxes.each do |box1| %>  
  2. "<%=box1.html_id%>">  /span>
  3.   <% box1.boxes.each do |box2|  
  4.        p1 box2.class.to_s  
  5.   
  6.       case box2.class.to_s  
  7.       when 'TopicsBox'  
  8.         board_id = box2.board_id  
  9.         if board_id  
  10.           board = Board.find(board_id)  
  11.           topics = Topic.by_board_id(board_id, :per_page => box2.per_page)   
  12.           %>  
  13.           <%= render(:partial => "topics/#{box2.view}":locals => {:title =>board.title, :topics => topics })%>  
  14.         <%end  
  15.       when 'CategoriesBox'  
  16.         board_id = box2.board_id  
  17.         if board_id  
  18.           board = Board.find(board_id)  
  19.           categories = board.categories  
  20.           %>  
  21.           <%= render :partial => "categories/#{box2.view}":locals => {:board =>board, :categories => categories } %>  
  22.         <%end%>  
  23.       <%when 'ImageBox'%>  
  24.         <%= box_tag :header=>false%>  
  25.           <%=image_tag(box2.url, :border => 0) %>  
  26.         <%= end_box_tag %>  
  27.       <%when 'TopicBox'  
  28.         topic = Topic.find(box2.topic_id) %>  
  29.         <%=render(:partial => "#{box2.view}":locals => {:title =>topic.title, :content => topic.content, :topic => topic })%>  
  30.       <%end  
  31.   end%> 
 

这样,以后想在页面上增加删除什么模块,修改配置文件就行了。当然给用户用,还必须得用AJAX来写个GUI界面,总不能让用户手工去改配置文件吧。

posted on 2007-10-11 00:00 陈刚 阅读(3572) 评论(0)  编辑  收藏 所属分类: Rails&Ruby


只有注册用户登录后才能发表评论。


网站导航: