BootBrander Bootstrap. less 生成器用户界面( 第 2部分/Parsing variables.less )

分享于 

18分钟阅读

Web开发

  繁體

介绍

如果你没有阅读本系列的第2部分,那么你应该在这里阅读它( )。

我们构建一个用户界面来生成一个定制的,通过操作 variables.less 文件中的变量颜色来生成一个定制的。

本文将解析这里文件并将其中的所有颜色公开给用户。 我想他可以改变颜色但不像 font-size 和填充物之类的东西。

文章索引

这些变量

我试图找出 less.js 库中有哪些变量。 但我找不到任何文件。 所以我决定获取 variables.less的文件并解析它。

编写代码解析器确实很难做到。 你通过字符来完成代码,这样做是正确的。

但是我们很幸运,variables.less 小组的boys 文件给我们的孩子和女孩们,真的很好。 每次声明一个节时,都不会有空格,它具有完全相同的语法。

变量在类别中声明。 我将利用它。 类别如下所示:

//== Colors

所以如果我读这一行,我可以很容易地查看前 4个字符来识别它。

变量如下所示:

@gray-base: #000;

那更容易。

启动

如果你有前一篇文章的代码,你应该更改一些内容。 首先,更改 viewModel的声明。

var viewModel = window.viewModel = {
 "@body-bg": ko.observable('#ffffff'),
 "@text-color": ko.observable('#777777'),
 "@brand-primary": ko.observable('#337ab7')
},

到:

var viewModel = {
},

并找到完成knockout绑定的行并将它的抛出。 在我们完全完成之前它会刹车。 我们稍后再把它放回原处。

获取和解析

让我们继续,编写一个Ajax函数,获取 variables.less的文件。

$(document).ready(function () {
 $.ajax({
 url: "/Content/bootstrap/variables.less",
 success: function (responseText) {
 var lines = responseText.split('n'),
 line,
 i;
 for (i = 0, j = lines.length; i <j; i++) {
 line = lines[i];
 if (line.substr(0, 1) === "@") {
 console.log(line);
 }
 }
 }
 })
 });
测试

如果运行这里代码,它应该给出以下输出:

...Lots up here
main.js:52 @brand-success: #5cb85c;
main.js:52 @brand-info: #5bc0de;
main.js:52 @brand-warning: #f0ad4e;
main.js:52 @brand-danger: #d9534f;
main.js:52 @body-bg: #fff;
... and more down here 

它把所有的东西都打印出来。 它有许多不同类型的变量。 它们可以是像 darken() 一样的函数,可以是像素,数字和对其他变量的引用。

现在,我们将重点讨论那些以 # 开始的值。 这些颜色是肯定的。

我们将添加到 viewModel 中的任何一个。

$.ajax({
 url: "/Content/bootstrap/variables.less",
 success: function (responseText) {
 var lines = responseText.split('n'),
 line,
 i,
 nameValue,
 name,
 value;
 for (i = 0, j = lines.length; i <j; i++) {
 line = lines[i];
 if (line.substr(0, 1) === "@") {
 //this is a variable nameValue = line.split(":");
 name = nameValue[0].trim();
 value = nameValue[1].trim();
 if (value.substr(0, 1) === "#") {
 //this is color viewModel[name] = ko.observable(value);
 }
 }
 }
 console.log(viewModel);
 }
 });

运行这个命令,我们可以看到,到控制台的viewModel 输出现在包含很多变量。

绑定 viewModel

在前一篇文章中,我们将一段HTML编码为每个单独的颜色变量中的for绑定。 这将不会非常有用,我们将替换它。

为此,我们将创建一个HTML模板,我们将把它送到 knockout。

单个颜色的模板

我们将使用一个模板并在稍后发送knockout绑定变量。 在正文的底部创建下一段HTML代码。

<scripttype="text/html"id="color"><divclass="row"><divclass="col-xs-9"style="padding-right: 0;"><inputtype="text"class="form-control"data-bind="value: $data"/></div><divclass="col-xs-3"style="padding-left: 0;"><inputtype="color"class="form-control"data-bind="value: $data"/></div></div></script>

现在,在带有 of toolbar-container的左面板中,我们将遍历 viewModel的属性。 在每次迭代中,我们将设置一个 label 并调用模板

<divclass="col-xs-2"id="toolbar-container"><divclass="form-group"data-bind="foreach: {data: Object.keys($data), as: '_propkey'}"><labeldata-bind="text: _propkey"></label><divdata-bind="template: { name: 'color', data: $root[_propkey] }"></div></div></div>

现在我们可以再次开始弹出绑定。 在调用处理程序的Ajax成功结束时执行这里操作。 在解析了 variables.less的循环之后:

ko.applyBindings(viewModel);
测试

运行该站点时,它应该类似于下面这样:

我们得到了一个漂亮的列表,所有看起来是颜色的。 但有一个问题。 或者实际上两个。

所有颜色微调器都是 black的,这是因为。 在";"的结尾。 第二个问题是颜色的shorthand 符号,如白色 #fff. 输入 type="颜色"需要完整地写出它们。

让我们找到这些行:

if (value.substr(0, 1) === "#") {
 //this is color viewModel[name] = ko.observable(value);
}

并将它们更改为:

if (value.substr(0, 1) === "#") {
 //this is color value = value.replace(";", "");
 if (value.length === 4) {
 value += value.substr(1, 3);
 }
 viewModel[name] = ko.observable(value);
}

再次运行:

Nice !

它似乎迭代了属性确实破坏了双向绑定。 但现在我们不用担心了。 因为我们将首先添加我们的类别,这将改变一切。

类别

现在,它只是一个长长的颜色列表。 有些上下文是不错的。 如前所述,变量放在声明为注释的categories 中。

//== Colors

首先,我们将看到一个类别,然后是属于这些类别的变量列表。 为了反映这一点,我们首先需要改变我们的viewModel。 它应该得到以下形式:

  • viewModel
    • categories
      • category
        • variableName
        • variableName
      • category
        • variableName
    • variables
      • variable
      • variable

viewModel的声明方式如下:

var viewModel = window.viewModel = {
categories: {},
variables: {}
}

我们还将更改 variable 对象本身。 如果你查看了我们现在得到的列表,我们会丢失一些变量,@text-color 已经消失了。 这是因为颜色不是以 # 开头的,而是被声明为从不同的variable 继承的。 我们以后再处理。 但是现在,我们将在值和类型中拆分单个 variable

我们的解析代码现在应该如下所示:

var lines = responseText.split('n'),
 line,
 i,
 nameValue,
 name,
 value,
 category
 ;
 for (i = 0, j = lines.length; i <j; i++) {
 line = lines[i];
 if (line.substr(0, 4) === "//==") {
 category = line.substr(5, line.length).trim();
 //console.log(line.substr(5, line.length).trim()); viewModel.categories[category] = {
 variables: ko.observableArray()
 };
 continue;
 }
 if (line.substr(0, 1) === "@") {
 //this is a variable nameValue = line.split(":");
 name = nameValue[0].trim();
 value = nameValue[1].trim();
 value = value.replace(";", ""); 
 if (value.substr(0, 1) === "#") {
 //this is colorif (value.length === 4) {
 value += value.substr(1, 3);
 }
 //add the name to the categories viewModel.categories[category].variables.push(name);
 //add the variable to the variables object viewModel.variables[name] = {
 type: "color",
 value: ko.observable(value)
 }
 }
 }
 }
 console.log(viewModel);
 //Apply the viewModel ko.applyBindings(viewModel);
}

你可能注意到我不是简单地将 variable 保存在类别本身中,而是只保存。 我将 variable 本身添加到一个对象中。

这是为了 2原因。

第一个原因是引用 variables ( 有另一个 variable 名称作为它的值的)。 要解决这些问题,对象的var 更容易查找。

第二个原因是序列化。 我不能在 category.variables 列表中保存引用,因为这会创建一个循环对象,我们不能通过 JSON.stringify 将它。

更新用户界面

现在我们需要更改HTML和弹出绑定来反映这种变化。 首先我们的模板:

<scripttype="text/html"id="color"><divclass="row"><divclass="col-xs-9"style="padding-right: 0;"><inputtype="text"class="form-control"data-bind="value: value"/></div><divclass="col-xs-3"style="padding-left: 0;"><inputtype="color"class="form-control"data-bind="value: value"/></div></div></script>

现在左边的一列。 我选择将类别和变量放在细节部分。 但是你可以通过使用 accordion 来改进它:

<divclass="col-xs-2"id="toolbar-container"><divdata-bind="foreach: {data: Object.keys(categories), as: '_propkey'}"><details><summarydata-bind="text: _propkey"></summary><divdata-bind="foreach: $root.categories[_propkey].variables"><divclass="form-group"><labeldata-bind="text: $data"></label><divdata-bind="template: 
 { name: $root.variables[$data].type, data: $root.variables[$data] }"></div></div></div></details></div></div>
测试

运行页面,用户界面应该类似于下面这样:

但是,如果我们在第一篇文章中运行测试:

  • 在文本字段中键入" red"来更改 @body-bg 变量
    • 页面的background 应该更改为红色
  • 通过颜色选择器更改 @body-bg 变量
    • 页面的background 应该更改为选中的颜色
  • 在文本字段中键入" red"来更改 @brand-primary 变量
    • 主按钮应该改为 blue""
    • 用户界面应该保留以前设置的@body-bg
  • 通过颜色选择器更改 @brand-primary 变量
    • 主按钮应改为选定的颜色
    • 用户界面应该保留以前设置的@body-bg

这些都不行,这是因为我们没有设置我们的目标的订阅。 在前一篇文章中,我们有以下代码。

function onViewModelChanged() {
 var viewData = ko.toJS(viewModel);
 less.modifyVars(viewData);
 localStorage.setItem("viewData", JSON.stringify(viewData));
};for (var prop in viewModel) {
 if (viewModel.hasOwnProperty(prop)) {
 viewModel[prop].subscribe(onViewModelChanged);
 if (storedViewData.hasOwnProperty(prop)) {
 viewModel[prop](storedViewData[prop]);
 };
 }
}

然后我说这根本是错误的。 这种方式的原因是它设置了存储数据的值。 订阅首先出现。然后对于每个变量,它设置存储的值。 这将导致 onViewModelChanged 函数为 viewModel 中的每个颜色触发。 在我们之前的例子中,这并不重要,因为我们只有 3个颜色。 但是现在我们可能会注意到。

首先,我们将在函数中执行订阅的循环包装起来,让我们调用这个 applySubscriptions

function applySubscriptions() {
 var observableVars = viewModel.variables;
 for (var prop in observableVars) {
 if (observableVars.hasOwnProperty(prop)) {
 observableVars[prop].value.subscribe(onViewModelChanged);
 }
 }
}

现在我们需要一些东西来反序列化我们的viewModel。 我们已经将变量分解为一个类型和一个值。 所以打电话 less.modifyVars(ko.toJS(viewModel)) 不可能工作。

function viewModelToJS() {
 var obj = {},
 observableVars = viewModel.variables
 ;
 for (var prop in observableVars) {
 if (observableVars.hasOwnProperty(prop)) {
 obj[prop] = observableVars[prop].value();
 }
 }
 return obj;
}

然后,我们改变 onViewModelChanged 函数,使用这个函数代替 ko.toJS

function onViewModelChanged() {
 var viewData = viewModelToJS();
 less.modifyVars(viewData);
 localStorage.setItem("viewData", JSON.stringify(viewData));
};

运行我们的测试:

  • 在文本字段中键入" red"来更改 @body-bg 变量
    • 页面的background 应该更改为红色
  • 通过颜色选择器更改 @body-bg 变量
    • 页面的background 应该更改为选中的颜色
  • 在文本字段中键入" red"来更改 @brand-primary 变量
    • 主按钮应该改为 blue""
    • 用户界面应该保留以前设置的@body-bg
  • 通过颜色选择器更改 @brand-primary 变量
    • 主按钮应改为选定的颜色
    • 用户界面应该保留以前设置的@body-bg
  • 移动到顶部导航中的其他页面
    • 用户界面应该保留以前设置的@body-bg
    • 用户界面应该保留以前设置的@brand-primary

我们的测试达到了 switch 页面的最大程度。 如上所述,这个MVC站点不是 ajaxy,所以它将把页面拖到服务器上。

我们需要修复变量形式的存储。 获取存储变量并将它的放入 storedViewData 中的代码仍然应该工作,因这里在检查变量类型之前,可以:

value = value.replace(";", "");if (storedViewData.hasOwnProperty(name)) {
 value = storedViewData[name];
}if (value.substr(0, 1) === "#") {

然后在Ajax成功处理程序的结尾,调用 less.modifyVars 应用所有变量;在 applyBindings 下面:

//Apply the viewModelko.applyBindings(viewModel);//Set the current valuesless.modifyVars(viewModelToJS());

如果我们现在执行 testplan,它应该能工作。

结尾

我现在要结束这篇文章了。 因为我看到它变得相当长。 查找我们的参考变量,如 @text-color 和处理'darken'和'lighten'等函数将在下一个文章中。

下载中,你将发现带有jsdoc注释的经过优化的版本。 这将是我们下个文章的起点。


PAR  BOO  引导  Generator  Bootstrap  VAR  
相关文章