写点什么

与前端训练营的日子 -- Week16

用户头像
SamGo
关注
发布于: 2021 年 02 月 20 日

Week 16 学习一波三折,这周遇上一个春节假期,给我们延长了学习时间,而我自己在这个假期又生病了,导致整个学习状态都不对劲,“跌跌撞撞”,也总算完成了这周学习任务了。这周是组件化的大结局,将之前的手势、动画模块与刚开始做的轮播组件结合起来,并进行一定的优化和抽象。经过这三周学习,大致了解的一个组件的生命周期🤣

轮播组件应用手势与动画

加入手势


/*...省略部分代码*/import {enableGesture} from "./gesture.js"export class Carousel extends Component {  constructor() {/*...省略部分代码*/}  render() {    /*...省略部分代码*/  enableGesture(this.root);    /*...省略部分代码*/  this.root.addEventListener("pan", event => {    	let x = event.clientX - event.startX - ax;    	let current = this[STATE].position - ((x - x % 500) / 500);    	for (const offset of [-1, 0, 1]) {      	let pos = current + offset;      	pos = (pos % children.length + children.length) % children.length;      	children[pos].style.transition = "none";      	children[pos].style.transform = `translateX(${-pos * 500 + offset * 500 + x % 500}px)`;    	}  	})  }  /*...省略部分代码*/}
复制代码


引入enableGesture,同时为this.root开启手势监听。通过addEventListener,为this.root添加不同类型的手势事件监听,从而实现,轮播组件手势拖拽。

加入动画


/*...省略部分代码*/import {Timeline, Animation} from "./animation.js"import {ease} from "./ease.js"
export class Carousel extends Component { constructor() {/*...省略部分代码*/} render() { /*...省略部分代码*/ let timeline = new Timeline; timeline.start(); let t = 0; let ax = 0; // 动画产生的位移x /*...省略部分代码*/ let nextPicture = () => { let children = this.root.children; let nextPosition = (this[STATE].position + 1) % children.length;
let current = children[this[STATE].position]; let next = children[nextPosition];
t = Date.now();
timeline.add(new Animation(current.style, "transform", - this[STATE].position * 500, -500 - this[STATE].position * 500, 500, 0, ease, v => `translateX(${v}px)`)); timeline.add(new Animation(next.style, "transform", 500 - nextPosition * 500, - nextPosition * 500, 500, 0, ease, v => `translateX(${v}px)`));
this[STATE].position = nextPosition; this.triggerEvent("Change", {position: this[STATE].position}); } handler = setInterval(nextPicture, 3000); } /*...省略部分代码*/}
复制代码


引入TimelineAnimationTimeline负责控制Animation的开始、添加、暂停、结束等状态,可通过合手势配合不同动画状态实现,拖拽的时候暂停动画,松手后恢复动画。通过tax,获取动画的进度,从而让手势事件获得正确的拖拽位置。

为组件添加更多属性(完善组件)

1. 组件变量私有化、事件机制处理

export const STATE = Symbol("state");export const ATTRIBUTE = Symbol("attribute");
export class Component { constructor(type) { this[ATTRIBUTE] = Object.create(null); this[STATE] = Object.create(null); } render() { return this.root; } setAttribute(name, value) { this[ATTRIBUTE][name] = value; } appendChild(child) { child.mountTo(this.root); } mountTo(parent) { if (!this.root) { this.render(); } parent.appendChild(this.root); } triggerEvent(type, args) { this[ATTRIBUTE]["on" + type.replace(/^[\s\S]/, s => s.toUpperCase())](new CustomEvent(type, { detail: args})); }}
复制代码


通过 Symbol 实现一个 State 机制,并将positon挂在 State 上,当需要访问position时,通过this[STATE]这个对象进行访问,达到一个类似于Protected的效果。同时,也将this.attribute通过 Symbol 变成this[ATTRIBUTE] 实现私有化,以达到类似于Protected的效果。为组件增加triggerEvent作为统一的事件机制,使组件内外信息流通,可以实现一些状态或者事件回调。


2. 内容型 Children


内容型 Children 的特点:你放几个 Children,实际上 DOM 就会出现几个 Children

Button 组件是内容型 Children 的一个典型代表

以下代码实现一个 Button 组件


import {Component, STATE, ATTRIBUTE, createElement} from "./framework.js"
export {STATE, ATTRIBUTE} from "./framework.js" // 用于其他继承Button的组件使用
export class Button extends Component { constructor() { super(); }
render() { this.childContainer = <span />; this.root = (<div>{this.childContainer}</div>).render(); return this.root; }
appendChild(child) { if (!this.childContainer) { this.render(); } this.childContainer.appendChild(child); }}
复制代码

3. 模板型 Children

模板型 Children 的特点:放在 Children 里面的其实是一个模板,不是真的 Children

List 组件是模板型 Children 的一个典型代表

以下代码实现一个 List 组件


import {Component, STATE, ATTRIBUTE, createElement} from "./framework.js"
export {STATE, ATTRIBUTE} from "./framework.js"// 用于其他继承List的组件使用
export class List extends Component { constructor() { super(); }
render() { this.children = this[ATTRIBUTE].data.map(this.template); this.root = (<div>{this.children}</div>).render(); return this.root; }
appendChild(child) { this.template = (child); this.render(); }}
复制代码

4. export...from...

参考export语法

import {Component, STATE, ATTRIBUTE} from "./framework.js"
/*export...from...相当于import之后再去export但如果只export,那么export的组件不能在当前组件使用,所以依然需要import一次需要的组件*/export {STATE, ATTRIBUTE} from "./framework.js"
export class Carousel extends Component { constructor() { super(); }}
复制代码

本周学习内容


  • 将手势和动画应用到轮播组件上

  • 为组件添加更多属性

参考资料

export语法

用户头像

SamGo

关注

还未添加个人签名 2018.12.16 加入

iOS渣渣,Flutter练习生,极客大学在学🤣🤣

评论

发布
暂无评论
与前端训练营的日子 -- Week16