background
RELAY has been committed to solving the demands of cloud management for the full cycle of design projects. Therefore, in addition to the core process of uploading design draft and viewing annotations on the Web terminal, browsing at any time and anywhere on the mobile terminal is also a scene we have been paying attention to. In the past, we provided the H5 preview mode, but we could only scan the code for each project separately, considering that mobile manuscripts can be previewed in the actual environment in the design acceptance scenario. This RELAY applet is an attempt to extend content management to mobile, providing a general overview of all design projects. In terms of experience, we hope it can still be light and fast. In addition to viewing design manuscripts by business line and project, we have added two functions that are not available on the Web side: Recently opened will synchronize the most recently viewed projects in the mobile terminal, and search can search projects in all lines of business — all take into account the efficiency cost brought by the hierarchy of business lines and projects, breaking the line of business browsing. Preview QR code can be generated in the Web side project, and small program preview can be opened through wechat scanning; At the same time, the page of H5 terminal can be opened in Beijing M, and the preview page of manuscript list and manuscript details can be opened temporarily.
Basic structures,
First, Taro needs to install @tarojs/cli using NPM or YARN globally. After the project initialization, Taro will start installing the dependencies required for the project by default.
(1) npm install -g @tarojs/cli
(2) taro init myApp
The project practice
The small program is generally divided into, login, line of business list, recently browse list, manuscript list contains view manuscript, users can easily find their recent use of the project, lock the manuscript position and view. H5 page Open the PC relay project manuscript list, manuscript details and preview link in Beijing Me, and convert it into H5 page. The project is divided into two parts to introduce to you, which are the jingdong login and manuscript list page operation of the small program.
Projects show
The login
The small program uses JD plug-in login, currently only JD employees can log in. The development and invocation of open plug-ins in wechat small program need to go through the process to apply for the use of plug-ins. Jingdong login plug-in can be added in the third-party Settings of the small program background, which is convenient to provide basic login services for the small program.
First, there will be a landing page when you enter the mini program. After clicking the button to log in with jingdong account, you will jump to the jingdong plug-in login page.
Note that after a successful login, you need to switch to a certain page. The default page is the home page. If you log in to another page again, you need to switch to the current page. Therefore, the parameter to be carried here is the path to the page after the successful login.
When the JINGdong login plug-in is logged in, it will return to the login verification page. Because there is our own login logic in this page, we need to store two identities locally and exchange user information with these two identities and back-end interaction.
Take a look at the main login logic for the validation page:
-
First, it checks whether there is a local storage with two identifiers. If there is, it requests the back-end interface/API /regist to return user information, and then stores user information globally to facilitate page use.
-
If there are no these two fields, jingdong plug-in login status, if already logged in, and jingdong plug-in Storage information: then with this key request our own interface. Call the login method, request/user/login interface, this interface will return to carry two [‘ Set – cookies’] field, with a defined getCookie (new RegExp through regular matching values (” (^ | to |,) “+ name +” = (/ ^; (*). | $) “)) method to get the two id value.
-
If neither is available or it’s your first entry, go to the landing page.
Here’s the full flow chart:
Here the small program login is completed, but also need to add some state judgment in the project. Next, take a look at the manuscript list page. On this page, you can view the manuscript directly, supporting zooming and zooming.
The manuscript list
First look at this page and analyze the structure: the header shows the name of the current group and the number of articles in the current group. Below are all the sections with headings. Click on the header group to expand all the group names of the current item. Clicking on the group list will jump to the specified group. Similarly, when the list is scrolling, the header will change the group names displayed according to the scrolling position. Click on the picture to view the larger image, and support zoom view.
The current detail file stores the content of the manuscript list page. Index is equivalent to the initialization component, which is mainly used to request data and determine loading:
- The List component builds up the body structure and preserves the header list logic.
- The Scroll component stores the body content of the page, group headings, and the contents of the card.
- The unPage component holds the content of the card, the title of the article, and the image.
- Taro components we used in the process include: ScrollView, previewImage, Image.
First of all, we first introduce the first function, and group options, click on the head page scroll to the specified location, according to our normal logic, first at the time of circulation data, each group assigned an id, then click on the head group, apply to the corresponding id, to match a list of group id, take offsetTop values, then scroll to the specified location.
📣 Note that the element binding ID in Taro cannot start with a number directly, because the data ID starts with a number, so we will concatenate a string beginning with “ID” during the binding.
After repeated attempts, it is found that document cannot be directly used to obtain elements in Taro, but it can be used in H5 environment. Therefore, it is possible to directly obtain the offsetTop value of elements in H5. On small program can be used to provide apiTaro. CreateSelectorQuery () selectAll (‘ elements’). BoundingClientRect, can take elements from the top of the distance, but it is changed by scrolling page, so there is a problem, After scrolling, we actually want to know the fixed offsetTop value when switching groups, so we will save the group value when entering the page, using domOffsetTop:
Taro.createSelectorQuery().selectAll('.group_item').boundingClientRect(function(rects){
rects.forEach(function(rect){
groupId[rect.id] = rect.top
_this.setState({
domOffsetTop:groupId
});
})
}).exec()
Copy the code
There is still a risk that if the network freezes or the image loads slowly, it will result in inaccurate values, even with delay. You then find that you can use the scrollIntoView property of the ScrollView component to set the value of this property directly to the selected group ID. Then the handleChangeGroup method is to click the grouping method, so you can do the positioning function in the small program and H5 side.
Let’s take a look at the scrolling feature, which is where the problem is. Let’s start with a piece of code:
OnScroll = (event=>{contentitems.map (dom =>{if (conditional) {lock group}})})Copy the code
In the onScroll method of ScrollView, loop through all the groups in the page and use getBoundingClientRect to get the set of positions of an element relative to the window. The set has properties like top, right, bottom, and left. If the header is less than 70 and the bottom is greater than 0, we have reached the group. Then we find the data matching the current ID and update it. There is no problem in H5. However, in wechat applet, we can only provide apis to achieve this:
Taro.createSelectorQuery().selectAll('.group_item').boundingClientRect(function(rects){ rects.forEach(function(rect){ if {find the data matching the current id to update}})}).exec()Copy the code
Then in the small program real machine debugging found that the page is very slow when scrolling, and accompanied by flashing, like the following:
Start analyzing the page. Are there more cards? No, it will also get stuck when there are fewer cards, because this is a special case, there is no slip-up loading, after all, click on the head to get to the specified position quickly, so start looking for problems.
There are three points to optimize:
🔔 First point: since the onScroll event is used and an event is frequently triggered, anti-shake and throttling will come to mind, both of which are to solve the performance consumption caused by frequent triggering of an event.
-
For example, in the search process, a method is invoked when the user stops typing to save requested resources.
-
Throttling refers to requesting an event at regular intervals when it is frequently triggered. It is similar to long pressing a button when playing a game. The action is triggered at regular intervals.
So let’s do a bit of an anti-shock, put it in the util file and throw debounce: onScroll = debounce((event)=>{})
🔔 Second point: In fact, the first optimization point effectively reduces the number of triggered events. Then there is another problem that when the interactive group meets the condition, when the head of the group reaches the top, in fact, the judgment is that there will always be a sub-group that meets the condition, so it will be triggered continuously. Then we define a state value, scrollHeadID, Rect.id. slice(2) === item.id && rect.id! ScrollHeadID = _this.state.scrollHeadID = _this.state.scrollHeadID = _this.state.scrollHeadID = _this.state.scrollHeadID = _this.state.
🔔 third point: so far is not enough, because the most important point comes, if the page manuscript is more, or the same will be stuck, so further look for the entry point. In React, state is an important part. Although automatic rendering saves us a lot of trouble, it is not easy to do without rendering. Sometimes, the re-rendering mechanism of state leads to unnecessary rendering, so it is necessary to study and apply it in some specific situations.
Therefore, when I look at the child component render, I find that when sliding, there will be setState to change the state value, but in this case, if there is a lot of manuscript, when the parent component changes the state, it will cause the child component to re-render, and too much data will inevitably cause a lot of resource reloading waste. Because the manuscript is fixed at this point.
React.PureComponent: react. PureComponent: react. PureComponent: react. PureComponent: react. PureComponent: react. PureComponent: react. PureComponent
Class Demo extends PureComponent{render() {console.log(" Do I repeat render? ) return ( { this.props.cont } ) } }Copy the code
import React { memo } from 'react' const memoDemo = memo(props => { return <div>... </div> })Copy the code
📣 Note: React.PureComponent relies on the class form to use it. And react.Memo () can be used with functional Component. By default, the react.purecomponent and react.Memo () are only used for shallow object comparisons. There is another way, that is, shouldComponentUpdate function, when he was a heavy rendering render () function call before the called function, it takes two parameters: the nextProps and nextState, said the next props and the value of the next state. Also, when the function returns false, it blocks the subsequent render() call, preventing the component from rerendering, and when the function returns true, the component rerenders as usual. I feel this way is more direct and flexible, so I use shouldComponentUpdate function to modify it. In the Scroll component, we will pass in a domId, which can be used to judge. The unPage component returns false if the card is passed with the same data, preventing rendering:
If (this.state.imgupdate) return true if(this.props. DomId! = 'fasle' && ! This.state.isrender){if(nextProps. DomId == this.props. DomId){return false}} return true} unPage component: shouldComponentUpdate(nextProps) { if(nextProps.page == this.props.page){ return false } return true }Copy the code
So far, we have gone through three layers of optimization, and look at the results:
You can see that entering the manuscript page is very smooth, and viewing the larger image is also very smooth.
At the same time, in the right panel of the project list on the PC side, you can directly scan the TWO-DIMENSIONAL code to enter the current project list in the small program.
Sometimes have this kind of scenario, at the time of using the RELAY platform, I may be in PC browsing, need to copy the articles list or details to my colleague to look at the copy of the project together, if using a mobile phone directly copy the link within the product, the other is actually the PC open the page, so they need to generate the H5 end page, For now, the manuscript list and the manuscript details page are transformed. In PC main js add judgment, judgment is in the global routing functions and mobile is to open the Beijing M environment H5 page:
router.beforeResolve( async (to, from, next) => { var reg = RegExp(/\/preview/) var userAgent = navigator.userAgent.toLowerCase() if(userAgent && / (iphone | android). * jdme /. The test (userAgent)) {judge jump to specify page}})Copy the code
To view a larger version
On the applet side, we can use the built-in API syntax Taro. PreviewImage. This function accepts an object, current, which represents the HTTP link to the currently displayed image. Therefore, we added click events to Image in the unPage component. Once we got the data in the list component, we saved the Image of the manuscript list into the list array, so it can be used directly. HandlePreviewImage:
HandlePreviewImage = (imageUrl)=>{const {list} = this.props. Showmenu :false})}Copy the code
It can be seen that clicking the picture can view the larger picture, and you can switch the manuscript to view, is it the same on the H5 end? Unfortunately, it can not be completely adapted. In H5 page, only pictures can be switched, and gesture zooming is not supported. Therefore, at this time, we need to judge the device and adopt another solution when H5 ends the page. A built-in environment variable, process.env.taro_env, is used. This variable can be used to evaluate the current compilation type. Currently, there are 8 values including appellate, swan, Alipay, H5, Rn, TT, QQ, and QuickApp. You can use this variable to write codes corresponding to different environments, and remove the codes that do not belong to the current compilation type during compilation. Only keep the code under the current compilation type, for example, want to reference different resources in wechat applet and H5 side respectively.
It is possible to introduce third-party plugins in H5, so I used WxImageViewer once. Although it has all the required functions, the effect is problematic, and the image will fly off the screen when I slide it. That’s not going to work. Continue exploring…… After three plugins, react-photo-view looks the best.
Can use NPM or yarn to install: NPM | | yarn add react – photo – the view
The basic use of introducing plug-ins in a project along with CSS stylesheets is nested like this:
import { PhotoProvider, PhotoConsumer } from 'react-photo-view';
import 'react-photo-view/dist/index.css';
function ImageView() {
return (
<PhotoProvider>
{photoImages.map((item, index) => (
<PhotoConsumer key={index} src={item} intro={item}>
<img src={item} alt="" />
</PhotoConsumer>
))}
</PhotoProvider>
);
}
Copy the code
Look a little trouble, the official also provides another use of plug-in PhotoSlider, it inherits from PhotoProvider, manual control the react – photo – the view to show and hide, can need not change existing unPage structure that is to say, Added PhotoSlider component to do H5 page click to see larger image.
return (
<View className='img-border'>
<View key={page.id} className='img-border'>
<Image className='img' mode='widthFix' onClick={(e)=>{this.handlePreviewImage(page.image,page.id,e)}} src={src} onError={this.imgError.bind(this, page)} />
</View>
</View>
<PhotoSlider
onIndexChange={this.setPhotoIndex.bind(this)}
images={imgArr.map(item => ({ src: item }))}
visible={isOpen}
onClose={() => this.onClose(false)}
index={photoIndex}
photoClosable={true}
/>
</View>
)
Copy the code
Images: is an array of images for the manuscript. Visible: Whether to display. Index: indicates the index value of the current image. OnIndexChange: Index change callback.
Taron. previewImage is not the same as taron. previewImage. When switching images, you need to reset the index of the current image in the index change callback function.
setPhotoIndex = (e) => {
this.setState({photoIndex: e})
}
Copy the code
Let’s take a look at the display effect in the H5 terminal page:
conclusion
With the addition of small programs and mobile terminal H5, I believe that it will bring great convenience to many users. When you are on the bus, subway, or at a conference, you can preview the latest project on your mobile phone, quickly preview the manuscript, so that you can seamlessly connect. In fact, in this small program development, also encountered a lot of problems and some pits, but also step by step to optimize and solve the problem. At the same time, it is necessary to summarize and plan the development steps. When encountering difficulties, we will sort out step by step, and there will always be some harvest. If you have good suggestions on RELAY platform, welcome to discuss, thank you.
Welcome to visit RELAY collaborative design platform (relay.jd.com) also hope that you put forward more valuable opinions, looking forward to further communication, common progress together.
Also present the RELAY applets QR code: