如何水水地写一个网站。(草稿)

这篇将介绍用比较简单的方式来写一个网站

一、语言问题

如果你是选择了Ruby的话,太牛了,我还没接触过。
如果你是选择了Python的话,写个网站,django一定是首选,很遗憾我也没接触过。
如果你是选择了PHP的话,那就太好了,因为我也是一个PHP水货。

所以语言问题解决了,就用PHP。

二、框架问题

首先是PHP的框架,当时作为小白的我面对这个问题果断地去问了Luin神,Luin神推荐了Yii。
然后我就去看了看,果断放弃了,的确不大易入门。探索过程之中发现了codeigniter,也就是CI框架。
这个框架的优点在于有异常清新的文档。

http://codeigniter.com.cn/user_guide/

这个典型的MVC框架+社区很活跃,无疑是一个比较好的选择。


其次就是前端框架了,果断用了twitter的bootstarp。
因为你没有UI,没有前端做出来的效果一定很挫,抱着把站搭出来的目的,这个是一个很好的选择了。

http://twitter.github.com/bootstrap/

这个东西的确像它宣传的那样,适合各个水平的用户,稍后细讲吧。


三、开始学着使用框架

1.写静态页

作为一个什么也不会的孩子,先写静态页是最明智的选择了。

其实产品设计师也可以写写静态页,有些时候比用Axure做原型还快,保真度还高。

学习写静态页的第一步就是找一个网站抄。
怎么抄呢? 你要现有个Chrome浏览器吧。(我不大喜欢firefox。。。) 打开bootstarp的介绍页面,右键审查元素。 慢慢地看里面的代码是怎么写的,页面的样子是什么样的。 然后自己新建个空白文档,把CSS,JS引用上,开始自己不断地尝试。

其实一段时间之后你就会发现,你用到的也就是那么多。

首先是布局。
(1)栅格化,页面宽等分为12份,弄出1、2、9三个宽度的DIV。

<div class="row">
    <div class="span3">
        <div class="row">
            <div class="span1">
            </div>
            <div class="span2">
            </div>
        </div>
    </div>
    <div class="span9">
    </div>
</div>

响应式布局神马的我觉得就不要用了。个人不看好那个东西。 (2)icon,bootstrap自带了很多比较好看的icon基本可以满足需求。

<i class="icon-search icon-white"></i>

(3)button,label,badge

其实就是class="xxx xxx-yyy"来达到不同的颜色

(4)form,table,navbar 照着抄就行了。

不多讲了

(5)各种效果、Modals与Dropdowns是比较常用的,其实不用懂那么多。

<a href="#" class="btn btn-danger" rel="popover" data-content="And here's some amazing content. It's very engaging. right?" data-original-title="A Title">hover for popover</a>

这是Popovers的样例代码,读过application.js那个文件的同志们就应该明白,其实各种效果的实现都是依靠'rel'、 ‘data-xxx’等实现的。各种效果无非就是里面的参数不同而已。即使要自己的特殊定制,直接调用它们封装好的函数即可。

(6)html页面要css和js文件。css文件就不多说了,就那一个官方的文件。js文件通常要包含以下几个:

<script src="/assets/js/jquery-1.7.2.min.js"></script>
<script src="/assets/js/bootstrap.min.js"></script>
<script src="/assets/js/application.js"></script>

.min 就是压缩过的,加载速度变快的效果还是很明显的。
application.js 就是实现了DEMO中各种效果的一些按钮监听什么的,有兴趣可以去看看。

(7)光用bootstarp自带的肯定是不够的,而且有时候需要对部分地方重新定义,你可以新建一个css文件,用同名的类直接覆盖掉之前的就可以了。js每个页面也来个单独的js文件。


2.开始学习ci框架了。

无疑就是开始上来看文档

http://codeigniter.org.cn/user_guide/index.html

遇到看不懂的就过,其实就是很普通的MVC。 不过后端框架问题就是多,你需要环境呀、什么apache\php,数据库什么的先不说了。 mac下这些都比较好搞。

http://dancewithnet.com/2010/05/09/run-apache-php-mysql-in-mac-os-x/

随网之舞的这篇文章的确很好用。
然后你就可以在~目录下建若干个网站,然后配置几个虚拟主机(上面的域名随便写),然后去改hosts文件把虚拟主机用的域名都换成127.0.0.1就好了。

之后去github上clone下,就可以开始体验了。

https://github.com/EllisLab/CodeIgniter/tree/2.1-stable

放到网站根目录后访问,会看到welcome页面。

其实用CI开发只需关注几点。

/application/controllers/ 存放C层文件
/application/models/ 存放M层文件
/application/views/ 存放V层文件
/application/config/ 存放配置文件
/application/libraries 存放一些你需要的文件

自建目录
/assets/{js/ico/css/img} 存放各种这些文件

自建目录
/scripts/sql/ 存放sql文件

基本就这么多。

CI的程序入口在根目录下的index.php,所有的访问必经过这里。 所以你可以在这个文件中加句

date_default_timezone_set("Asia/Shanghai");

当然也可以加别的东西啦~

接下来从C层开始说,
C层的文件都放在/application/controllers/
这里的文件名xyz就对应着url中的www.example.com/index.php/xyz

这里插一段,index.php出现在URL中不好看,所以要使用.htaccess 这个东西。先在httpd.conf 中开启.htaccess 然后去网站根目录

touch .htaceess
vim .htaccess
#把下面这段粘进去
RewriteEngine on  
RewriteCond $1 !^(index\.php|favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

这样我们就可以直接访问www.example.com/xyz 当然你也可以利用config文件中的routes.php来将URL与文件对应。

CI 的MVC三层都支持一级文件夹,就是说我建一个test.php文件,我可把它放到/application/controllers/c/test

先给一个DEMO吧,omarhub.huiter.me/c/test
---

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * 测试环境 
 */


class Test extends CI_Controller
{        
    public function __construct()
    {
        parent::__construct();    
    }

    public function index()
    {
        $template['content'] = $this->load->view('test_view',$this->template,TRUE);
        $template['css'] = $this->load->view('test_css',$this->template,TRUE);
        $template['js'] = $this->load->view('test_js',$this->template,TRUE);
        $this->load->view('template_view',$template);
    }

}
/* End of file test.php */
/* Location: ./application/controllers/c/test.php */ 

上面给出了对应的test.php文件。
类名要与文件名一致,且首字母大写,下划线什么的不要乱用了。
继承于CI_Controller,你也可以自己写一个Controller 继承于CI_Controller。

如在/application/core/下建一个Huiter_Controller 做一些自己的定义,然后在config文件夹下的config.php文件中进行这个设置$config['subclass_prefix'] = 'Huiter_';

进入test.php文件都会先执行index()
上面那几行代码的意思就是将content\css\js内容都存在了template数组中,然后传给template_view,然后输出。
这里用到了一个函数$this->load-view('','','');
三个参数第一个是对应着/application/views中的文件,第二个是传递的参数,第三个TRUE表述不直接输出到页面上。

如何给index()传递参数呢,这一点需要了解CI的URL。

如果我把这上的index()函数定义改为index($word='')
然后访问.../c/test/hello
那么在index函数体中就可以用$word接收到参数了。
当然你也可以用$this->input->get();或者$this->input->post();来接收参数。

下面我看讲下view层的东西吧。
这里我依然使用了php与html混写。 在这里,你大概只需要知道三件事,

如何拿到C层的变量并输出
如何写循环
如何写判断

首先来看下C层的代码:

$template['content'] = $this->load->view('test_view',$this->template,TRUE);
$template['css'] = $this->load->view('test_css',$this->template,TRUE);
$template['js'] = $this->load->view('test_js',$this->template,TRUE);
$this->load->view('template_view',$template);

这里我将$template传给了template_view,然后来看一下template_view的代码吧。

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
            <title>By huiter</title>
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta name="description" content="">
            <meta name="author" content="huiter">
            <!-- Le styles -->
                <link href="/assets/css/bootstrap.css" rel="stylesheet">
                <?php if ( isset ($css) && ! empty($css)): ?>
                    <?php print $css; ?>
                <?php endif ?>

            <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
            <!--[if lt IE 9]>
            <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
            <![endif]-->
            <!-- Le fav and touch icons -->         
            <link rel="shortcut icon" href="/assets/ico/favicon.ico">
    </head>

    <body>
    <div class="container">

        <?php if ( isset ($content) && ! empty($content)): ?>
            <?php print $content; ?>
        <?php endif ?>

    </div> 
    <!-- /container -->
    <!--[if IE 6]>
    <script src="http://letskillie6.googlecode.com/svn/trunk/letskillie6.zh_CN.pack.js"></script>
    <![endif]-->
        <script src="/assets/js/jquery-1.7.2.min.js"></script>
        <script src="/assets/js/bootstrap.min.js"></script> 
        <script src="/assets/js/application.js"></script>
         <?php if ( isset ($js) && ! empty($js)): ?>
            <?php print $js;?>
        <?php endif ?>  
    </body>
</html>

这里我们可以看到

<?php if ( isset ($css) && ! empty($css)): ?>
    <?php print $css; ?>
<?php endif ?>

通过这种方式,我们就可以就可以将template数组中的$css读出来了。
这里我们可以看到if语句的基本写法,下面再给一个for的写法。
假设我们在C层令

$template['info'] = array("a"=>"Dog","b"=>"Cat","c"=>"Horse");

那么我们可利用这样的方式,来获取值

<?php foreach ($info as $key => $value) :?>
    <span><?php echo $key;?></span> 
    <span><?php echo $value;?></span>       
<?php endforeach;?>

这样我们就可以得到

<span>a</span>
<span>Dog</span>
<span>b</span>
<span>Cat</span>
<span>c</span>
<span>Horse</span>

知道这些基本就可以通过判断和循环来向html中加入对应的数据,或者输出哪些html不输出哪些html 例如

<ul class="nav">
    <li <?php if($page=='home'):?>class="active"<?php endif;?>><a href="/home">写心情</a></li>  
    <li <?php if($page=='about'):?>class="active"<?php endif;?>><a href="/about">关于</a></li>
    <li class="divider-vertical"></li>
</ul>

这样就可以我们传递进来一个值page来表述当前页,令navbar中的当前页的选项为选中状态,
这一点是通过加一个class="active"实现的。

view层基本介绍到这了。

这时,你就可以把自己写好的静态页拆分下,把公共部件提取成小view,然后用CI框架实现它。

现在,我假设你已经能运用C、V两层了。 之后,我们就可以来看M层了。

首先跳转至CI文档

http://codeigniter.org.cn/user_guide/database/index.html

这里你需要配置个mysql。如果你要玩mongodb的话也是可以的。 其实这个文档你只需关注两点

如何设置数据库的相关配置使你能连接上数据库
怎么执行各种数据库操作

关于数据库配置,文档讲的很详细了。 怎么执行各种操作呢,建议可以直接去

http://codeigniter.org.cn/user_guide/database/active_record.html

用Active Record 类可以很好地完成各种操作,主要是省去了很多防注入的工作。

给个M层的demo

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Offer_model extends CI_Model {

    function __construct()
    {
        parent::__construct();
    }


    function get_entry_byoffer_url_token($offer_url_token)
    {
        $this->db->select('offer.*,fellow.fellow_url_token,fellow.first_name,fellow.last_name');
        $this->db->from('offer');
        $this->db->join('fellow','offer.fellow_id = fellow.id');
        $this->db->where('offer_url_token',$offer_url_token);

        $query = $this->db->get();
        return $query->row_array();
    }

    function get_entrys_bynothing($number,$time_stamp,$orderby)
    {
        $this->db->select('offer.*,fellow.fellow_url_token,fellow.first_name,fellow.last_name');
        $this->db->from('offer');
        $this->db->join('fellow','offer.fellow_id = fellow.id');
        $this->db->where('offer.created <=',$time_stamp); 
        $this->db->order_by($orderby,'desc');
        $this->db->limit($number);

        $query = $this->db->get();

        return $query->result_array();
    }


    function insert_entry($data)
    { 
        $this->db->insert('offer', $data);
        return mysql_insert_id();
    }


    function delete_entry_byoffer_url_token($offer_url_token)
    {
        $this->db->delete('offer', array('offer_url_token' => $offer_url_token)); 
        return 1;
    }
}

看一看文档就很容易理解这一切。

在C层

    $this->load->model('offer_model','',TRUE);
    $offer = $this->offer_model->get_entry_byoffer_url_token($offer_url_token);

加载刚刚可写的offer_model,然后调用里面的函数,用$offer获取。

现在我们知道数据怎么从C层传递给V层,知道怎么从M层拿数据到C层。 我们基本上完成了对C框架的初步认识。

而对框架的使用,或者说是网站开发的难点就是在于设计。
如何管理好你的这些代码,MVC三层就够了么?
数据层是不是要分的更细?
asp.net中三层结构BLL\DAL\ENRTY很具有参考意义。
加上每个.aspx文件都有对应的.cs文件
相当于一个v 一个c。
BLL层对数据处理成直接可用的数据。
DAL层负责从连接数据库从数据库中拿出需要的数据。
ENTRY层负责定义对象。(面向过程,这个无所谓啦。)
其实就相当于在我们CI的MVC三层中加一个层来将从数据库中拿到的数据进行下处理输出给C。
所以4层-5层结构还是比较有必要的。

当然也不是分的越细越好,什么事情都要有度,太多层管理起来就复杂了。
毕竟一切都是为了交付么。


四、一些探索

1、X层结构

数据库:mysql,表与对象对应。
M层:从数据库中拿数据,主要就是写各种SQL语句,对于需要多表的查询一律使用join。
API层:仿restful风格。接受数据$in,输出数据$out,与M层通讯。
C层:页面跳转逻辑,从API获取数据,传至V层,输出页面。
V层:通过文件夹的方式按页面分隔view文件,并抽取公共组建放入template文件夹。

封装API的好处就是测试可以前后端分离。
而且在网站实现方式上有更多的选择。
你可以用PHP去实现。你也可以Node.js去实现。你也可以去做IOS\Android客户端。

2、相关配套设置

CI REST:http://github.com/philsturgeon/codeigniter-restserver
Jquery写的测试工具或使用Chrome插件POSTMAN
新浪SAE(免费。。。)

有了这些就可以搞一个在Internet上的网站了。

3、其他的东西

(1)好看的网站模版获取:365psd.com, onepagelove.com, themeforest.net
(2)node.js less jade coffeescript backbone (3)zombie.js:内存型浏览器 。。。