background
With the OpenHarmony
component development competition, our team members were informed that they had won the second prize. While they were happy, they also wanted to write down our valuable development experience during this period to share with you. When we saw the notification of the competition It's already mid-September, and it's time for the work to be submitted. After referring to some other works, we found that Canvas
, so we plan to write one based on Canvas
and common components. Components, because we have not developed OpenHarmony
application before, our team members have no relevant experience, everyone is exploring from scratch, we first IDE
and cooperate, some members are responsible for downloading 061db7d4a0dbd2 and debugging equipment, and some members are responsible for research and read the official documentation. First attach the source code, sharing and summarizing is not easy, please like and follow ⭐️:
https://github.com/Wscats/openharmony-sheet
configure
After reading the official documents, our members made the following environment configurations on their local computers and devices:
- Download and install DevEco Studio 2.1 Release and above
- Get the OpenHarmony SDK package and unzip it
- config
OpenHarmony SDK
In DevEco
main interface, click on the toolbar File
> Settings
> Appearance & Behavior
> System Settings
> HarmonyOS SDK
interface, click HarmonyOS SDK Location
load SDK
:
Then click Next
and Finish
complete the environment configuration.
- Install additional packages, enter the
OpenHarmony-SDK-2.0-Canary/js/2.2.0.0/build-tools/ace-loader
directory, then run the command line tool in this directory, and execute the following commands respectively until the installation is complete
npm cache clean -f
npm install
- Download the OpenHarmonyJSDemos project project and import the project into
DevEco Studio
- Apply and configure the certificate. Note that the certificates of
OpenHarmony
andHarmonyOS
are not common, so additional application is required - Compile and build, generate a
HAP
application installation package, generate aHAP
application installation package, and install it on theOpenHarmony
development board - After installation and running, click the application icon on the screen of the development board to open the application, you can view the running effect of the application example on the device, and perform related debugging
- In addition to using real machine debugging, we can also use remote debugging and local
Previewer
debugging, although it is very convenient, but the actual performance is definitely slightly different from the real machine
foreword
Before realizing the Canvas
, we had some discussions and discussions. First of all, we hoped that we could use this development to improve our OpenHarmony
and facilitate subsequent business support. Secondly, our team members also hope to get better rankings and rewards. We It is noted that the score of the competition is scored by the judges, and the full score is 100 points. Here, the score will be based on the four dimensions of creativity, practicality, user experience, and code specification. Canvas
will be more difficult to implement first than ordinary applications. Canvas
to debug, we have little advantage in creativity and practicality, because most of the 061db7d4a0df72 applications that most front-end developers come into contact with are game-related, so this road is destined to be relatively difficult, and the user experience is also A big difficulty, our real machine test found that Canvas
is not very good, much worse than the experience of some native components, I have confidence in the code quality of team members, but the code specification has the least proportion of scores. So when we set up the project, we had a big difference.
Selection dimension | instruction | Score |
---|---|---|
creative | The degree of innovation of the work | 30% |
practicality | The degree of practical application of the work in the application scenario | 30% |
user experience | User experience value, users can easily use components and get a good sense of experience | 25% |
code specification | Code quality, aesthetics, compliance with specifications | 15% |
plan
Because of the above general doubts, we first formulated three plans and one goal:
- Implement common components using base components and container components etc - OpenHarmonyGallery
Canvas
game using the canvas component OpenHarmonyFlappyBirdCanvas
rendering engine using base components, container components and canvas components OpenHarmonySheet
The rendering engine is our ultimate goal. Although the difficulty is too high, our team members decided to achieve this goal in three steps. First, at least learn to use basic components and container components, then learn to use canvas components, and finally integrate these experiences to achieve a rendering engine.
First Experience
We first implemented a general gallery component as a hands-on project, which mainly uses four basic components and container components:
We place a button to trigger showGallery
method to control panel
display popups and hidden, where div
and button
label is hml
built-in components, we usually write with html
very similar, it supports most of our general properties such as id
, class
and type
etc., are convenient for us to set the basic identification of the component and display the appearance features.
<div class="btn-div">
<button type="capsule" value="Click Here" onclick="showGallery"></button>
</div>
Then we place a changeable gallery content display window in the panel
mode
and src
variables, so that the gallery component can display different forms according to the mode, and display different shapes according to the incoming image address. Picture content, the syntax here is very similar to the Vue
Mustache
syntax can be used to control the attribute value.
<panel
id="gallery"
class="gallery"
type="foldable"
mode="{{modeFlag}}}"
onsizechange="changeMode"
>
<div class="panel-div" onclick="closeGallery">
<image class="panel-image" onclick="closeGallery" src="{{galleryUrl}}}"></image>
<button
class="panel-circle"
onclick="closeGallery"
type="circle"
icon="/common/images/close.svg"
></button>
</div>
</panel>
After implementing the view and layout, we can add the logic of the gallery component in index.js
ES6
syntax, we can write very comfortable and efficient. The data here is the data model of the gallery component, and the type can be Object or function, if the type is a function, the return value must be an object. Note that the attribute name cannot start with $
or _
, and do not use reserved words. We set default values modeFlag
and galleryUrl
export default {
data: {
modeFlag: "full",
galleryUrl:
"https://pic1.zhimg.com/v2-3be05963f5f3753a8cb75b6692154d4a_1440w.jpg?source=172ae18b",
},
};
The display and hiding logic is relatively simple, you only need to get panel
, and then trigger the show
or hide
method. Of course, in addition to this method, we can also use the rendering attribute to achieve:
for
Expand the current element according to the set data listif
Add or remove the current element according to the setboolean
show
According to the setboolean
, show or hide the current element
showGallery(e) {
this.$element('gallery').show()
},
closeGallery(e) {
if(e.target.type==='image') return
this.$element('gallery').close()
},
index.css
in the same level directory, which can make our gallery show better effects. The animation style also supports dynamic rotation, translation, zoom and gradient effects, which can be set in style
or css
.
.panel-div {
width: 100%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
}
The overall effect is shown in the figure below. The effect is simple and rude. After writing this DEMO
, our team members have the most basic understanding of the application of the basic components OpenHarmony
Advanced
Although we have mastered the use of the most basic components above, we still haven't used the Canvas
canvas component, so we continued to read the official documentation and found that OpenHarmony
provides a complete canvas interface:
We used the classic FlappyBird
game as our first attempt at the canvas component.
collect material
First of all, let's prepare the pictures and animation materials of the game:
material | |
---|---|
background | |
bird | |
ground | |
water pipe |
Then we prepare the canvas, set the height and width, and listen to the canvas press method ontouchend
.
<div class="container">
<canvas ref="canvas" style="width: 280px; height: 512px;" ontouchend="moveUp"></canvas>
</div>
Data initialization
After preparing the canvas, we need to initialize the initial data of the game. The core mainly involves several:
el | canvas element |
---|---|
gap | Pipe spacing |
score | Score |
bX | Bird X-axis coordinate |
bY | Bird Y-axis coordinate |
gravity | Gravity Index |
pipe | pipeline data |
birdHeight | bird height |
birdWidth | bird width |
pipeNorthHeight | Upper side pipe height |
pipeNorthWidth | Lower pipe height |
cvsHeight | canvas height |
cvsWidth | canvas width |
fgHeight | ground height |
fgWidth | ground width |
Before implementing this game, we not only need to master the basic components, but also need to understand part of the life cycle. OpenHarmony
has two life cycles, namely the application life cycle and the page life cycle. We use the life cycle onShow
first time here, which is Triggered when the page is opened, and the application is in the foreground, we need it to help us initialize some key data at the beginning, get the nodes of the canvas, save the context scope of the canvas ctx
, clear the pipeline data and trigger the game frame drawing.
onShow() {
this.el = this.$refs.canvas;
this.ctx = this.el.getContext('2d');
this.pipe[0] = {
x: this.cvsWidth,
y: 0,
};
requestAnimationFrame(this.draw);
},
The this.draw
method here is the core logic of the whole game, involving the bird's flight animation, motion trajectory, boundary processing and score calculation.
First we draw the background of the game from the top left corner of the canvas at X
and Y
const ctx = this.ctx;
ctx.drawImage(this.bg, 0, 0);
Then we draw the pipes that appear in the sky and the ground during the flight of the bird. Here we need to calculate the position of the pipe in the sky. The position of the upper pipe needs to be calculated from the preset distance between the two pipes and the height of the lower pipe. When the position is calculated After that, you only need to cooperate with the timer or requestAnimationFrame
to update the position of the pipe and the bird in real time, so that the user can perceive the effect of the dynamic picture of the game. Here I use requestAnimationFrame
request animation frames. The experience will be better, but it only supports API Version 6
You do not need to import, so readers need to pay attention to SDK
is a relatively new version.
for (let i = 0; i < this.pipe.length; i++) {
this.constant = this.pipeNorthHeight + this.gap;
ctx.drawImage(this.pipeNorth, this.pipe[i].x, this.pipe[i].y);
ctx.drawImage(this.pipeSouth, this.pipe[i].x, this.pipe[i].y + this.constant);
this.pipe[i].x--;
}
Impact checking
Here we use a conditional judgment to do boundary processing, that is, collision detection, that is, if the bird touches the ground, the pipeline in the sky or the pipeline on the ground will stop all animations, that is, the game is over, and if the game is over, the results will be settled. And use the OpenHarmony
remind players if they need to restart a new game.
if (
(this.bX + this.birdWidth >= this.pipe[i].x &&
this.bX <= this.pipe[i].x + this.pipeNorthWidth &&
(this.bY <= this.pipe[i].y + this.pipeNorthHeight ||
this.bY + this.birdHeight >= this.pipe[i].y + this.constant)) ||
this.bY + this.birdHeight >= this.cvsHeight - this.fgHeight
) {
prompt.showDialog({
buttons: [{ text: "重来一次" }],
success: (data) => this.restart(),
});
clearInterval(this.interval);
}
When the boundary is processed, we also need to deal with the fact that when the bird keeps flying, new pipelines must be created, and the old pipelines are recycled to calculate the score. This logic is also quite simple, and it is essentially a kind of collision detection. When the pipeline position X
axis on the left side of the screen 5
, that is, the bird has passed safely, and the score is successful. When the latest pipe is changed to X
axis is 125
, that is, the next pipe the bird will fly, then Create the next new pipeline in advance. If the bird’s flying distance is relatively long, we also need to consider optimizing the pipeline array. We can’t let the array grow indefinitely. We can also optimize, so when the old pipeline has completely disappeared from the picture , we can consider deleting the old pipe data from the array.
if (this.pipe[i].x == 125) {
this.pipe.push({
x: this.cvsWidth,
y: Math.floor(Math.random() * this.pipeNorthHeight) - this.pipeNorthHeight,
});
}
if (this.pipe[i].x == 5) {
this.score++;
}
All of the above logic is essentially the animation of the drawing pipeline. We can easily draw the flight trajectory of the bird by combining the offset and gravity factors. We also draw the score to the lower left corner of the screen by the way, so that it can be real-time. Display the player's score.
ctx.drawImage(this.fg, 0, this.cvsHeight - this.fgHeight);
ctx.drawImage(this.bird, this.bX, this.bY);
this.bY += this.gravity;
ctx.fillStyle = "#000";
ctx.font = "20px Verdana";
ctx.fillText("Score : " + this.score, 10, this.cvsHeight - 20);
Action and Scoring
And our players only need one operation to participate in the whole game, that is to click on the screen with a finger, try to let the bird fly safely between the pipes, so we need to monitor the click event of the screen, which is essentially the click event of the canvas, when the user clicks time, we let the bird move a little distance up.
moveUp() {
this.bY -= 25;
},
The logic of resetting the game is very similar to the initialization, as long as the player's score, the position of the bird and the data of the pipeline are all restored to the default state:
restart() {
this.pipe = [];
this.pipe[0] = {
x: this.cvsWidth,
y: 0,
};
this.constant = 0;
this.score = 0;
this.bY = 150;
},
Package components
Since the competition requires us to implement a general component, in case 2, we hope to go further and try to encapsulate this game into a general component. Check the official documentation and find that it is very simple to implement. The details are in Custom component , The so-called custom component is a new component that the user combines and encapsulates the existing components according to the business needs, which can be called multiple times in the project, thereby improving the readability of the code. To sum up, we only need to use the <element>
component to introduce the component we just implemented into the host page.
<element name="Flappy" src="./flappy//pages//index/index.hml"></element>
<div class="container">
<Flappy></Flappy>
</div>
ultimate challenge
With the accumulation of the previous two cases, our team has OpenHarmony
, and we are about to enter the final exciting challenge. We need to completely transplant a Canvas
engine. At the beginning, we considered implementing a game However, considering that the remaining time of the game is not enough, and the practicality and creativity of the game engine are not conducive to display, after comprehensive consideration by our team, we finally decided to implement a document table rendering engine.
think
Some people may ask why they choose to transplant a document rendering engine. Here I remember that there was a similar discussion on the how long will it take China to develop an alternative software similar to Excel, and its functions cover 95% of the functions of Excel? , this road is very rough and difficult, please quote the answers of some big Vs with the highest praise:
Microsoft Wheel Brother: There are so many things that can't be done, and it will take several years to write the requirements document well.
Microsoft's Belleve: Programmers can try to implement recalc first (update the cell value according to the formula), and then you will know the difficulty. As the most complex C++ project in China, the document project is by no means a vain name.Microsoft's monster brother: As an engineer of Excel, my brother seriously answered one, no, because our group next door has already tried it, and it has covered about 40% in two years.
IBM's Caspar Cui: If you are developing common Excel functions, WPS is already a good alternative. And Microsoft and Kingsoft also have cross-licensing. But Excel, which says it's 95% functional, has already done that. . . Still a bit underestimated by Excel. As far as the amount of help documentation is concerned, WPS has to work harder.
University of Science and Technology of China: If Microsoft is brainstorming and loses the Excel source code, it cannot be recovered. That's the end of the world, and it's all over together. Even if Microsoft brought back the original team of Excel team, resigned from resignation, revived premature death, and then re-developed an Excel. There is no way he can guarantee that the functions of Excel will be restored to 95%, and that 95% of the Excel files will be opened normally.
Bbcallen
: Impossible, Microsoft can't do it themselves.
No matter what anyone says, we must take this road. Just like the meaning behind the birth of Hongmeng, we choose to meet this challenge. Every hurdle and pit in it is worth leaving a Chinese footprint.
From the perspective of technology and goals, what we should achieve is not a local personal document that has solidified the market and user habits, but an online collaborative document. Local documents only need to consider individuals, not multi-person collaboration scenarios, only need to consider Offline, do not need to consider online scenarios, only need to consider client scenarios, do not need to consider server scenarios, etc...
The host environment of online documents is the browser, and the local document is behind the system. There is no support for any online document in China based on Google Chrome, and there is no support for Microsoft Office
based on Microsoft Windows
system. In fact, based on all this, we should also 95%
that it is difficult to do 061db7d4a0ed10. You must know that Google has invested thousands of people and tens of billions of people for more than ten years to develop the browser, Windows
system. We may not have such a technical background in China, but we are still trying to narrow the gap and catch up.
Implementation plan
Before talk about implementation, let's talk about how complex form rendering , table rendering in general, there are two implementations:
DOM
rendering.Canvas
rendering.
The well-known handsontable
open source library in the DOM
for rendering. The same rendering results require DOM
node, but it is obvious that DOM
rendering with 100,000 or one million cells will cause major performance problems. So, now many online forms implementations are based on Canvas
and superimposed DOM
to achieve, but the use of Canvas
realize the need to consider the visible area, the scroll operation, canvas hierarchy, there Canvas
some performance issues facing their own, including Canvas
how straight out etc., the requirements for development are higher, but for better user experience, the implementation scheme of Canvas
Since most of the front-end project rendering layers are rendered layer by layer according to the layout model tree structure, the entire rendering tree corresponds to the layout model tree one by one. Therefore, the number of nodes in the entire rendering is also very large. When the project is larger, performance suffers more.
[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-ACtSdVX6-1637535201140) ( https://p3-juejin.byteimg.com/tos-cn-i- k3u1fbpfcp/9d7f39b369da4fca9abbd5827be03b17~tplv-k3u1fbpfcp-zoom-1.image "screenshot.png")]
In order to improve the rendering performance and provide a better editing experience DOM
replaced by Canvas
, which is convenient for developers to build large-scale online document projects. companies that implement similar engines at home and abroad, such as: Tencent Documents, Jinshan Docs and Google Docs etc.
top floor | ||
---|---|---|
↑ | DOM | Container plugin input box, etc. |
↑ | Canvas | Highlight selection, etc. |
↑ | Canvas | Content font background color, etc. |
bottom layer |
We view collection element, and then rendered by category manner, reducing Canvas
number of switching graphics engine state machine, reduce performance losses optimize the rendering time consuming, the entire core engine control codes 1500
around line, the other supplementary demo code 500
line , which is convenient for everyone to understand and read and carry out secondary development.
The engine ported here mainly refers to a commercial project and an open source project:
Canvas initialization
We construct a table
class, create a canvas during initialization, set the height and width, and put it into DOM
, and mount the commonly used properties to the prototype chain and expose it to the global window
variable.
class Table {
constructor(container, width, height) {
const target = document.createElement("canvas");
document.querySelector(container).appendChild(target);
this.$target = target;
this.$draw = Canvas2d.create(target);
this.$width = width;
this.$height = height;
}
}
<div id="table"></div>
on the page, and instantiate the canvas directly in the global environment. id
attribute, you can use the id
obtain the component object and call the relevant component method.
const table = new Table("#table", 800, 500);
upper left area | col column | col column |
row row | cell cell | cell cell |
row row | cell cell | cell cell |
Coordinate system establishment
With the canvas, we will start preparing for rendering. We encapsulate the render
method in the table
render
method mainly draws four areas, which is similar to the mathematical Cartesian Cartesian coordinate system The four imaginations involve grid line segments, grids information, column headers (columns AZ), row headers, and freeze areas.
2 - Top left area | 1 - Top right area |
---|---|
3 - Lower left area | 4 - Bottom right area |
These area
are initialized area.js
of Area
- Areas 2 to 1 are the headers of the AZ column
- Areas 2 to 3 are the line headers
- 4 Areas are most commonly used and are editable cells
renderBody.call(this, draw, area4);
renderRowHeader.call(this, draw, iarea3);
renderColHeader.call(this, draw, iarea1);
renderFreezeLines.call(this, draw, area4.x, area4.y);
Most of the core ideas of these four areas are essentially drawing grids, all of which use the renderLinesAndCells
method, which has methods for drawing the lines and grid information of the renderCells
will traverse the area and trigger renderCell
draw each For individual cells, some special cells are also processed here, such as merged cells and selected cells, while renderLines
will traverse each row and column to draw the interval lines of all rows and columns.
function renderLinesAndCells() {
renderLines(draw, area, lineStyle);
renderCells(draw, type, area, cell, cellStyle, selection, selectionStyle, merges);
}
cell rendering
After drawing the cells of the table, you need to render the data and format to each cell. Here, cell
method is mounted Table
prototype chain, which accepts a callback function and saves it to the static property $cell
. When renderCell
function is triggered, this method is called and the row and column numbers are passed into the $cell
method to obtain cell information.
Table.prototype["cell"] = function (callback) {
this[`$$cell`] = callback;
return this;
};
const sheet = [
["1", "1", "1"],
["1", "0", "1"],
["1", "1", "1"],
];
table.cell((ri, ci) => sheet?.[ri]?.[ci] || "").render();
<img width="250" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d88f654f3b04af1a1b7fdb54eb89472~tplv-k3u1fbpfcp-zoom-1.image" />
So we can $cell
method. Of course, you can only pass in plain text here, and you can also pass in complex data structures to decorate cells. Here style
will have the default The value is from $cellStyle
.
bgcolor | #ffffff |
---|---|
align | left |
valign | middle |
textwrap | true |
underline | false |
color | #0a0a0a |
bold | false |
italic | false |
rotate | 0 |
fontSize | 9 |
fontName | Source Sans Pro |
These styles are essentially using Canvas
interface provided draw.attr()
to show.
const c = cell(ri, ci);
let text = c.text || "";
let style = c.style;
cellRender(draw, text, cellRect, style);
With the most basic method above, we already have the function of displaying table data. At this time, we can expose richer interfaces to third parties, such as commonly used merged cells. We call the merges
method to inform the table
class, and we are in the X
axis G9
The cells in the range from H11
to Y
axis B9
to D11
Table.create("#table", 800, 500).merges(["G9:H11", "B9:D11"]);
At this time, renderCells
will do special processing to the grid in this area and render it into the state of merged cells.
eachRanges(merges, (it) => {
if (it.intersects(area)) {
renderCell(draw, it.startRow, it.startCol, cell, area.rect(it), cellStyle);
}
});
Data can be edited
In addition to cell merging, the event processing of the canvas is also commonly used, because all the methods just now only view the state of the table, and the table will also be edited by the user, so we have to listen to the events of the user's click and input, so we render the table When binding click
, mousedown
, mousemove
and mouseup
events, etc., we can monitor the user's click behavior and Z
DOM
element, and provide the user with the function of inputting and modifying the cell. .
bind($target, "click", (evt) => {});
bind($target, "mousedown", (evt) => {});
So DOM
node in addition to our place <canvas>
elements can also be arranged on <textarea>
elements, where we can notice that inline styles have areaTop
and areaLeft
to control our input box specific location, this location is also very easy to get, we just need to Get the click event objects evt.offsetX
and evt.offsetY
, and then calculate whether it is in the four quadrant areas according to the position of the coordinates and return the row and column information. Combined with the information of the areaTop
and areaLeft
input box can be accurately calculated, and then let The input box is switched to the displayable state, and the user can see the input box on the corresponding cell of the table.
<div
if="{{isShowArea}}"
style="width: 100px; height: 25px; top: {{areaTop}}px; left: {{areaLeft}}px"
>
<textarea
if="{{isShowArea}}"
focus="{{isFocus}}"
value="{{content}}"
selectchange="change"
onchange="change"
></textarea>
</div>
With the input box, we can monitor the user's input operation. We bind the input event to the textarea
component. When the component reaches the event trigger condition, the corresponding event callback function in JS
UI
view and page JS
logic Layer interaction, the event callback function can carry additional information through parameters, such as the data object dataset
event-specific callback parameters on the component, when the component triggers the event, the event callback function will receive an event object by default, through the event object Corresponding information can be obtained. We get the value entered by the user through the event object, and call the cell
method to re-update the value of the corresponding cell in the table. Of course, the actual situation is sometimes complicated. For example, the user modifies the color of the cell text, so here The data format will be determined.
textarea.addEventListener("input", (e) => {
let input = e.target.value;
table.cell((ri, ci) => {
if (ri === row && ci === col) {
return (window.data[ri][ci] =
typeof value === "string" || typeof value === "number"
? input
: { ...value, text: input });
}
return window.data[ri][ci];
});
});
The following picture is the actual measurement effect of our real machine. You can see that we have introduced the built-in library @system.prompt
. Click the corresponding cell pop-up window to display the corresponding row and column information, which is convenient for us to develop and debug. We use the built-in input method of the mobile phone to input the content to test, input The box will accurately obtain the information and update it to the table, but the IDE
built in Previewer
is invalid. The guess is that the input event of the keyboard on the PC
Toolbar implementation
With the most basic functions of viewing and editing tables, we can consider implementing the toolbar in the next step. The implementation of the toolbar generally provides settings such as setting row and column height, text bolding, centering, italics, underline and background color. In fact, the above cell style
method cooperates with the row and column position or range information to repackage various interface implementations.
We introduce a few commonly used ones here. colHeader
can set your list row header and its height. If you do not set a value for it, it will also have a default height.
table.colHeader({ height: 50, rows: 2 }).render();
In some cases, when we look up the table, we may need to fix the cells of some rows and some columns to improve the readability of the table. At this time, .freeze
can come in handy. The following settings will help you freeze the C6
within 061db7d4a0fa79. List.
table.freeze("C6").render();
scrollRows
generally used with the frozen area, so that the selection outside the frozen area can be scrolled.
table.scrollRows(2).scrollCols(1).render();
We can use the following method to update the data in the second row and second column of the cell to be 8848
and the color to be red:
table
.cell((ri, ci) => {
if (ri === 2 && ci === 2) {
return {
text: "8848",
style: {
color: "red",
},
};
}
return this.sheet?.[ri]?.[ci] || "";
})
.render();
Since there are too many forms of cells that can be set, we will not expand them here. For details, you can refer to the following interfaces, which support a variety of rich and diverse changes. It can be seen that it is actually very similar to CSS
{
cell: {
text,
style: {
border, fontSize, fontName,
bold, italic, color, bgcolor,
align, valign, underline, strike,
rotate, textwrap, padding,
},
type: text | button | link | checkbox | radio | list | progress | image | imageButton | date,
}
}
We have made some demonstrations of the common interfaces above, run OpenHarmonySheet , long-press any cell to pop up the
dialog box and click the corresponding option to view the running results of common interfaces. This demonstration is for reference only, more practical use Please refer to the documentation for the scenario:
Lifecycles and Events
After completing the above functions, we need to consider exposing the life cycle and events and encapsulate them into a common component for the access party to use.
@sheet-show
table display@sheet-hide
table hidden@click-cell-start
before cell click@click-cell-end
cell 061db7d4a0fd0e is clicked@click-cell-longpress
long press the table@change
Modify cell data
Because OpenHarmony
provides a series of lifecycle callback methods for custom components, it is convenient for developers to manage the internal logic of custom components. The life cycle mainly includes: onInit
, onAttached
, onDetached
, onLayoutReady
, onDestroy
, onPageShow
and onPageHide
. Our form component can use the timing of each lifecycle callback to expose its own lifecycle.
this.$emit("eventName", data);
Here, the name
attribute refers to the custom component name. The component name is not case-sensitive, and lowercase is used by default. src
attribute refers to the file path of the hml
name
attribute is hml
file name is used as the component name by default. Binding components and custom events using subassembly onXXX
or @XXX
syntax subassembly by this.$emit
and traditional values triggering event parameter passed upwardly through custom event bindings, parent component performs bindParentVmMethod
method of transmitting and receiving subassembly parameter.
<element name="Sheet" src="../../components/index.hml"></element>
<Sheet
sheet="{{sheet}}"
@sheet-show="sheetShow"
@sheet-hide="sheetHide"
@click-cell-start="clickCellStart"
@click-cell-end="clickCellEnd"
@click-cell-longpress="clickCellLongpress"
@change="change"
></Sheet>
We packaged all the above, and improved the introduction documents and access documents and uploaded them to Gitee
- [OpenHarmonySheet
]( https://github.com/Wscats/sheet) In the warehouse, our table engine component is completed.
Looking back on the whole process, although it was difficult and challenging, our team still managed to solve it. During the entire competition, our team also learned a lot about Hongmeng. We never had the opportunity to learn about it before. We took the opportunity of this competition. I can re-understand Hongmeng, and I have also met some like-minded developers. Let’s make a summary for the time being. Before participating in the competition, you must find a certain direction. It is best to be familiar with this field and not overlap with other entries. In this way Be responsible for your own work, be friendly to other people's works, and respect the competition. After you have grasped the direction, you must formulate every small plan and final goal, and make specific plans for the early, middle and late stages, and you can't step over the ground. It is too big to be too ambitious. We must complete every small plan down-to-earth. This process is a win-win for the team and ourselves. Although we may not reach the end, looking back at each of our footprints is a reward for our own efforts. The team Members must unite, complete each task in a targeted manner, be conscientious and responsible, help each other, and make progress together. Just like what Hongmeng has experienced, a complete system requires millions of developers to work together to build and polish. I hope There can be more and more good OpenHarmony
open source projects, and we can build our own ecology together without accumulating small steps.
Finally, I sincerely hope that 061db7d4a0ff2d can develop more and more powerfully and smoothly. Although this road is difficult, it is worth it. There will be long winds and waves, and OpenHarmony
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。