Skip to content

Latest commit

 

History

History
445 lines (444 loc) · 10.6 KB

json.md

File metadata and controls

445 lines (444 loc) · 10.6 KB

动态json格式

预览

json和代码其实是一一对应的,二者完全等价,只是json可以动态加载,但无法用函数和编程等高级功能。

// csx写法
karas.render(
  <canvas width={100} height={100}>
    <div style={{color:'#F00'}}>Hello World</div>
  </canvas>,
  '#selector'
);
// json写法
karas.parse({
  tagName: 'canvas',
  props: {
    width: 100,
    height: 100,
  },
  children: [{
    tagName: 'div',
    props: {
      style: {
        color: '#F00',
      },
    },
    children: ['Hello World'],
  }],
}, '#selector');

基本格式

json其实只包含4个基本key,对应CSX写法的名称。

{
  tagName: string, // 标签名
  props?: Object, // props即属性,常见style和矢量属性在其内。
  children?: Array<Object>, // 孩子节点
  animate?: Object/Array<{ value: Object/Array, options: Object }>, // WAA执行动画的声明
}

例:

// csx写法
let root = karas.render(
  <canvas width={100} height={100}>
    <div style={{color:'#F00'}}>Hello World</div>
  </canvas>,
  '#selector'
);
root.animate([
  {},
  {
    translateX: 100
  },
], {
  duration: 1000,
});
// json写法
karas.parse({
  tagName: 'canvas',
  props: {
    width: 100,
    height: 100,
  },
  children: [{
    tagName: 'div',
    props: {
      style: {
        color: '#F00',
      },
    },
    children: ['Hello World'],
    animate: [
      {
        value: [
          {},
          {
            transateX: 100,
          },
        ],
        options: {
          duration: 1000,
        },
      },
    ],
  }],
}, '#selector');

压缩格式(过时)

json有压缩格式,即把常见的样式/动画的key简写别名,使得整体内容大小更短,但不易于阅读。缩写只针对了css样式的键名,以及动画的2个属性valueoptions,还有options下的内容,动画中的关键帧同样是样式。因为是驼峰结构,所以普通情况下缩写就是驼峰单词的缩写形式。当出现冲突时,有专门覆盖定义:https://github.com/karasjs/karas/blob/master/src/parser/abbr.js 。所有缩写共享一个冲突定义,下面示例2种是等价的:

karas.parse({
  tagName: 'div',
  props: {
    style: {
      color: '#F00',
    },
  },
  animate: [
    {
      value: [
        {
          translateX: 0,
        },
        {
          translateX: 100,
        },
      ],
      options: {
        duration: 1000,
        iterations: 2,
      },
    },
  ],
});
// 缩写key
karas.parse({
  tagName: 'div',
  props: {
    style: {
      c: '#F00',
    },
  },
  animate: [
    {
      v: [
        {
          tx: 0,
        },
        {
          tx: 100,
        },
      ],
      o: {
        d: 1000,
        i: 2,
      },
    },
  ],
});

library字段

工具导出的json能看到library字段,这是编辑器专用,为了复用,所有的元件(可理解为一个dom类)均在library中,且有唯一id标识,json中使用libraryId来引用并实例化元件。实例化的json有init属性来覆盖props属性,相当于创建对象并传入初始化参数。一般情况下,实例化无法覆盖childrenanimate,后面会有特殊方式。

let json = {
  tagName: 'canvas',
  children: [
    {
      libraryId: 0,
      init: {
        style: {
          background: '#F00',
        },
      },
    },
    {
      libraryId: 0,
      init: {
        style: {
          background: '#00F',
        },
      },
    },
  ],
  library: {
    id: 0,
    tagName: 'div',
    props: {
      style: {
        width: 100,
        height: 100,
      },
    },
    children: ['text'],
  },
};

变量替换(过时)

工具导出的json还能看到var-开头的字段,会出现在propsstyle中,即插槽变量,在karas.parse()时可根据id传入变量替换对应的属性。另外想要替换某个特殊字段如childrenanimate,会看到特殊的如var-children.0的字段,数字标明索引。

let json = {
  tagName: 'canvas',
  children: [
    {
      libraryId: 0,
    },
  ],
  library: {
    id: 0,
    tagName: 'div',
    props: {
      style: {
        background: '#F00',
        'var-background': {
          id: 'color',
          desc: '自定义背景色',
        },
      },
    },
    children: [],
    'var-children.0': {
      id: 'custom',
      desc: '自定义children',
    },
  },
};
karas.parse(json, {
  vars: {
    color: '#00F',
    custom: 'text'
  },
});

变量替换(新)

新的插槽定义变成了vars标识,同时用子属性member表达替换的成员属性,可为数组递归下去。特别的,json的直接子属性上定义的vars可以替换library中的内容,此时可以用id替代索引。

let json = {
  tagName: 'canvas',
  children: [
    {
      libraryId: 'lid',
    },
  ],
  library: [{
    id: 'lid',
    tagName: 'div',
    props: {
      style: {
        background: '#F00',
        vars: [{
          id: 'color',
          member: 'background', // 只有1个直接属性定义key即可
        }],
      },
    },
    children: [],
    vars: [{
      id: 'custom',
      member: ['children', 0], // 需要替换children的第0个所以是个数组
    }],
  }, {
    tagName: 'img',
    props: {
      src: 'xxx',
      vars: {
        id: 'url',
        member: 'src', // 单个vars可以不用数组直接用对象
      },
    },
  }],
  vars: [{
    id: 'lib',
    member: ['library', 'lid',] // 特殊的可以用lid访问library的直接内容
  }],
};
karas.parse(json, {
  vars: {
    color: '#00F',
    custom: 'text',
    url: 'xxx',
    lib: {},
  },
});

时间段

由于复用的需求,一个容器(比如div)包含有动画的节点(比如p),作为库元素library中的一员存在,被多次放入舞台中。希望它们里面的元素(img)以不同时间开始动画一段,可以在引用libraryId的同层声明areaStart和areaDuration。 这和AE的播放一段时间轴动画功能类似。

karas.render(
  <svg>
    {
      karas.parse({
        tagName: 'div',
        children: [
          {
            libraryId: 1,
            areaStart: 100, // 本节点和递归子节点开始时间都从100ms开始
            areaDuration: 200, // 本节点和递归子节点播放到200ms就会认为结束一轮
            init: {
              style: {
                left: 0,
                top: 0,
              }
            }
          },
          {
            libraryId: 1,
            init: {
              style: {
                left: 20,
                top: 20,
              }
            }
          }
        ],
        library: [
          {
            id: 0,
            tagName: 'p',
            props: {
              style: {
                position: 'absolute',
                width: 20,
                height: 20,
                background: '#F00'
              }
            }
          },
          {
            id: 1,
            tagName: 'div',
            props: {
              style: {
                position: 'absolute',
              }
            },
            children: [
              {
                libraryId: 0,
                init: {
                  style: {
                    left: 0,
                    top: 0,
                  }
                },
                animate: [
                  {
                    value: [
                      {},
                      {
                        translateX: 100,
                      }
                    ],
                    options: {
                      duration: 1000,
                      fill: 'both',
                    }
                  }
                ]
              }
            ]
          }
        ]
      })
    }
  </svg>
);

parse详情

对于parse的json内容,可以为包含根节点(canvas之类)也可以不包含由外部提供,render可以包含parse的json。json还可以包含fonts信息,指明自定义字体名字和信息,但是没有加载逻辑,它要求字体必须是预先加载好且添加到页面中的(document.fonts.add)。

karas.render(
  <canvas>
    {
      karas.parse(json)
    }
  </canvas>,
);

karas.parse({
  tagName: 'canvas',
  children: [],
  fonts: [{
    fontFamily: 'xxx',
    "url": "xxx", // 加载的url
    data: {
      "emSquare": 2000,
      "ascent": 1200,
      "descent": 800,
      "lineGap": 60
    }
  }]
});

loadAndParse

特别的,对于loadAndParse方法,json直接子属性新增fontscomponents来通过url定义远程加载的字体和自定义组件。字体的data为字体信息。自定义组件的tagName做了默认约定,需要自己执行同名注册,或暴露同名变量给全局访问自动注册。同时组件还有reload申明强制加载,即便是发现已经注册过的同名组件。其中fonts多支持了url字段,可以加载并注册自定义字体。整体是个异步,只有全部成功后才会渲染。根节点也必须是canvas等,不能是div。

karas.loadAndParse(
  {
    "tagName": "canvas",
    "props": {
      "width": 100,
      "height": 100
    },
    "children": [
      {
        "tagName": "Custom",
        "props": {
          "style": {
            "fontFamily": "DINPro"
          }
        }
      }
    ],
    "fonts": [
      {
        "fontFamily": "DINPro",
        "url": "xxx", // 加载的url
        "data": {
          "emSquare": 2000,
          "ascent": 1200,
          "descent": 800,
          "lineGap": 60
        }
      }
    ],
    "components": [
      {
        "tagName": "Custom",
        "url": "xxx", // 加载的url
        "reload": true // 强制加载,即便已经注册
      }
    ]
  },
  '#selector',
  {
    callback(root) {
      console.log(root);
    }
  }
);

禁用缩写

另外,json直接子属性新增abbr字段,当为false时强制不使用缩写功能,等同于parse的第2个参数传入abbrfalse。建议始终使用,缩写已经不建议。没有的话会看到一个警告。

karas.parse({
  tagName: 'div',
  props: {},
  children: [],
  abbr: false, // 等同于下面的
}, {
  abbr: false, // 等同于上面的
});

禁用复制json(单例)

对于每个json,parse的时候都进行复制一份解析,以避免对传入原始数据的修改,这会造成一些性能损失。如果确保只有1个实例且无需保护原有json数据,不进行复制操作,那么json中或者parse的第3个options参数可声明singleton

karas.parse({
  tagName: 'div',
  props: {},
  children: [],
  singleton: true, // 等同于下面的
}, {
  singleton: true, // 等同于上面的
});