Write good JS principles
Do their job
- HTML is responsible for structure
- CSS is responsible for presentation
- JavaScript is responsible for behavior
Here’s an example:
We want to change the page by clicking on the sun or moon
Solution a:
We can capture the icon click event, click to change the font color and background color.
But this couples JS to CSS
Scheme 2:
We changed js to modify the style directly, and changed js to modify the element class, the style transformation is left to CSS.
Solution 3:
A pure CSS solution without JS
The state is captured in the form of an input check box and a label
When we click on label, the corresponding check box is also clicked
The mode can be switched through the selected state pseudo-class of the checkbox
Either the second or the third option is better than the first option.
Conclusion:
- HTML/CSS/JS is responsible
- Unnecessary direct manipulation of styles by JS should be avoided
- You can use class to represent state
- Pure presentation class interaction seeks zero JS scheme
Component packaging
A component is a unit of a Web page that contains templates (HTML), functions (JS), and styles (CSS).
Component design principles:
- encapsulation
- correctness
- scalability
- Reusability.
When encapsulating components, don’t just try to get them right.
We can start with simple features and iterate and optimize.
Component encapsulation can start with the following steps:
Component design steps
The structure design
Show the effect
Behavior design
- API (Features)
- Event (Control flow)
The following illustrates the component encapsulation process using an example of creating a multicast diagram component.
The structure design
Structure design is the first step, we need to display all the elements in the HTML document
For a caroute diagram component, it is a container that contains a list of images
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<link rel="stylesheet" href="slider.css">
</head>
<body>
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list__item--selected">
<img src="https://img12.360buyimg.com/pop/s590x470_jfs/t1/200666/3/2407/80779/611cbdbfE67561765/802cf07557ad00c6.jpg.webp" alt="">
</li>
<li class="slider-list__item">
<img src="https://imgcps.jd.com/ling4/100009077475/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5f3a47329785549f6bc7a6e0/0f1863cd/cr/s /q.jpg" alt="">
</li>
<li class="slider-list__item">
<img src="https://img13.360buyimg.com/pop/s590x470_jfs/t1/204538/27/418/100695/6110eb81E40c33891/98a22a2cf9021e4e.jpg.webp" alt="">
</li>
<li class="slider-list__item">
<img src="https://img10.360buyimg.com/pop/s590x470_jfs/t1/184419/8/18902/98852/6114bd1bEa22d6dbb/1cfa09c57dbf3817.jpg.webp" alt="">
</li>
</ul>
</div>
</body>
<script src="slider.js"></script>
</html>
Copy the code
Display effect
Once the structure is designed, what we see in the browser is an array of elements.
We need to adjust the style of different elements according to the design requirements. Including location, size, color and so on
For the rotation image, we want to set the image to absolute position, opacity of no display to 0, opacity of display to 1
#my-slider {
position: relative;
width: 590px;
}
.slider-list ul {
list-style-type: none;
position: relative;
padding: 0;
margin: 0;
}
.slider-list__item..slider-list__item--selected {
position: absolute;
transition: opacity 1s;
opacity: 0;
text-align: center;
}
.slider-list__item--selected {
transition: opacity 1s;
opacity: 1;
}
Copy the code
After adding CSS, all of the images are centralized and have a rotating image feel. Here is how to control which images are displayed
Behavior design
When designing the behavior of a component, we need to tailor it to its functionality.
Provides apis for various functions during encapsulation.
API (Features)
API design should ensure atomic operation, single responsibility and flexibility.
For a multicast image, we need to be able to control the jump to a given image, to the previous image, to the next image
I did some packaging design
class Slider {
constructor(id) {
this.container = document.getElementById(id);
this.items = this.container.querySelectorAll(".slider-list__item,.slider-list__item--selected");
}
getSelectedItem() {
const select = this.container.querySelector(".slider-list__item--selected");
return select;
}
getSelectedItemIndex() {
return Array.from(this.items).indexOf(this.getSelectedItem());
}
sliderTo(index) {
const select = this.getSelectedItem();
if (select) {
select.className = "slider-list__item";
}
const item = this.items[index];
if (item) {
this.items[index].className = "slider-list__item--selected"; }}sliderNext() {
const index = this.getSelectedItemIndex();
const nextIndex = (index + 1) % this.items.length;
this.sliderTo(nextIndex);
}
sliderPrevious() {
const index = this.getSelectedItemIndex();
const previousIndex = (index + this.items.length - 1) % this.items.length;
this.sliderTo(previousIndex); }}Copy the code
Event (Control flow)
Do the previous part we have the control object for the wheel cast diagram
In order to really achieve the effect of rotation graphics, we need to design the control flow
We mainly design three control functions for the rote graph
- Page regularly
- Click left and right to turn the page
- Turn the page at the lower control point
With this control idea in mind, write the elements used for the control into an HTML document
<a class="slider-list__previous"><</a>
<a class="slider-list__next">></a>
<div class="slider-list__control">
<span class="slider-list__control-buttons--selected"></span>
<span class="slider-list__control-buttons"></span>
<span class="slider-list__control-buttons"></span>
<span class="slider-list__control-buttons"></span>
</div>
Copy the code
Setting the style for the element
.slider-list__next..slider-list__previous {
position: absolute;
top: 200px;
line-height: 40px;
padding: 0 5px 5px 5px;
background-color: black;
opacity: 0;
font-size: 30px;
color: white;
}
.slider-list__next:hover..slider-list__previous:hover {
opacity: 0.7;
transition: opacity 0.5 s;
}
.slider-list__next {
right: 0;
}
.slider-list__control {
position: absolute;
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
bottom: 40px;
left: 260px;
height: 20px;
width: 70px;
background-color: rgba(185.183.183.0.911);
border-radius: 10px;
}
.slider-list__control-buttons..slider-list__control-buttons--selected {
height: 10px;
width: 10px;
background-color: white;
border-radius: 5px;
}
.slider-list__control-buttons--selected {
background-color: red;
}
Copy the code
With that in mind, here’s how to use JS to drive the transformation of the element class
For periodic page turning, in fact, is to set a timer, the method of periodic page turning. But since left and right page turns or control point page turns may be used in the control process, we can’t have them in conflict with each other. We need to set the start and stop for the timed page turning. When we turn left and right or turn control points, we need to stop first, and then start after turning over.
We added two methods to the Slider class
start() {
this.stop();
this._timer = setInterval(() = > {
this.sliderNext();
}, this.cycle)
}
stop() {
clearInterval(this._timer);
}
Copy the code
For the left and right page flipping, we directly add the click listening event when the Slider class is initialized. After clicking, the timer will be turned off first, and the timer will be turned on again after the page flipping.
/ / forward
const previous = this.container.querySelector(".slider-list__previous");
if (previous) {
previous.addEventListener('click'.evt= > {
this.stop();
this.sliderPrevious();
this.start(); evt.preventDefault(); })}/ / turn back
const next = this.container.querySelector(".slider-list__next");
if (next) {
next.addEventListener('click'.evt= > {
this.stop();
this.sliderNext();
this.start(); evt.preventDefault(); })}Copy the code
For control point page-turning, our control point needs to correspond with the current picture displayed at all times, which involves the coupling between the current control point and the current picture. For decoupling, we design a custom event ourselves.
An event is raised when the page turn method is executed.
const detail = { index: index }
const event = new CustomEvent("slide", { bubbles: true, detail })
this.container.dispatchEvent(event);
Copy the code
Then set the monitoring of the event. When the page-turning event is monitored, we modify the current control point.
this.container.addEventListener('slide'.evt= > {
const idx = evt.detail.index;
const selected = controller.querySelector('.slider-list__control-buttons--selected');
if (selected) {
selected.className = "slider-list__control-buttons";
}
buttons[idx].className = "slider-list__control-buttons--selected";
})
Copy the code
Once you’ve done this, you’ve basically wrapped the entire component
The full code is posted here
HTML part
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<link rel="stylesheet" href="slider.css">
</head>
<body>
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list__item--selected">
<img src="https://img12.360buyimg.com/pop/s590x470_jfs/t1/200666/3/2407/80779/611cbdbfE67561765/802cf07557ad00c6.jpg.webp" alt="">
</li>
<li class="slider-list__item">
<img src="https://imgcps.jd.com/ling4/100009077475/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5f3a47329785549f6bc7a6e0/0f1863cd/cr/s /q.jpg" alt="">
</li>
<li class="slider-list__item">
<img src="https://img13.360buyimg.com/pop/s590x470_jfs/t1/204538/27/418/100695/6110eb81E40c33891/98a22a2cf9021e4e.jpg.webp" alt="">
</li>
<li class="slider-list__item">
<img src="https://img10.360buyimg.com/pop/s590x470_jfs/t1/184419/8/18902/98852/6114bd1bEa22d6dbb/1cfa09c57dbf3817.jpg.webp" alt="">
</li>
</ul>
<a class="slider-list__previous"><</a>
<a class="slider-list__next">></a>
<div class="slider-list__control">
<span class="slider-list__control-buttons--selected"></span>
<span class="slider-list__control-buttons"></span>
<span class="slider-list__control-buttons"></span>
<span class="slider-list__control-buttons"></span>
</div>
</div>
</body>
<script src="slider.js"></script>
</html>
Copy the code
The CSS part
#my-slider {
position: relative;
width: 590px;
height: 474px;
}
.slider-list ul {
list-style-type: none;
position: relative;
padding: 0;
margin: 0;
}
.slider-list__item..slider-list__item--selected {
position: absolute;
transition: opacity 1s;
opacity: 0;
text-align: center;
}
.slider-list__item--selected {
transition: opacity 1s;
opacity: 1;
}
.slider-list__next..slider-list__previous {
position: absolute;
top: 200px;
line-height: 40px;
padding: 0 5px 5px 5px;
background-color: black;
opacity: 0;
font-size: 30px;
color: white;
}
.slider-list__next:hover..slider-list__previous:hover {
opacity: 0.7;
transition: opacity 0.5 s;
}
.slider-list__next {
right: 0;
}
.slider-list__control {
position: absolute;
display: flex;
flex-direction: row;
justify-content: space-evenly;
align-items: center;
bottom: 40px;
left: 260px;
height: 20px;
width: 70px;
background-color: rgba(185.183.183.0.911);
border-radius: 10px;
}
.slider-list__control-buttons..slider-list__control-buttons--selected {
height: 10px;
width: 10px;
background-color: white;
border-radius: 5px;
}
.slider-list__control-buttons--selected {
background-color: red;
}
Copy the code
Js part
class Slider {
constructor(id, cycle = 3000) {
this.cycle = cycle;
this.container = document.getElementById(id);
this.items = this.container.querySelectorAll(".slider-list__item,.slider-list__item--selected");
/ / forward
const previous = this.container.querySelector(".slider-list__previous");
if (previous) {
previous.addEventListener('click'.evt= > {
this.stop();
this.sliderPrevious();
this.start(); evt.preventDefault(); })}/ / turn back
const next = this.container.querySelector(".slider-list__next");
if (next) {
next.addEventListener('click'.evt= > {
this.stop();
this.sliderNext();
this.start(); evt.preventDefault(); })}/ / control points
const controller = this.container.querySelector(".slider-list__control");
if (controller) {
const buttons = controller.querySelectorAll('.slider-list__control-buttons,.slider-list__control-buttons--selected');
controller.addEventListener("mouseover".evt= > {
const idx = Array.from(buttons).indexOf(evt.target);
if (idx >= 0) {
this.sliderTo(idx);
this.stop();
}
})
controller.addEventListener('mouseout'.evt= > {
this.start();
})
this.container.addEventListener('slide'.evt= > {
const idx = evt.detail.index;
const selected = controller.querySelector('.slider-list__control-buttons--selected');
if (selected) {
selected.className = "slider-list__control-buttons";
}
buttons[idx].className = "slider-list__control-buttons--selected"; }}})getSelectedItem() {
const select = this.container.querySelector(".slider-list__item--selected");
return select;
}
getSelectedItemIndex() {
return Array.from(this.items).indexOf(this.getSelectedItem());
}
sliderTo(index) {
const select = this.getSelectedItem();
if (select) {
select.className = "slider-list__item";
}
const item = this.items[index];
if (item) {
this.items[index].className = "slider-list__item--selected";
}
const detail = { index: index }
const event = new CustomEvent("slide", { bubbles: true, detail })
this.container.dispatchEvent(event);
}
sliderNext() {
const index = this.getSelectedItemIndex();
const nextIndex = (index + 1) % this.items.length;
this.sliderTo(nextIndex);
}
sliderPrevious() {
const index = this.getSelectedItemIndex();
const previousIndex = (index + this.items.length - 1) % this.items.length;
this.sliderTo(previousIndex);
}
start() {
this.stop();
this._timer = setInterval(() = > {
this.sliderNext();
}, this.cycle)
}
stop() {
clearInterval(this._timer); }}const slider = new Slider("my-slider".2000);
slider.start();
Copy the code
Refactoring one: plug-in
We’ve done everything we wanted, but we can see that there’s a lot of code in the constructor that initializes the sliders as well as the control elements.
The coupling of the control element with our package is too high to be used in combination with other control buttons.
So we want to decouple
- Extract control elements into plug-ins
- Pass between plug-in and componentDependency injectionTo establish a connection
We’ll start by adding dependency injection methods to the Slider class
registerPlugins(. plugins) {
plugins.forEach(plugin= > plugin(this));
}
Copy the code
Then there are three plug-ins outside the class
function pluginPrevious(slider) {
/ / forward
const previous = slider.container.querySelector(".slider-list__previous");
if (previous) {
previous.addEventListener('click'.evt= >{ slider.stop(); slider.sliderPrevious(); slider.start(); evt.preventDefault(); }}})function pluginNext(slider) {
/ / turn back
const next = slider.container.querySelector(".slider-list__next");
if (next) {
next.addEventListener('click'.evt= >{ slider.stop(); slider.sliderNext(); slider.start(); evt.preventDefault(); }}})function pluginController(slider) {
/ / control points
const controller = slider.container.querySelector(".slider-list__control");
if (controller) {
const buttons = controller.querySelectorAll('.slider-list__control-buttons,.slider-list__control-buttons--selected');
controller.addEventListener("mouseover".evt= > {
const idx = Array.from(buttons).indexOf(evt.target);
if (idx >= 0) {
slider.sliderTo(idx);
slider.stop();
}
})
controller.addEventListener('mouseout'.evt= > {
slider.start();
})
slider.container.addEventListener('slide'.evt= > {
const idx = evt.detail.index;
const selected = controller.querySelector('.slider-list__control-buttons--selected');
if (selected) {
selected.className = "slider-list__control-buttons";
}
buttons[idx].className = "slider-list__control-buttons--selected"; }}})Copy the code
The three functions were originally executed inside the constructor of the Slider class, depending on the Slider’s this. We just separate these three functions out and pass the Slider’s this parameter to them using the plugin’s registerPlugins method.
const slider = new Slider("my-slider".2000);
slider.registerPlugins(/*pluginController,*/ pluginPrevious, pluginNext)
slider.start();
Copy the code
This way we can comment out any functionality we don’t want to use, or add a button to control it, and then register the plugin into the slider
Refactoring two: Templating
After the pluginization we just did, we actually decoupled the control program from the Slider class.
If we want to control without using control points, we simply comment out the registration where the plug-in is registered
const slider = new Slider("my-slider".2000);
slider.registerPlugins(/*pluginController,*/ pluginPrevious, pluginNext);
slider.start();
Copy the code
This disables our control points method, but we will find that there will still be control points on the page. And the control point does not change with the change of pictures.
So we need to put the HTML code into JS and let JS render the structure.
That leaves our HTML with just one line of code
<div id="my-slider" class="slider-list"></div>
Copy the code
Our CSS doesn’t have to change
js
class Slider {
constructor(id, opts = { images: [], cycle: 3000 }) {
this.options = opts;
this.container = document.getElementById(id);
this.container.innerHTML = this.render();
this.items = this.container.querySelectorAll(".slider-list__item,.slider-list__item--selected");
this.cycle = opts.cycle || 3000;
this.sliderTo(0);
}
render() {
const images = this.options.images;
const content = images.map(image= > `
<li class="slider-list__item">
<img src="${image}">
</li>
`.trim())
return `
<ul>${content.join("")}</ul>
`
}
registerPlugins(. plugins) {
plugins.forEach(plugin= > {
const pluginContainer = document.createElement('div');
pluginContainer.className = "slider-list__plugin";
pluginContainer.innerHTML = plugin.render(this);
this.container.appendChild(pluginContainer);
plugin.action(this)}); }getSelectedItem() {
const select = this.container.querySelector(".slider-list__item--selected");
return select;
}
getSelectedItemIndex() {
return Array.from(this.items).indexOf(this.getSelectedItem());
}
sliderTo(index) {
const select = this.getSelectedItem();
if (select) {
select.className = "slider-list__item";
}
const item = this.items[index];
if (item) {
this.items[index].className = "slider-list__item--selected";
}
const detail = { index: index }
const event = new CustomEvent("slide", { bubbles: true, detail })
this.container.dispatchEvent(event);
}
sliderNext() {
const index = this.getSelectedItemIndex();
const nextIndex = (index + 1) % this.items.length;
this.sliderTo(nextIndex);
}
sliderPrevious() {
const index = this.getSelectedItemIndex();
const previousIndex = (index + this.items.length - 1) % this.items.length;
this.sliderTo(previousIndex);
}
start() {
this.stop();
this._timer = setInterval(() = > {
this.sliderNext();
}, this.cycle)
}
stop() {
clearInterval(this._timer); }}const pluginPrevious = {
render() {
return `< `;
},
action(slider) {
/ / forward
const previous = slider.container.querySelector(".slider-list__previous");
if (previous) {
previous.addEventListener('click'.evt= >{ slider.stop(); slider.sliderPrevious(); slider.start(); evt.preventDefault(); })}}}const pluginNext = {
render() {
return `> `;
},
action(slider) {
/ / turn back
const next = slider.container.querySelector(".slider-list__next");
if (next) {
next.addEventListener('click'.evt= >{ slider.stop(); slider.sliderNext(); slider.start(); evt.preventDefault(); })}}}const pluginController = {
render(slider) {
const controller = slider.options.images.map((image, index) = > {
if (slider.getSelectedItemIndex() == index) {
return ` `.trim();
} else {
return ` `.trim(); }})return `<div class="slider-list__control">${controller.join("")}</div>`;
},
action(slider) {
/ / control points
const controller = slider.container.querySelector(".slider-list__control");
if (controller) {
const buttons = controller.querySelectorAll('.slider-list__control-buttons,.slider-list__control-buttons--selected');
controller.addEventListener("mouseover".evt= > {
const idx = Array.from(buttons).indexOf(evt.target);
if (idx >= 0) {
slider.sliderTo(idx);
slider.stop();
}
})
controller.addEventListener('mouseout'.evt= > {
slider.start();
})
slider.container.addEventListener('slide'.evt= > {
const idx = evt.detail.index;
const selected = controller.querySelector('.slider-list__control-buttons--selected');
if (selected) {
selected.className = "slider-list__control-buttons";
}
buttons[idx].className = "slider-list__control-buttons--selected"; })}}}const images = [
"https://img12.360buyimg.com/pop/s590x470_jfs/t1/200666/3/2407/80779/611cbdbfE67561765/802cf07557ad00c6.jpg.webp"."https://imgcps.jd.com/ling4/100009077475/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5f3a47329785549f6bc7a6e0/0f1863cd/cr/s /q.jpg"."https://img13.360buyimg.com/pop/s590x470_jfs/t1/204538/27/418/100695/6110eb81E40c33891/98a22a2cf9021e4e.jpg.webp"."https://img10.360buyimg.com/pop/s590x470_jfs/t1/184419/8/18902/98852/6114bd1bEa22d6dbb/1cfa09c57dbf3817.jpg.webp"
]
const slider = new Slider("my-slider", { images, cycle: 2000 });
slider.registerPlugins(pluginController, pluginPrevious, pluginNext)
slider.start();
Copy the code
Refactoring three: Component frameworks
So far, from the point of view of the rotator, this has worked out pretty well
But if we are definitely designing a site with more than one component, we can abstract out a more general component model. Use this component model to create more components.
So we can write an abstract component class
class Component {
constructor(id, opts = { name, data: [] }) {
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render(opts.data);
}
registerPlugins(. plugins) {
plugins.forEach(plugin= > {
const pluginContainer = document.createElement('div');
pluginContainer.className = `The ${this.name}__plugin`;
pluginContainer.innerHTML = plugin.render(this);
this.container.appendChild(pluginContainer);
plugin.action(this)}); }render(component) {
/ / abstract
return ""; }}Copy the code
Use this abstract component class to design the Slider class
class Slider extends Component {
constructor(id, opts = { name: "slider-list", data: [], cycle: 3000 }) {
super(id, opts);
this.items = this.container.querySelectorAll(".slider-list__item,.slider-list__item--selected");
this.cycle = opts.cycle || 3000;
this.sliderTo(0);
}
render(data) {
const content = data.map(image= > `
<li class="slider-list__item">
<img src="${image}">
</li>
`.trim())
return `
<ul>${content.join("")}</ul>
`
}
getSelectedItem() {
const select = this.container.querySelector(".slider-list__item--selected");
return select;
}
getSelectedItemIndex() {
return Array.from(this.items).indexOf(this.getSelectedItem());
}
sliderTo(index) {
const select = this.getSelectedItem();
if (select) {
select.className = "slider-list__item";
}
const item = this.items[index];
if (item) {
this.items[index].className = "slider-list__item--selected";
}
const detail = { index: index }
const event = new CustomEvent("slide", { bubbles: true, detail })
this.container.dispatchEvent(event);
}
sliderNext() {
const index = this.getSelectedItemIndex();
const nextIndex = (index + 1) % this.items.length;
this.sliderTo(nextIndex);
}
sliderPrevious() {
const index = this.getSelectedItemIndex();
const previousIndex = (index + this.items.length - 1) % this.items.length;
this.sliderTo(previousIndex);
}
start() {
this.stop();
this._timer = setInterval(() = > {
this.sliderNext();
}, this.cycle)
}
stop() {
clearInterval(this._timer); }}const pluginPrevious = {
render() {
return `< `;
},
action(slider) {
/ / forward
const previous = slider.container.querySelector(".slider-list__previous");
if (previous) {
previous.addEventListener('click'.evt= >{ slider.stop(); slider.sliderPrevious(); slider.start(); evt.preventDefault(); })}}}const pluginNext = {
render() {
return `> `;
},
action(slider) {
/ / turn back
const next = slider.container.querySelector(".slider-list__next");
if (next) {
next.addEventListener('click'.evt= >{ slider.stop(); slider.sliderNext(); slider.start(); evt.preventDefault(); })}}}const pluginController = {
render(slider) {
const controller = slider.options.data.map((image, index) = > {
if (slider.getSelectedItemIndex() == index) {
return ` `.trim();
} else {
return ` `.trim(); }})return `<div class="slider-list__control">${controller.join("")}</div>`;
},
action(slider) {
/ / control points
const controller = slider.container.querySelector(".slider-list__control");
if (controller) {
const buttons = controller.querySelectorAll('.slider-list__control-buttons,.slider-list__control-buttons--selected');
controller.addEventListener("mouseover".evt= > {
const idx = Array.from(buttons).indexOf(evt.target);
if (idx >= 0) {
slider.sliderTo(idx);
slider.stop();
}
})
controller.addEventListener('mouseout'.evt= > {
slider.start();
})
slider.container.addEventListener('slide'.evt= > {
const idx = evt.detail.index;
const selected = controller.querySelector('.slider-list__control-buttons--selected');
if (selected) {
selected.className = "slider-list__control-buttons";
}
buttons[idx].className = "slider-list__control-buttons--selected"; })}}}const images = [
"https://img12.360buyimg.com/pop/s590x470_jfs/t1/200666/3/2407/80779/611cbdbfE67561765/802cf07557ad00c6.jpg.webp"."https://imgcps.jd.com/ling4/100009077475/5Lqs6YCJ5aW96LSn/5L2g5YC85b6X5oul5pyJ/p-5f3a47329785549f6bc7a6e0/0f1863cd/cr/s /q.jpg"."https://img13.360buyimg.com/pop/s590x470_jfs/t1/204538/27/418/100695/6110eb81E40c33891/98a22a2cf9021e4e.jpg.webp"."https://img10.360buyimg.com/pop/s590x470_jfs/t1/184419/8/18902/98852/6114bd1bEa22d6dbb/1cfa09c57dbf3817.jpg.webp"
]
const slider = new Slider("my-slider", { data: images, cycle: 2000 });
slider.registerPlugins(pluginController, pluginPrevious, pluginNext)
slider.start();
Copy the code
The code involved can be learned in 03.js · Craipy/ youth Camp notes code – code… In the view
Procedural abstraction
- A method used to handle local detail control
- Basic application of functional programming ideas
We think of the function itself as a controller, and we care about the inputs and outputs of the controller
To understand:
Operation limit
Let’s take an example. A list of tasks, we click on it to say that the task is done, and then the task fades away, and when it disappears, after deleting the element from the list, we can easily write the code on the right.
This code normally runs fine, but if the same task button is clicked twice in a row, an error is reported.
Because two asynchronous tasks were created, the first one removed the element, and the second one reported an error.
To enable a requirement that is executed once to be covered by different event handlers, we can separate the requirement out, a process we call process abstraction.
So much of what we’ve been talking about, component encapsulation, is really data abstraction, abstracting out data, abstracting out an object, and then passing that object to our plug-in.
In fact process abstraction we can take an action, a function and give it to more tasks to use.
Here’s an example:
We have a person, there is a door, the person has to open the door to enter the room.
If we abstract people out, that’s data abstraction;
In fact, we can also abstract out the action of opening the door, which is process abstraction.
Now, if we do this once, we can write a higher-order function. That is, each function is cleaned up after it is executed once. So that solves the problem of execution once, and it’s also universal.
Higher-order functions
- Take a function as an argument
- Take a function as the return value
- Often used as a function decorator
The basic normal form of higher order function — equivalent normal form
Commonly used higher-order functions
- Once
- Throttle – throttling
- Debounce – stabilization
- Consumer / 2 — Tasks execute asynchronously
- Iterative — Iterative
In general, when we have this kind of problem, we don’t want to use higher-order functions. I’m thinking about how to solve these problems in the current function.
Considering only the current function, then we might define the global flag bit. Although this can be achieved, but maybe later, when another function also has such a function, we will use the same method, the same idea to write again.
But to solve this problem, when we look at the function as a whole, and the whole thing doesn’t change, we can write another function to call the original function
Like this, if it’s just a normal call, it doesn’t scale very well. If we call functions as parameters, we can extend this operation to all functions.
Programming paradigm
In conclusion, we can summarize programming into two paradigms
- imperative
- declarative
What does the imperative prefer to do
What does the declarative do more
Here’s an example
Toggle – imperative
Toggle – declarative
Toggle – three states
What should you focus on when writing code
- style
- The efficiency of
- convention
- Usage scenarios
- design