The year 2019 has been the biggest change for me. Not only in technology, but also in communication and ability, I have clearly realized my shortcomings. There is still a long way to go in learning.
induction
I joined this company (Sichuan Lingfan Digital Technology Co., LTD.) in March. Since then, I have been involved in the development and maintenance of the company’s core product release background management system and release system small program, including test work.
At first, I had only a rudimentary understanding of the company’s products. My boss told me about them, including my successor in front end development. But at that time, I was still ignorant, vaguely aware that the company’s products are exhibition hall, and I joined in, mainly to participate in some outsourcing projects outside the release system.
However, ONE thing I vaguely knew was that I needed to learn pixi.js, an engine for writing 2D Sprite renderings. My first job was to get familiar with the architectural system code that had been written, and as the development progressed, I became familiar with the product.
Development applet
March to April released a month’s time I mainly is familiar with the background management system code, and some maintenance and add some new features, in April to may, the main development of the publishing system of the first edition of small programs, since there is no design, although the function of the basic requirements completed, and the time is not much, also have a week’s time, So the first version of the miniprogram just went out the window.
The second week, the development of the second version of the small program, this version of the design, after a month of development and maintenance, the basic functions have been completed, and the launch of successful operation.
Small program modules are not many, roughly divided into the following modules:
- Login: Account and password login and wechat authorized login
- Home page: broadcast plan and related operations (add, delete, and release terminal), each broadcast plan contains multiple programs (program operation includes add, delete and change), programs can also preview and modify the broadcast time. (Note: Each program contains multiple production templates)
- User: Security center, feedback, add terminal and activate terminal.
The basic functions involved are also included, including wechat authorization, payment, scan, SMS authentication, data encryption (background) and decryption (front end).
The technique used in the applet :uni-app.
The ICONS are designed, and the layout is handwritten. No plugins are used.
What did you learn? Iview: reference to the ROW and COL components and model component source code, on this basis also encapsulates its own ROW and COL components and model components used in small programs. The detailed code is shown as follows:
util.js:
Eveningwater * date :2019/3/6 */ // look up the parent component of the componentexport function findComponentUp(context,componentName,componentNames){
componentNames = typeof componentName === 'string' ? [componentName] : componentName;
let parent = context.$parent;
let name = parent.$options.name; // If the parent component is not the name of the component that was passed in, loop upwards until the parent component is foundwhile(parent && (! name || componentName.indexOf(name) === -1)){ parent = parent.$parent;
if(parent)name = parent.$options.name;
}
returnparent; } // Go down to find the child components of the componentexport function findComponentDown(context,componentName){
const childrens = context.$children;
let children = null;
if(guaranteed. Length){// Loop through groups //for(const child of childrens){
// const name = child.$options.name;
// if(name === componentName){
// children = child;
// break;
// }else{
// children = findComponentDown(child,componentName);
// if(children)break;
// }
// }
for(letk = 0,len = childrens.length; k < len; k++){ const name = childrens[k].$options.name;
if(name === componentName){
children = childrens[k];
break;
}else{
children = findComponentDown(childrens[k],componentName);
if(children)break; }}}returnChildren} // Find all the parent components of the componentexport function findComponentsUp(context,componentName){
let parents = [];
if(parent){
const name = parent.$options.name;
if(name === componentName)parents.push(parent);
return parents.concat(findComponentsUp(parent,componentName));
}else{
return[]; }} // Find all children of a componentexport function findComponentsDown(context, componentName) {
let components = [];
return context.$children.forEach((child) => {
if (child.$options.name === componentName) components.push(child);
let foundChild = findComponentsDown(child, componentName);
returncomponents.concat(foundChild); })} // Find the sibling of the componentexport function findComponentsBrother(context, componentName, exceptSelf = true) {// Find all children of the parent of the current componentlet childComponents = context.$parent.$children.filter((item) => {
return item.$options.name === componentName; }) // All child components contain indexes for their own componentslet selfIndex = childComponents.findIndex((item) => {
returncontext._uid === item._uid; }) // Whether to delete its own componentif (exceptSelf) childComponents.splice(selfIndex, 1);
return childComponents;
}
Copy the code
row.vue:
<template>
<div :style="gutterObject" class="ew-row">
<slot></slot>
</div>
</template>
<script>
import {findComponentDown,findComponentsBrother} from './util.js'
export default {
props:{
gutter:{
type:[String,Number],
default:0
}
},
data() {
return{}; }, computed:{// Interval bindinggutterObject() {let gutter = parseInt(this.gutter),style = {};
if(gutter){
style = 'margin-left:'+ gutter / -2 + 'px; ' +
'margin-right:' + gutter / -2 + 'px; ';
}
returnstyle; }},mounted(){}, methods:{updateGutter(gutter){// Find the col component of the current componentlet ewCol = findComponentDown(this,'ewCol');
let ewCols = findComponentsBrother(ewCol,'ewCol'.false);
if(ewCols.length){
ewCols.forEach((child) => {
if(gutter){
child.gutter = gutter;
}
})
}
}
},
watch:{
'gutter':{
handler(val){
if(val){// Pass the gutter value this. UpdateGutter (val)}}, deep:true
}
}
}
</script>
<style>
@import './component.css';
</style>
Copy the code
col.vue:
<template>
<div :style="gutterObject" :class="classObject" class="ew-col">
<slot></slot>
</div>
</template>
<script>
import { findComponentUp } from './util.js'
export default {
props: {
span: {
type: [String, Number],
default: 0
}
},
data() {
return{ gutter:0 }; }, computed: {// Block intervalgutterObject() {let gutter = parseInt(this.gutter);
if(gutter){
return 'padding-left:' + gutter / 2 + 'px; ' +
'padding-right:' + gutter / 2 + 'px; '; }}, // Grid class bindingclassObject() {
let span = parseInt(this.span);
if (span) {
return 'ew-col-span-' + span;
}
}
},
methods:{
updateGutter(){
const ewRow = findComponentUp(this,'ewRow');
if(ewRow){ ewRow.updateGutter(ewRow.gutter); }}},mounted() {
this.updateGutter();
}
}
</script>
<style>
@import './component.css';
</style>
Copy the code
model.vue:
<template>
<view class="modal-mask" @click="$emit('on-ew-close',$event)" :class="className">
<view class="modal-content" @click="$emit('on-ew-open',$event)">
<text class="modal-title" v-if="message.title">{{ message.title }}</text>
<text class="modal-content-text" v-if="message.content">{{ message.content }}</text>
<slot name="content"></slot>
<button type="primary" @click="$emit('on-ew-sure')" class="surebtn" v-if=! "" showCancel"</button> <ew-row v-else> <ew-col span="12">
<view @click="$emit('on-ew-sure')" class="surebtn"</view> </ew-col> <ew-col span="12">
<view @click="$emit('on-ew-cancel')" class="cancelbtn"> cancel < / view > < / ew - col > < / ew - row > < view > < view > < / template > < script >export default {
props:{
message:{
type:Object,
default:() => {
return {}
}
},
showCancel:{
type:Boolean,
default:false
},
className:String
},
computed:{
},
data() {
return{}; },mounted(){
},
methods:{
}
}
</script>
<style>
@import './component.css';
</style>
Copy the code
Problems ENCOUNTERED: During development I encountered that the Uni-App framework does not yet fully support the Vue slot syntax. I will then have to rewrite the components that do not work.
Learning pixi. Js
Later, because I need to be familiar with the engine code written by the boss, I spent a week to learn the basic pixi.js, and took advantage of the time not too busy, recorded down, written down their own notes. Document content.
Publish some features of the system
I’m proud of the publishing system because it involves a lot of complex features, including component event editors, animation timelines, libraries, animation Settings, etc.
First, let’s explain the release system. This product is similar to Yiqixiu’s product, but it is different from Yiqixiu’s. And the main feature of the publishing system is the ability to edit particle animations.
Now the basic components for editing templates have been developed, and some templates can be made. Here is a template I made myself using the publishing system.
Later can also be in accordance with the needs to complete some features of the function, this is also the difference with yi Qixiu.
The engine used to create the template was written using pixi.js. Publishing system code is terror, is only an edit template involved in more than twenty code file, (PS: it is not so multiple files, all code is concentrated in a file, with tens of thousands of lines of code to a file, I watched a headache, just step by step out of the code, so also more time). Let me show you the timeline code. I won’t show you anything else. As shown in the figure below (only files in one of the folders are shown) :
Timeline code:
timeline.vue:
<template>
<div class="timeline" v-drag ref="timeline" :style="closeStyle"> <! > <div class="timeline-drag-el"></div> <! -- Close the timeline --> < el-Tooltip Effect ="dark" content="Closed" placement="top-start">
<i :class="iconClassName" class="close-timeline" @click="closeTimeLine"></i>
</el-tooltip>
<div class="timeline-content-container" :style="closeStyle"> <! <div class="timeline-component-group">
<div class="timeline-component-header"<div class="timeline-component-name" v-for="(com,index) in componentArr" :key="index" :style ="curComponentIndex === index ? 'background-color:rgb(155, 199, 226); color:#fff; ':' '" @click="selectComponent(com,index)">
{{ com.styles.name }}
<el-tooltip effect="dark" content="Play" placement="top-start">
<i class="el-icon-caret-right play-component-icon" @click="playComponentAnimation(com)"></i>
</el-tooltip>
<el-tooltip effect="dark" content="Delete" placement="top-start">
<i class="el-icon-delete delete-component-icon" @click="deleteComponent(com)"></i>
</el-tooltip>
</div>
</div>
<div class="timeline-timeline-container" ref="timeLineScroll"> <! --> <div class="timeline-scrollbar-wrapper">
<div class="timeline-scrollbar" style="width:1479px;">
<div class="timeline-track" style="width:1479px;">
<div class="timeline-thumb" style="width:990px;" :style="moveLeft" @mousedown="changeLeft"></div>
</div>
</div>
</div>
<div class="timeline-container">
<div
class="timeline-content-overview"
ref="timeLineView"
:style="{ 'min-width':'100%',width:spotArr * 195 + 22 + 'px',left:-viewLeft + 'px'}"> <! --> <div class="timeline-content-iframe">
<div class="timeline-content-marker" v-for="(t,index) in spotArr" :key="index" :style="{ width:'195px'}">
<span class="timeline-text">{{ index + 's'}}</span> </div> </div> <! --> <div class="timeline-layer-container">
<div class="timeline-layer-area" v-for="(com,index) in componentArr" :key="index" :style ="curComponentIndex === index ? 'background-color:rgb(155, 199, 226); color:#fff; ':' '">
<div class="timeline-layer-animation"
v-for = "(node,_index) in com['animation']['group'][0].ani"
:key="_index"
@mousedown="changeDelayOrDuration($event,node,_index)"
:style="computedStyle(com['animation']['group'][0].ani,node,_index)">
<span class="timeline-layer-delay" v-show="node.delay * 1000 >= 150">{{ node.delay * 1000 }}</span>
<span class="timeline-layer-duration">{{ node.duration * 1000 }}</span>
<div class="timeline-layer-resize-handle-delay"></div>
<div class="timeline-layer-resize-handle-duration"></div> </div> </div> </div> <! --> <div class="timeline-drag-handle" :style="{ left:spotLeft +'px'}" @mousedown="changeSpot">
<div class="timline-drag-spot"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script src=".. /js/_timeline.js"></script>
<style lang="stylus">
@import '.. /css/timeline.styl'
</style>
Copy the code
_timeline.js:
export default {
name: "timeline",
props: ['timeLineData'.'componentIndex'].data() {
return{left: 0,// viewLeft: 0,// componentArr: [],// spotLeft: -10,// curComponentIndex: This.componentindex,// current component closeStyle: {}, isCloseTimeLine:false,
iconClassName:"el-icon-remove-outline"}}, computed: {// The left offset of the simulated scroll barmoveLeft() {
return {
left: this.left + 'px'}}, // the number of ticks, perhaps an arrayspotArr() {
return Math.ceil(this.maxLeftOrMaxTime('time') (a) / 1000) + 1 | | 11; },maxScrollLeft() {// 990 is the width of the rolling track, 4px to reduce the deviationreturn this.$refs.timeLineScroll.offsetWidth - 994;
},
viewMaxLeft(this.spotarr-6) {this.spotarr-6 = this.spotarr-6 = this.spotarr-6 = this.spotarr-6if (this.spotArr > 6) {
return 195 * (this.spotArr - 6);
} else {
return0; }}},mounted() {// Timeline dataif (this.timeLineData) {
this.componentArr = this.timeLineData;
}
},
methods: {
closeTimeLine() { this.isCloseTimeLine = ! this.isCloseTimeLine;if (this.isCloseTimeLine) {
this.$set(this.closeStyle, 'width', 0);
this.$set(this.closeStyle, 'height', 0);
this.$set(this.closeStyle, 'padding', 0);
this.iconClassName = 'el-icon-full-screen';
} else {
this.closeStyle = {};
this.iconClassName = 'el-icon-remove-outline'; } // computedStyle(nodeArr, node, index) {if (index <= 0) {
return { width: 10 * (node.duration * 1000 / 50) + 'px', left: 10 * node.delay * 1000 / 50 + 21 + 'px'}}else{// Initial left offsetlet left = 21;
nodeArr.forEach((n, nIndex) => {
if (nIndex <= index) {
left += 10 * (n.delay * 1000 / 50)
}
if(nIndex <= index - 1) { left += 10 * (n.duration * 1000 / 50); }})return { width: 10 * (node.duration * 1000 / 50) + 'px', left: left + 'px'}, // Change the left offsetchangeLeft() { document.onmousemove = (e) => { this.left = e.pageX > this.maxScrollLeft ? this.maxScrollLeft : e.pageX <= 0 ? 0 : e.pageX; this.viewLeft = e.pageX > this.viewMaxLeft ? this.viewMaxLeft : e.pageX <= 0 ? 0 : e.pageX; } this.cancelEvent(); ChangeDelayOrDuration (event, node, index) {// Determine the drag directionletdirection = event.clientX; // The total width of the blocklettotal = 10 * (node.duration * 1000 / 50); // Change the execution time if you drag the execution timeline, otherwise change the delay timelet isDuration = event.target.className.indexOf('duration') > -1?true : false;
document.onmousemove = (e) => {
if (e.clientX >= direction) {
if (isDuration) {
node.duration = (node.duration * 1000 + 50) / 1000;
} else{ node.delay = (node.delay * 1000 + 50) / 1000; }}else {
if (isDuration) {
node.duration = (node.duration * 1000 - 50) / 1000;
} else {
node.delay = (node.delay * 1000 - 50) / 1000;;
}
if (node.delay <= 0) node.delay = 0;
if(node.duration <= 0) node.duration = 0; } } this.cancelEvent(); }, // Drag the cursor's maximum value maxLeftOrMaxTime(type) {
let nodeArr = [];
this.componentArr.forEach((com) => {
if (com['animation'] ['group'] [0] ['ani'].length) {
com['animation'] ['group'] [0] ['ani'].map((val) => {
if (type.indexOf('left') > -1) {
nodeArr.push(10 * (val.duration * 1000 / 50) + 10 * (val.delay * 1000 / 50));
} else if (type.indexOf('time') > -1) { nodeArr.push(val.duration * 1000 + val.delay * 1000); }})}})returnnodeArr.length > 0 ? () = > {returnMath.max(... nodeArr) || Math.max.apply(null, nodeArr); } : () => {return0}; }, // drag the timeline cursorchangeSpot() {
this.spotLeft = -10;
this.left = 0;
this.viewLeft = 0;
document.onmousemove = (e) => {
this.spotLeft = e.pageX <= 0 ? -10 : e.pageX >= this.maxLeftOrMaxTime('left')() ? this.maxLeftOrMaxTime('left')() : e.pageX;
if (e.pageX > this.maxScrollLeft) this.left = e.pageX - this.maxScrollLeft >= this.maxScrollLeft ? this.maxScrollLeft : e.pageX - this.maxScrollLeft;
if (e.pageX > this.viewMaxLeft) this.viewLeft = e.pageX - this.viewMaxLeft >= this.viewMaxLeft ? this.viewMaxLeft : e.pageX - this.viewMaxLeft;
if(e.pageX <= 0) { this.left = this.viewLeft = 0; } } this.cancelEvent(); }, // Unregister the mouse drag end eventcancelEvent() { document.onmouseup = (e) => { document.onmousemove = document.onmouseup = null; }}, selectComponent(item, index) {this.curcomponentIndex = index; this.$parent.$parent.getCoverage(item.uuid); }, // deleteComponent animation deleteComponent(item) {if (this.componentArr.length) {
letidx = this.componentArr.indexOf(item); this.componentArr[idx].animation.group[0].ani = []; }}, // playComponentAnimation(item,name) {this.spotLeft = -10;let spotMaxLeft = 0;
let time = 0;
let start = null;
let animationName = name ? name : item.animation.group[0].name;
if(! name){ this.$parent.$parent.$refs.iframe.contentWindow.EditorSupport.root.previewAnimation(animationName);
}
if(item.animation.group[0].ani.length) { item.animation.group[0].ani.forEach((ani) => { spotMaxLeft += 10 * (ani.duration * 1000 / 50) + 10 * (ani.delay * 1000 / 50); time += ani.duration + ani.delay; }) // Time axis cursor motionlet play = (t) => {
if(! start) start = t;let progress = t - start;
if (progress < time * 1000) {
this.spotLeft = progress / 5;
window.requestAnimationFrame(play);
} else{ this.spotLeft = spotMaxLeft; }}if (spotMaxLeft && time) {
window.requestAnimationFrame(play);
}
}
}
}
}
Copy the code
Although the timeline has achieved the basic functions so far, it is not very useful, because when the timeline was developed, I did not understand the requirements very well. It was written with reference to the timeline function in SmartSlider3.
I have encountered many problems, especially the one that impressed me deeply:
Because the data of a template is very complex, each template has the data of an animation. When I request template data, I use a variable to accept it. The code is as follows:
// The this.decrypt method is just a data decryption method that is already wrappedletres = JSON.parse(JSON.parse(this.Decrypt(result))); // Print console.log(this.decrypt (result),res) that the two are not equal;Copy the code
The first result is shown in the figure below:
The second result is as follows:
In view of this problem, I spent a full three hours to identify the problem, I successively printed out the data returned by the background is no problem.
I was really curious because there was no assignment code in my code. Later, I located the engine code, and the result actually led me to the problem. As shown in the figure below:
Because the engine code is packaged in a WebPack, then I load the engine code here with an iframe tag. The code is as follows:
<iframe ref="iframe" class="iframe" src=".. /.. /.. /static/pixijs/index.html" frameborder="0" scrolling="no" @load="dataInit"></iframe>
Copy the code
Then, to create an engine, I need to call the createApp method provided by the engine code, taking the data and width and height as parameters. The code is as follows:
// This. AddData = res this.$refs.iframe.contentWindow.Main.createApp(this.addData, 888, 500);
Copy the code
This gave me a clear understanding of the reference properties of JS objects.
Other projects
Of course, there were some other projects, but they were all relatively small projects, and the basic technology used was jquery and so on. In this year, I spent the most time in developing and maintaining the release background management system. But other projects let me have a profound impact on the time of two days to complete a background management system – quotation background management system.
Quotation management system involved in the background of the function is not much, so I completed relatively fast, there is nothing to say. But what I’m going to conclude is that in this system, I’m gradually standardizing the code. I’ve defined all the interfaces in one file, api.js. As follows:
const host = ' ';
const api = {
loginAPI:host + 'UserLogin/login'// registerAPI:host +'UserLogin/addUser',// Add the user interfaceexportAPI:host + 'MakeExcel/getJson'// Common user data export interface addSystemAPI:host +'ShowProjectController/inserShowProject'// The administrator adds the system interface editSystemAPI:host +'ShowProjectController/updateShowProject'// The administrator edit the system interface deleteSystemAPI:host +'ShowProjectController/deleteShowProject',// The administrator removes the system interface findSystemAPI:host +'ShowProjectController/selectShowProject'// Administrator and user query system interface lookWareApi: host +"EquipmentController/selectEqui"// Query software and hardware information interface addWareApi: host +"EquipmentController/insertEqui"// Add software and hardware information to the interface editWareApi: host +"EquipmentController/updateEqui", // Modify software and hardware information interface deleteWareApi: host +"EquipmentController/deleteEqui", // Delete software and hardware information interface modelApi: host +"ChildController/selectChild", // check the software and hardware models addModelApi: host +"ChildController/insertChild"// Add software and hardware models updateModelApi: host +"ChildController/editChild", // Modify the software and hardware models deleteModelApi: host +"ChildController/deleteChild", // Delete the software and hardware models}export default api;
Copy the code
Slowly standardized their own code, this is what I want to say, this is also the system brought me harvest.
Publish system and applet usage documentation
From February to March this year, my main work was to complete the use documents of the release system and small programs, which were built by gitbook. Also encountered some pits, are summed up into the article. See.
Write personal website documents in my spare time
After my spare time, I will write the documents for my own personal website and keep learning. At present, I have completed the summary of HTML and pixi.js, and THE CSS is about to be completed. I hope to finish javascript and vue.js this year.
If you are interested, please visit my personal website.
The last
Learning is like rowing upstream: not to advance is to drop back. Graduated from 2017 to over two years now, in fact, I still has some confusion about their future, because these are not what I want, I especially want to be a freelancer, able to make a another open source project, that is my goal, so I use the free time to do a ewplugins open source projects, however, This is just a simple beginning, and also my initial dabble in open source projects. I believe I still have a long way to go. I give myself a word of encouragement: come on, study hard a little bit every day, and make a little progress every day.