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?

  1. 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
  1. 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
  1. 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

  1. 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