写了个jquery的自动填充form插件

最近发现每次做后台编辑数据的时候, 给表单设置默认值都很麻烦, 这次干脆写了一个jquery插件, 直接自动填充表单, 省去php一个一个的写, 这样代码可读性也好了很多.

jquery.autofill.js

  1. jQuery.fn.extend({
  2. autofill: function (data) {
  3. if (!data || !$.isPlainObject(data)) {
  4. return;
  5. }
  6. for (var name in data) {
  7. if ($.isArray(data[name])) {
  8. var field = $('[name="' + name + '[]"]', this);
  9. field.each(function () {
  10. if (data[name].indexOf($(this).val()) >= 0) {
  11. $(this).attr('checked', 'checked');
  12. }
  13. });
  14. } else {
  15. var field = $('[name="' + name + '"]', this);
  16. field.each(function () {
  17. switch ($(this).attr('type')) {
  18. case 'radio':
  19. if ($(this).val() === data[name].toString()) {
  20. $(this).attr('checked', 'checked');
  21. }
  22. break;
  23. default:
  24. $(this).val(data[name]);
  25. break;
  26. }
  27. });
  28. }
  29. }
  30. }
  31. });

使用方法 ./test.php

  1. <!DOCTYPE HTML>
  2. <html lang="en-US">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <link href="css/bootstrap.css" rel="stylesheet" type="text/css"/>
  7. </head>
  8. <body>
  9. <div class="container">
  10. <form action="?" method="post" id="form">
  11. 姓名: <input type="text" name="name" id="" />
  12. <br />
  13. 年龄: <input type="number" name="age" id="" />
  14. <br />
  15. 性别:
  16. <input type="radio" name="sex" value="1" id="" />
  17. <input type="radio" name="sex" value="0" id="" />
  18. <br />
  19. 省份:
  20. <select name="area" id="">
  21. <option value="-1">选择省份</option>
  22. <option value="shanghai">上海</option>
  23. <option value="beijing">北京</option>
  24. <option value="henan">河南</option>
  25. </select>
  26. <br />
  27. 爱好:
  28. <input type="checkbox" name="hobby[]" value="book" id="" /> 看书
  29. <input type="checkbox" name="hobby[]" value="coding" id="" /> 写代码
  30. <input type="checkbox" name="hobby[]" value="games" id="" /> 打游戏<br />
  31. 简介:
  32. <textarea name="content"></textarea>
  33. <br />
  34. <input type="submit" value="提交" />
  35. </form>
  36. <!-- 这里是数据 -->
  37. <div class="hidden" id="data">
  38. <?php
  39. $data = [
  40. 'name' => 'shuai',
  41. 'age' => '25',
  42. 'area' => 'henan',
  43. 'sex' => 0,
  44. 'hobby' => ['book', 'games'],
  45. 'content' => 'hello world',
  46. ];
  47. echo json_encode($data);
  48. ?>
  49. </div>
  50. </div>
  51. <script src="jquery.min.js" type="text/javascript"></script>
  52. <script src="jquery.autofill.js" type="text/javascript"></script>
  53. <script type="text/javascript">
  54. $(function () {
  55. var data = $.parseJSON($('#data').text());
  56. $('#form').autofill(data);
  57. });
  58. </script>
  59. </body>
  60. </html>

访问

一种同步登录的解决方案

这几天碰到一个需求, 登录A站的时候, 同时自动登录B站, 有可能会有多个B站, 所以想到了有 B站主动发起请求的方式, 解决这个自动登录问题

流程是这样的:

  1. 打开 A站 登录 或 不登录.
  2. 打开 B站 .
  3. B站 自己判断是否存在用户session
  4. 存在就说明已经登录, 操作结束
  5. 没有session, 就给页面输出一个js, 去 A站 用json获取登录用户的token
  6. 如果没有token, 说明没有登录 A站, 不做任何处理.
  7. 如果获取到token, 就ajax向 B站 自己的后台发起同步登录信号
  8. B站 后台通过前台传来的token, 请求 A站 用户数据.
  9. B站 后台请求到用户数据后做自动登录的cookie写入.
  10. 登录成功, 刷新页面

写了一个ThinkPHP的模板引擎, 仿angular的, 简单版

前段时间学习angularjs, 里面的模板思想和实现方法很酷, 就心血来潮, 想实现一个php版的, 今天试着写了一下, 发现貌似可以, 具体看源码.

./ThinkPHP/Library/Think/Template/Driver/Angular.class.php

  1. <?php
  2. namespace Think\Template\Driver;
  3. use Think\Storage;
  4. /**
  5. * Angular模板引擎驱动
  6. */
  7. class Angular {
  8. private $config = array();
  9. private $tpl_var = array();
  10. /**
  11. * 架构函数
  12. */
  13. public function __construct() {
  14. $this->config['cache_path'] = C('CACHE_PATH');
  15. $this->config['tpl_dir'] = THEME_PATH;
  16. $this->config['cache_path'] = C('CACHE_PATH');
  17. $this->config['template_suffix'] = C('TMPL_TEMPLATE_SUFFIX');
  18. $this->config['cache_suffix'] = C('TMPL_CACHFILE_SUFFIX');
  19. $this->config['tmpl_cache'] = C('TMPL_CACHE_ON');
  20. $this->config['cache_time'] = C('TMPL_CACHE_TIME');
  21. $this->config['attr'] = 'tp-';
  22. }
  23. /**
  24. * 编译模板
  25. * @param type $tpl_file 模板文件
  26. * @param type $tpl_var 模板变量
  27. */
  28. public function fetch($tpl_file, $tpl_var) {
  29. $this->tpl_var = $tpl_var;
  30. $tpl_file = $this->load_template($tpl_file);
  31. Storage::load($tpl_file, $tpl_var, null, 'tpl');
  32. }
  33. /**
  34. * 加载主模板并缓存
  35. * @param string $tpl_file 模板文件名
  36. * @return string 缓存的模板文件名
  37. */
  38. public function load_template($tpl_file) {
  39. if (is_file($tpl_file)) {
  40. // 读取模板文件内容
  41. $tpl_content = file_get_contents($tpl_file);
  42. } else {
  43. $tpl_content = $tpl_file;
  44. }
  45. // 根据模版文件名定位缓存文件
  46. $tpl_cache_file = $this->config['cache_path'] . md5($tpl_file) . $this->config['cache_suffix'];
  47. if (Storage::has($tpl_cache_file) && !APP_DEBUG && $this->config['tmpl_cache']) {
  48. return $tpl_cache_file;
  49. }
  50. // 编译模板内容
  51. $tpl_content = $this->compiler($tpl_content);
  52. Storage::put($tpl_cache_file, trim($tpl_content), 'tpl');
  53. return $tpl_cache_file;
  54. }
  55. /**
  56. * 编译模板内容
  57. * @param string $tpl_content 模板内容
  58. * @return string 编译后端php混编代码
  59. */
  60. protected function compiler($tpl_content) {
  61. //模板解析
  62. $tpl_content = $this->parse($tpl_content);
  63. // 添加安全代码
  64. $tpl_content = '<?php if (!defined(\'THINK_PATH\')) exit();?>' . $tpl_content;
  65. // 优化生成的php代码
  66. $tpl_content = str_replace('?><?php', '', $tpl_content);
  67. return strip_whitespace($tpl_content);
  68. }
  69. /**
  70. * 解析模板标签属性
  71. * @param string $content 要模板代码
  72. * @return string 解析后的模板代码
  73. */
  74. public function parse($content) {
  75. while (true) {
  76. $sub = $this->match($content);
  77. if ($sub) {
  78. $method = 'parse_' . $sub['attr'];
  79. if (method_exists($this, $method)) {
  80. $content = $this->$method($content, $sub);
  81. } else {
  82. E("模板属性" . $this->config['attr'] . $sub['attr'] . '没有对应的解析规则');
  83. break;
  84. }
  85. } else {
  86. break;
  87. }
  88. }
  89. $content = $this->parse_value($content);
  90. return $content;
  91. }
  92. /**
  93. * 解析include属性
  94. * @param string $content 源模板内容
  95. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  96. * @return string 解析后的模板内容
  97. */
  98. private function parse_include($content, $match) {
  99. $tpl_name = $match['value'];
  100. if (substr($tpl_name, 0, 1) == '$') {
  101. //支持加载变量文件名
  102. $tpl_name = $this->get(substr($tpl_name, 1));
  103. }
  104. $array = explode(',', $tpl_name);
  105. $parse_str = '';
  106. foreach ($array as $tpl) {
  107. if (empty($tpl))
  108. continue;
  109. if (false === strpos($tpl, $this->config['template_suffix'])) {
  110. // 解析规则为 模块@主题/控制器/操作
  111. $tpl = T($tpl);
  112. }
  113. // 获取模板文件内容
  114. $parse_str .= file_get_contents($tpl);
  115. }
  116. return str_replace($match['html'], $parse_str, $content);
  117. }
  118. /**
  119. * 解析if属性
  120. * @param string $content 源模板内容
  121. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  122. * @return string 解析后的模板内容
  123. */
  124. private function parse_if($content, $match) {
  125. $new = "<?php if ({$match['value']}) { ?>";
  126. $new .= str_replace($match['exp'], '', $match['html']);
  127. $new .= '<?php } ?>';
  128. return str_replace($match['html'], $new, $content);
  129. }
  130. /**
  131. * 解析repeat属性
  132. * @param string $content 源模板内容
  133. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  134. * @return string 解析后的模板内容
  135. */
  136. private function parse_repeat($content, $match) {
  137. $new = "<?php foreach ({$match['value']}) { ?>";
  138. $new .= str_replace($match['exp'], '', $match['html']);
  139. $new .= '<?php } ?>';
  140. return str_replace($match['html'], $new, $content);
  141. }
  142. /**
  143. * 解析show属性
  144. * @param string $content 源模板内容
  145. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  146. * @return string 解析后的模板内容
  147. */
  148. private function parse_show($content, $match) {
  149. $new = "<?php if ({$match['value']}) { ?>";
  150. $new .= str_replace($match['exp'], '', $match['html']);
  151. $new .= '<?php } ?>';
  152. return str_replace($match['html'], $new, $content);
  153. }
  154. /**
  155. * 解析hide属性
  156. * @param string $content 源模板内容
  157. * @param array $match 一个正则匹配结果集, 包含 html, value, attr
  158. * @return string 解析后的模板内容
  159. */
  160. private function parse_hide($content, $match) {
  161. $new = "<?php if (!({$match['value']})) { ?>";
  162. $new .= str_replace($match['exp'], '', $match['html']);
  163. $new .= '<?php } ?>';
  164. return str_replace($match['html'], $new, $content);
  165. }
  166. /**
  167. * 解析普通变量和函数{$title}{:function_name}
  168. * @param string $content 源模板内容
  169. * @return string 解析后的模板内容
  170. */
  171. private function parse_value($content) {
  172. $content = preg_replace('/\{(\$.*?)\}/', '<?php echo \1 ?>', $content);
  173. $content = preg_replace('/\{\:(.*?)\}/', '<?php echo \1 ?>', $content);
  174. return $content;
  175. }
  176. /**
  177. * 获取第一个表达式
  178. * @param string $content 要解析的模板内容
  179. * @return array 一个匹配的标签数组
  180. */
  181. private function match($content) {
  182. $reg = '#<(?<tag>[\w]+)[^>]*?\s(?<exp>' . preg_quote($this->config['attr']) . '(?<attr>[\w]+)=([\'"])(?<value>[^\4]*?)\4)[^>]*>#s';
  183. $match = null;
  184. if (!preg_match($reg, $content, $match)) {
  185. return null;
  186. }
  187. $sub = $match[0];
  188. $tag = $match['tag'];
  189. /* 如果是但标签, 就直接返回 */
  190. if (substr($sub, -2) == '/>') {
  191. $match['html'] = $match[0];
  192. return $match;
  193. }
  194. /* 查找完整标签 */
  195. $start_tag_len = strlen($tag) + 1; // <div
  196. $end_tag_len = strlen($tag) + 3; // </div>
  197. $start_tag_count = 0;
  198. $content_len = strlen($content);
  199. $pos = strpos($content, $sub);
  200. $start_pos = $pos + strlen($sub);
  201. while ($start_pos < $content_len) {
  202. $is_start_tag = substr($content, $start_pos, $start_tag_len) == '<' . $tag;
  203. $is_end_tag = substr($content, $start_pos, $end_tag_len) == "</$tag>";
  204. if ($is_start_tag) {
  205. $start_tag_count++;
  206. }
  207. if ($is_end_tag) {
  208. $start_tag_count--;
  209. }
  210. if ($start_tag_count < 0) {
  211. $match['html'] = substr($content, $pos, $start_pos - $pos + $end_tag_len);
  212. return $match;
  213. }
  214. $start_pos++;
  215. }
  216. return null;
  217. }
  218. }

./Application/Home/Controller/TestController.class.php

  1. <?php
  2. namespace Home\Controller;
  3. use Think\Controller;
  4. class TestController extends Controller {
  5. public function index() {
  6. C('SHOW_PAGE_TRACE', true);
  7. C('TMPL_ENGINE_TYPE', 'Angular');
  8. $data = array();
  9. $data['title'] = '标题';
  10. $data['nav'] = array(
  11. array('title' => '首页', 'url' => '/'),
  12. array('title' => '文章', 'url' => '/article'),
  13. array('title' => '图片', 'url' => '/pic'),
  14. array('title' => '新闻', 'url' => '/news'),
  15. );
  16. $data['count'] = 6;
  17. $data['list'] = array(
  18. array('id' => 1, 'title' => '这是标题1', 'create_time' => strtotime('-5 seconds')),
  19. array('id' => 2, 'title' => '这是标题2', 'create_time' => strtotime('-4 seconds')),
  20. array('id' => 3, 'title' => '这是标题3', 'create_time' => strtotime('-3 seconds')),
  21. array('id' => 4, 'title' => '这是标题4', 'create_time' => strtotime('-2 seconds')),
  22. array('id' => 5, 'title' => '这是标题5', 'create_time' => strtotime('-1 seconds')),
  23. array('id' => 6, 'title' => '这是标题6', 'create_time' => NOW_TIME),
  24. );
  25. $this->assign($data);
  26. $this->display('index');
  27. }
  28. }

./Application/Home/View/Test/index.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Angular 模板测试 - {$title}</title>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <style>
  8. * {
  9. margin: 0px;
  10. padding: 0px;
  11. font-size: 12px;
  12. color: #333;
  13. line-height: 20px;
  14. }
  15. a {
  16. color: #33F;
  17. text-decoration: none;
  18. }
  19. a:hover {
  20. color: #f00;
  21. text-decoration: underline;
  22. }
  23. .center {
  24. text-align: center;
  25. }
  26. h1{
  27. font-size: 30px;
  28. line-height: 50px;
  29. }
  30. .nav {
  31. line-height: 30px;
  32. }
  33. .nav a{
  34. padding: 0px;
  35. margin: 0px 20px;
  36. }
  37. .main table{
  38. width: 500px;
  39. margin: 0px auto;
  40. }
  41. table {
  42. border: 1px solid #666;
  43. }
  44. table td,
  45. table th{
  46. border: 1px solid #666;
  47. line-height: 20px;
  48. padding: 0px 5px;
  49. }
  50. table th{
  51. background: #CCC;
  52. }
  53. #footer p{
  54. text-align: center;
  55. line-height: 30px;
  56. }
  57. </style>
  58. </head>
  59. <body>
  60. <div class="header">
  61. <h1 class="center">Angular 模板测试 - {$title}</h1>
  62. <div class="nav center" tp-if="$nav">
  63. <a tp-repeat="$nav as $vo" href="{$vo['url']}">{$vo['title']}</a>
  64. </div>
  65. </div>
  66. <div class="main">
  67. <table>
  68. <tr>
  69. <th>编号</th>
  70. <th>标题</th>
  71. <th>创建时间</th>
  72. <th>操作</th>
  73. </tr>
  74. <tr tp-if="$list" tp-repeat="$list as $vo">
  75. <td>{$vo['id']}</td>
  76. <td>{$vo['title']}</td>
  77. <td>{:date('Y-m-d H:i:s', $vo['create_time'])}</td>
  78. <td><a href="#del={$vo['id']}">删除</a></td>
  79. </tr>
  80. <tr tp-if="$count">
  81. <td colspan="4" class="center">共 {$count} 条数据</td>
  82. </tr>
  83. <tr tp-hide="$list">
  84. <td colspan="4" class="center">没有数据</td>
  85. </tr>
  86. </table>
  87. </div>
  88. <div tp-include="footer"></div>
  89. </body>
  90. </html>
  1. <footer id="footer">
  2. <div class="foot-warp">
  3. <p>
  4. © 2015 {:C('SITE_TITLE')} zhaishuaigan@qq.com    豫ICP备13012601号
  5. </p>
  6. </div>
  7. </footer>

运行/Test/index, 显示结果

目前只是实现了简单的解析, 还需要进一步完善, 比如配置啊, 扩展更多的标签啊什么的.

第一篇文章

Hello World