导航菜单的数据会以 JSON 的方式存在 options 表中 key 为 nav_menus 的 value 中。
一般系统的
options表的结构就是键值结构,也就是必然会有两个列,一个是key,另一个是value,这种结构比较灵活
在页面加载过后,根据配置选项的键 nav_menus 获取对应的数据(JSON):
1$(function () {2 /**3 * 显示消息4 * @param {String} msg 消息文本5 */6 function notify (msg) {7 $('.alert').text(msg).fadeIn()8 // 3000 ms 后隐藏9 setTimeout(function () {10 $('.alert').fadeOut()11 }, 3000)12 }1314 /**15 * 加载导航菜单数据16 */17 function loadData () {18 $.get('/admin/options.php', { key: 'nav_menus' }, function (res) {19 if (!res.success) {20 // 失败,提示21 return notify(res.message)22 }2324 var menus = []2526 try {27 // 尝试以 JSON 方式解析响应内容28 menus = JSON.parse(res.data)29 } catch (e) {30 notify('获取数据失败')31 }3233 // 使用 jsrender 渲染数据到表格34 $('tbody').html($('#menu_tmpl').render(menus))35 })36 }3738 // 首次加载数据39 loadData()40})🚩 源代码: step-76
--
思路:在点击保存按钮时,先获取全部导航菜单的数据,然后将界面上填写的数据 push 进去,然后再序列化为一个 JSON 字符串,通过 AJAX 发送到服务端保存。
名词解释:
- 将一个对象转换为一个 JSON 字符串的过程叫做序列化;
- 同理将一个 JSON 字符串转换为一个对象的过程叫做反序列化;
作为当前的情况,我们可以有两种方式获取当前导航菜单数据:
提问:哪一种方式跟合适?
发送异步请求:
之前我们已经定义了一个加载数据的 loadData 函数,但是在这里不能共用,因为在这个函数中拿到数据过后就渲染到界面上了,而我们这里是需要这个数据做后续逻辑。
如果需要公用,则需要改造这个函数,让其返回数据,而不是使用数据。
函数的粒度问题 函数的粒度指的是在同一个函数中业务的数量。
- 粒度越细,公用性越好
- 粒度越粗,调用越方便,性能大多数越好。
返回数据的方式:
如果是一个普通情况下的函数数据返回,直接使用 return 即可,但是此处我们的数据是需要 AJAX 过后才能拿到的,不能使用简单的 return 返回,即异步编程最常见的问题,必须使用回调(委托)解决。
重新封装 loadData():
xxxxxxxxxx231/**2 * 加载导航菜单数据3 * @param {Function} callback 获取到数据后续的逻辑4 */5function loadData (callback) {6 $.get('/admin/options.php', { key: 'nav_menus' }, function (res) {7 if (!res.success) {8 // 失败,提示9 return callback(new Error(res.message))10 }1112 var menus = []1314 try {15 // 尝试以 JSON 方式解析响应内容16 menus = JSON.parse(res.data)17 } catch (e) {18 callback(new Error('获取数据失败'))19 }2021 callback(null, menus)22 })23}首次加载数据时:
xxxxxxxxxx61// 首次加载数据2loadData(function (err, data) {3 if (err) return notify(err.message)4 // 使用 jsrender 渲染数据到表格5 $('tbody').html($('#menu_tmpl').render(data))6})🚩 源代码: step-77
xxxxxxxxxx141/**2 * 新增逻辑3 */4$('.btn-save').on('click', function () {5 // 获取当前的菜单数据6 loadData(function (err, data) {7 if (err) return notify(err.message)89 console.log(data)10 })1112 // 阻止默认事件13 return false14})封装保存数据函数:
xxxxxxxxxx151/**2 * 保存导航菜单数据3 * @param {Array} data 需要保存的数据4 * @param {Function} callback 保存后需要执行的逻辑5 */6function saveData (data, callback) {7 $.post('/admin/options.php', { key: 'nav_menus', value: JSON.stringify(data) }, function (res) {8 if (!res.success) {9 return callback(new Error(res.message))10 }1112 // 成功13 callback(null)14 })15}实现保存逻辑:
xxxxxxxxxx461/**2 * 新增逻辑3 */4$('.btn-save').on('click', function () {5 var menu = {6 icon: $('#icon').val(),7 text: $('#text').val(),8 title: $('#title').val(),9 link: $('#link').val()10 }1112 // 数据校验13 for (var key in menu) {14 if (menu[key]) continue15 notify('完整填写表单')16 return false17 }1819 // 获取当前的菜单数据20 loadData(function (err, data) {21 if (err) return notify(err.message)2223 // 将界面上的数据追加到已有数据中24 data.push(menu)2526 // 保存数据到服务端27 saveData(data, function (err) {28 if (err) return notify(err.message)29 // 再次加载30 loadData(function (err, data) {31 if (err) return notify(err.message)32 // 使用 jsrender 渲染数据到表格33 $('tbody').html($('#menu_tmpl').render(data))3435 // 清空表单36 $('#icon').val('')37 $('#text').val('')38 $('#title').val('')39 $('#link').val('')40 })41 })42 })4344 // 阻止默认事件45 return false46})将模板中每一个删除按钮调整为:
xxxxxxxxxx11<a class="btn btn-danger btn-xs btn-delete" href="javascript:;" data-index="{{: #index }}">删除</a>为所有 btn-delete 添加点击事件:
xxxxxxxxxx41// 删除按钮是后续创建的所以不能直接绑定事件,这里使用委托事件2$('tbody').on('click', '.btn-delete', function () {3 // TODO: ...4})思路也是获取已有数据,在已有数据中找到当前数据并移除
xxxxxxxxxx231/**2 * 删除指定数据3 */4$('tbody').on('click', '.btn-delete', function () {5 var index = parseInt($(this).parent().parent().data('index'))67 // 获取当前的菜单数据8 loadData(function (err, data) {9 if (err) return notify(err.message)1011 data.splice(index, 1)1213 // 保存数据到服务端14 saveData(data, function (err) {15 if (err) return notify(err.message)16 // 再次加载17 loadData(function (err, data) {18 if (err) return notify(err.message)19 $('tbody').html($('#menu_tmpl').render(data))20 })21 })22 })23})思考:这样处理是否会有问题,为什么,如何解决