怎样保存 Checkbox 值

预备知识点:

二进制数值:
0的二进制数值是   0
1的二进制数值是   1
2的二进制数值是  10
3的二进制数值是  11
4的二进制数值是 100
5的二进制数值是 101
6的二进制数值是 110
...
在 php 中可以通过 decbin() 函数将十进制数字转换为二进制数字.

位运算符 & (按位与), 什么是 & 运算呢?
以 $c = $a & $b 表达式为例, & 运算是将 $a, $b 的二进制数值相比较, 只要两个二进制数中某位都是1, 则结果的二进制数中该位都为1, 否则结果为 0.

假设:
$a 的值为 2 (十进制), 它的二进制数值为  10
$b 的值为 4 (十进制), 它的二进制数值为 100
那么 $c 为 0 (十进制) 因数 $a & $b 的结果为 000(二进制数值), 转换为十进制数值就为 0

假设:
$a 的值为 2 (十进制), 它的二进制数值为  10
$b 的值为 6 (十进制), 它的二进制数值为 110
那么 $c 为 2 (十进制) 因数 $a & $b 的结果为 010(二进制数值), 转换为十进制数值就为 2

Javascript/php/mysql 都支持 & 运算.

OK. 进入正题:
我们现在要记录用户的兴趣爱好, 兴趣爱好有很多选项, 可以复选, 表现在页面上就是一堆的 checkbox , 它看起来像是这样子的

<input type="checkbox" name="hobby[]" value="aa">爱好1 <br>
<input type="checkbox" name="hobby[]" value="bb">爱好2 <br>
<input type="checkbox" name="hobby[]" value="cc">爱好3 <br>
<input type="checkbox" name="hobby[]" value="dd">爱好4 <br>
<input type="checkbox" name="hobby[]" value="ee">爱好5 <br>
<input type="checkbox" name="hobby[]" value="ff">爱好6 <br>
<input type="checkbox" name="hobby[]" value="gg">爱好7 <br>

假设用户勾选的是 "爱好1", "爱好3", "爱好5", 我们要怎么把用户勾选的值保存到数据库呢?

方法1:

用特定的分隔符(比如,)把用户勾选的 value 值串连起来? 那么保存到数据库中的值应该是 "aa,cc,ee"
还有别的方法吗?

方法2:

保存到数据库的值是 "1010100" , 这个字串是怎么得来的呢? 设计这种方法的思想是这样的: 数据库中保存一个长度与复选框个数一样的字符串, 这个字串中的第一位就表示第一个复选框, 如果第一个复选框的勾选了, 那字串的第一位就是1. 同样的道理所以字串的第3位,第5位值为1, 其它位值为0.
还有别的方法吗?

我用的是方法3:

重新设计 checkbox 的值, 将它们设置成2的N(N>=0)次方. 它看起来像这样子:
<input type="checkbox" name="hobby[]" value="1" >爱好1 <br>
<input type="checkbox" name="hobby[]" value="2" >爱好2 <br>
<input type="checkbox" name="hobby[]" value="4" >爱好3 <br>
<input type="checkbox" name="hobby[]" value="8" >爱好4 <br>
<input type="checkbox" name="hobby[]" value="16">爱好5 <br>
<input type="checkbox" name="hobby[]" value="32">爱好6 <br>
<input type="checkbox" name="hobby[]" value="64">爱好7 <br>
而我要保存到数据库中的值是 21, 没错, 它是一个数字, 它是怎么来的呢? 1+4+16 = 21, 它就是将用户勾选的复选框 value 值累加而以.

为什么是2的N(N>=0)次方? ( 1, 2, 4, 8, 16, 32, ... )

<?php
//我们来看看它们的二进制数值有什么特点.
echo decbin(1)."<br>";   //       1
echo decbin(2)."<br>";   //      10
echo decbin(4)."<br>";   //     100
echo decbin(8)."<br>";   //    1000
echo decbin(16)."<br>";  //   10000
echo decbin(32)."<br>";  //  100000
echo decbin(64)."<br>";  // 1000000

//来看问题: 为什么要把 value 值设置为2的N(N>=0)次方?
//因为2的N(N>=0)次方数字的二进制表示一定是最左边第一位是1, 其它位是0,
//而正是这样的特性, 使得任意2的N(N>=0)次方数字相加, 都不会在其对应的二进制数字中出现进位的状况.
//什么意思? 举个例子:
//1+2+4 二进制表示是 1+10+100
//1+2+3 二进制表示是 1+10+11  <-- 这样会使右边第一位,第二位出现进位

//再来看个例子
echo decbin(1+2)."<br>";     //    11
echo decbin(1+2+4)."<br>";   //   111
echo decbin(4+8)."<br>";     //  1100
echo decbin(1+4+16)."<br>";  // 10101
//结合"任意2的N(N>=0)次方数字相加, 都不会在其对应的二进制数字中出现进位的状况"的特性, 很容易分析出上面例子中的规律:
//结果值的二进制数值中如果右边第一位是1, 那么结果值的十进制数值一定是 1+***
//结果值的二进制数值中如果右边第二位是1, 那么结果值的十进制数值一定是 2+***
//结果值的二进制数值中如果右边第一位是1,右边第二位也是1, 那么结果值的十进制数值一定是 1+2+***

//我们回到用户勾选爱好复选框保存到数据库中的值 21 (十进制)
//通俗点, 我们可以这样理解:
//2的N(N>=0)次方数字的和(例如21) 的二进制表示(10101), 从右至左如果第n位为1, 那它十进制一定是 2 的 n-1 次方与其它2的N(N>=0)次方数字的和
//所以 21(二进制表示为 10101) 应该是 (2的(1-1)次方)+(2的(3-1)次方)+(2的(5-1)次方) = 1+4+16

//同样根据"任意2的N(N>=0)次方数字相加, 都不会在其对应的二进制数字中出现进位的状况"的特性, 结合我们已知的 & 运算, 我们能很方便的判断 任意2的N(N>=0)次方数字相加的和中是否存在一个确定的2的N(N>=0)次方数字
echo (21 & 1)."<br>";   // 1
echo (21 & 2)."<br>";   // 0
echo (21 & 4)."<br>";   // 4
echo (21 & 8)."<br>";   // 0
echo (21 & 16)."<br>";  // 16
echo (21 & 32)."<br>";  // 0
echo (21 & 64)."<br>";  // 0
?>

我们来看看页面前端 javascript 是怎么保存和还原用户勾选的选项的:
在线实例

<input type="button" value="要保存到数据库中的值" onclick="get_save_value('hobby[]')">
<input type="button" value="清除勾选" onclick="clear_all('hobby[]')"> <br>
<br>还原勾选框<br>
<input type="text" name="set_check_value" id="set_check_value"><br>
<input type="button" value='先点击 "清除勾选" 再点我' onclick="set_check('hobby[]', document.getElementById('set_check_value').value)"> <br>

<script language="JavaScript">
/* 重点 */
//还原用户的选取项
function set_check(name, value){
    var obj = document.getElementsByName(name);
    for(var i=0; i<obj.length; i++){
        if( (obj[i].value & value) == obj[i].value ){
            obj[i].checked = true;
        }
    }
}

/* 这不是重点 */
function get_save_value(name){
    var obj = document.getElementsByName(name);
    var saveValue = 0;
    for (var i=0; i<obj.length; i++){
        if (obj[i].checked){
            saveValue += parseInt(obj[i].value);
        }
    }
	document.getElementById("set_check_value").value = saveValue;
    alert(saveValue); //这个就是要存到数据表里的值
}

function clear_all(name){
    var obj = document.getElementsByName(name);
    for (var i=0; i<obj.length; i++){
        obj[i].checked = false;
    }
}
</script>

我们来看看后端数据库是查询用户勾选项的:
假设我们 tableName 中的 hobby 字段是保存用户的兴趣爱好值
一个用户一第记录, 如果前面的例子成功记录到数据库中, 那么 tableName 中应该有一条 hobby==21 的值的记录.

--要查询选择了"爱好1"或者"爱好3"的用户:
--爱好1(value=1)
--爱好3(value=4)
SQL: SELECT * FROM tableName WHERE (hobby&1) OR (hobby&4);

--要查询选择了"爱好1"并且"爱好3"的用户:
--爱好1(value=1)
--爱好3(value=4)
SQL: SELECT * FROM tableName WHERE (hobby&1) AND (hobby&4);

--要查询只选择了"爱好1"和"爱好3"的用户:
--爱好1(value=1)
--爱好3(value=4)
SQL: SELECT * FROM tableName WHERE hobby=(1+4)
This entry was posted in JavaScritp, Mysql, PHP, html and tagged , , , . Bookmark the permalink. Trackbacks are closed, but you can post a comment.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>