On the 15th, I came to the advanced class of Byte Youth Training Camp, and I had to finish a project at the end of the course
First of all, fortunately, our leader is from the Research Institute of Peking University. He has never worked with students of Peking University before. Today, he is not as famous as others.
Project description
FrontendWiki, as its name suggests, is a former wiki that aggregates links to large front-end learning sites around the web to create a user-friendly site for front-end learning
Project Technical Framework
- The React+Ts+Sass technical framework was initially considered, but the React+Css module was eventually settled
- The backend uses the form of SQL database + microservice
What I do?
A tree
A real tree. This is a tree that grows from left to right
It was expected to be implemented in Canvas or SVG, and the style is not that. It is difficult to estimate, so SH and I took over the home page together. Later… Later, I made HHH with div+ CSS through recursion and clever use of CSS
The general approach is as follows:
- TreeNode: Writes a node component, using class
render(){
return(
<div className={styles.nodeContain}>
<div>
{this.props.data.content}
</div>
</div>)}Copy the code
Styles. NodeContain is the basic use of the CSS moudle. Here’s the basic framework, so we’ll implement this component step by step
- Tree: The logic is expected to be complex, so class is still used
What about this Tree?
- First, we should validate the data structure and build a convenient recursive data. This part of the data is theoretically called from the cloud, so we write a special method to get the data directly
getTreeData() {
axios
.get("xxx")
.then((res) = > {
this.setState({
data: res,
});
})
.catch((e) = > {
this.setState({
data: [{content: "CSS".id: "1".level: 0.childrens: [{content: "Animation Properties".id: "1-1".level: 1.childrens: [{content: "transition".id: "1-1-1".level: 2.childrens: []}, {content: "animation".id: "1-1-2".level: 2.childrens: []}, {content: Bessel function.id: "1-1-3".level: 2.childrens: [],},],}, {content: "Selector".id: "1-2".level: 1.childrens: []},],}, {content: "HTML".id: "2".level: 0.childrens: [{content: "Tag set".id: "2-1".level: 1.childrens: [{content: "div".id: "2-1-1".level: 2.childrens: []},],}, {content: "Specification".id: "2-2".level: 1.childrens: []},],}, {content: "React".id: "3".level: 0.childrens: []}, {content: "JS".id: "4".level: 0.childrens: []},],}); }); }Copy the code
The structure is fairly clear, and each node contains this data
- Content, which represents displayed content, such as CSS
- Id, used as the key parameter
- Level, the level of importance, there will be style differences in the tree
- Childrens (there should not be s… , the list of child nodes
- The next step is through recursive spanning trees
getNode(data) {
return data.map((item) = > {
return (
<div key={item.id} className="flexRowNone">
<TreeNode
data={item}
/>
<div>{this.getNode(item.childrens)}</div>
</div>
);
});
}
Copy the code
This is just a simple recursive generation, where flexRowNone looks like this, simple flex+row, to make sure the tree grows to the right, use column if you want to make it vertical, and there are some things that need to be changed
.flexRowNone {
display: flex;
flex-direction: row;
}
Copy the code
- In the last step we implemented the tree, but now the tree has no style
Let’s go back to the TreeNode and style the TreeNode, very simple implementation
.nodeContain{
position: relative;
display: flex;
margin-left:.6rem;
margin-top:.9rem;
}
Copy the code
Once you have done this, you will see that you have successfully generated a tree, which now has no style
- The icing on the cake
I hope that user clicks will generate some click-through feedback in the relevant area, which will improve user feedback
class TreeNode extends React.Component {
constructor(props) {
super(props);
this.state = {
point: false.top: 0.left: 0}; }pointShow(e) {
let { layerX, layerY, offsetX, offsetY } = e.nativeEvent;
this.setState({
top: layerY || offsetY,
left: layerX || offsetX,
point: true});setTimeout(() = > {
this.setState({
point: false}); },600);
}
render() {
return (
<div className={styles.nodeContain}>
<div
onClick={(e)= > {
this.pointShow(e);
}}
style={styleMap[this.props.data.level]}
>
{this.state.point ? (
<div
className={styles.pointCircle}
style={{ top: this.state.top.left: this.state.left }}
></div>
) : (
<></>
)}
{this.props.data.content}
</div></div> ); }}Copy the code
{this.state.point? (
) : (<>)} is actually the core of the click-feedback code; Below is the related dynamic CSS
.pointCircle{
border: solid .6px rgba(20.20.20.0.24);
width:.1px;
height:.1px;
position: absolute;
border-radius: 100%;
animation: showPonitCircle .6s ease;
z-index: 10;
}
@keyframes showPonitCircle{
to{transform: scale(100);opacity: 0;}
}
Copy the code
Post-implementation effect
Light tree is not drop, now need to deal with the tree after clicking the node pop-up
This section of code has little to do with Tree and is handled separately to enhance component reuse
- Estimate the implementation effect
- Control eject in outermost layer
I’m not going to show you the style, but I’m going to control the presentation of the component by controlling the selected ID
- One of the lower left corner of the ball implementation is relatively simple, can be simply stated, the other effect is the best look at my source code
I’m sure I put it in the outermost layer
export var shareFunc={
}
function Home() {
const [headShow,setHeadShow]=useState(true);
const [showParcel, setParcel] = useState(false);
shareFunc.setParcel=setParcel;
return (
<>
{showParcel ? <div className={styles.parcel}></div> : <></>}
{
headShow?<HomeHead />:<></>
}
<HomeMain setHeadShow={setHeadShow}/>
</>
);
}
export default Home;
Copy the code
.parcel{
position: fixed;
height: 100%;
border-radius: 100%;
border: solid .6px # 000;
width: 100%;
width:.1px;
height:.1px;
bottom: 0;
left: 0;
z-index: 100000;
animation: parcelShow ease 1s forwards;
}
@keyframes parcelShow {
50%{transform: scale(3000);opacity: 1; }100%{transform: none;opacity: 0;}
}
Copy the code
This controls the visibility of the ball via setParcel, which I exported via shareFunc for the convenience of local calls
So after clicking somewhere else you can control the animation in the following way, and this piece can actually be encapsulated again
import {shareFunc} from '.. /Home.jsx';
onClick=() = >{
shareFunc.setParcel(true);
setTimeout(() = >{
shareFunc.setParcel(false);
},1500)}Copy the code
It’s mostly UI, but now it’s blocks of data, which are retrieved and stored via Redux
Here’s a quick example of clicking on a tree node to get a list of labels
Reducer
const initState = {
linkList:[]
};
const linkReducer = (state = initState, action) = > {
console.log('state',state)
switch (action.type) {
case "getLinkListStart":
case "getLinkListSuccess":
case "getLinkListFail": state.linkList={... state.linkList, ... action.payload};return{... state};default:
returnstate; }};export default linkReducer;
Copy the code
Reducer provides Action processing in redux. For details, see the actions below
Action
/ * * *@author source
* @updateTime * Get the list of links under the entry through the entry ID; *@param Term {String} * Optional */
const getLinkListAction = (term) = > (dispatch) = > {
getLinksbyTerm(term)
.then((res) = > {
dispatch({
type: "getLinkListSuccess".payload: {[`${term}`] : {data: { ...res },
code: 1,}}}); }) .catch((e) = > {
dispatch({
type: "getLinkListFail".payload: {[`${term}`] : {data: { ...e },
code: -1,}}});console.log("store", store.getState().linkReducer);
});
};
Copy the code
Combining the Reducer and actions, you will know that the Reducer receives data after actions are triggered, and the corresponding data is processed by type and updated into the Store, where dynamic keys are used to ensure that data will not be overwritten each time
At the end
In fact, the project is not difficult, but it is very meaningful and valuable. There is indeed a lack of front-end summary websites on the network, and I hope that each front-end can find its own way