Introduce a,
Swiper is a javascript plugin designed for mobile devices such as mobile phones and tablets. Swiper can realize common effects such as touchscreen focus image, touchscreen Tab switching, and touchscreen wheel casting image switching.
Swiper is widely used in the industry. Last year, the company’s basic data department needed to add image rotation function to Swiper, so I took the opportunity to read the source code of Swiper and expand the Rotate component.
This article, from how to read [email protected] source, to start with custom development, to introduce my ideas, I hope to give you some inspiration and thinking.
How to analyze the source code step by step
Usually when I read source code, I follow the following steps:
- Readme.md
- package.json
- Packaging tools
- Entrance to the file
- Minimum development unit
2.1 the Readme. Md
A Readme is usually an overview of a project. It tells us how to install, compile, package, and use the project, as well as common apis and simple code examples. By reading this, we can get a general understanding of the project, so that we will not get lost in the details later.
Here is part of the readme.md Swiper project:
Install the NPM package
$ npm install --global gulp Install the gulp tool globally
$ npm install Install dependencies for this project
Copy the code
Packaged development releases
$ npm run build:dev
Copy the code
Package results in build/ folder.
Packaged production version
$ npm run build:prod
Copy the code
Package results in package/ folder.
😭😭😭, unfortunately, there is no introduction to how to launch the development environment locally, so next, let’s take a look at package.json…
2.2 package. Json
In package.json, focus first on scripts, dependencies, and devDependencies.
From scripts we can infer locally developed commands because it contains gulp Server, packaged commands;
# [gulp build package]; [Gulp Playground demo environment]; [gulp server local service];
"dev": "cross-env NODE_ENV=development gulp build && cross-env NODE_ENV=development gulp playground && cross-env NODE_ENV=development gulp server".# Local development scripts
npm run dev | yarn dev
Copy the code
There are also other commands, such as lint to execute eslint, test to package dev after lint, etc.
Swiper is a clean project with only two libraries. Most functions are completed independently.
"dependencies": {
"dom7": "^ 2.1.3".# DOM operation encapsulation
"ssr-window": "^" 1.0.1
}
Copy the code
DevDependencies provides a list of engineering tools, compilation tools, and other tools for the project.
"devDependencies": {
"eslint": "^ 6.4.0".// Check the code style
"gulp": "^ 4.0.2." ".// Package the compiler
"less": "^ 3.10.3"./ / less compilation
"postcss": "^ 7.0.18"./ / CSS
"rollup": "^ 1.21.4".// JavaScript module wrapper
},
Copy the code
2.3 Packing Tools
By analyzing package.json, we find gulp, rollup and less. It is easy to imagine that the project uses gulp as an engineering tool, rollup to package JS code, and less to compile less files.
Let’s take a look at gulpfile.js and see, alas, only one line of code
require('./scripts/gulpfile');
Copy the code
All the code related to packaging is arranged into the scripts directory.
The idea of gulp is similar to Grunt, that is, tasks, and then a series of tasks are executed in order to compile and package the code and output the results.
The following is the analysis of gulP tasks in this project: the core server and build tasks.
server
The goal of the task is to start a Web service locallyconnect
And then by monitoring the native codewatch
, there are code changes, will go to repackage JS and CSS, finally openplayground
Address of the online testopen
.build
The goal of the task is to package the project code, and the task to go isjs
andcss
Packaging.
graph TB
A[tasks] --> B[playgroud]
A[tasks] --> C[server]
A[tasks] --> D[build]
C[server] --> G[watch]
C[server] --> H[connect]
C[server] --> I[open]
D[build] --> K[styles]
D[build] --> J[js]
J[js] --> L[es]
J[js] --> M[umd]
K[styles] --> N[less]
G[watch] --> O[js]
G[watch] --> P[styles]
2.3.1 task of js
scripts/build-js.js
We found that two packaging methods of ES and UMD are supported. Esm is the standard Module system proposed by ES6, and UMD stands for Universal Module Definition, which is a scheme combining CommonJS, AMD and CMD, namely, to write a set of code. It can run in different scenarios such as browser and server.
Rollup ->plugins->replace, where ‘//INSTALL_COMPONENTS’ is inserted into the following code string, pure string substitution.
replace({
delimiters: [' '.' '].'process.env.NODE_ENV': JSON.stringify(env),
'//IMPORT_COMPONENTS': components.map((component) = > `import ${component.capitalized} from './components/${component.name}/${component.name}'; `).join('\n'),
'//INSTALL_COMPONENTS': components.map((component) = > `${component.capitalized}`).join(',\n '),
'//EXPORT': 'export default Swiper',}).Copy the code
Search the code and you will find that ‘//INSTALL_COMPONENTS’ exists in the following code, so a batch of component names will be inserted into this location, as will //IMPORT_COMPONENTS, etc.
// Path: SRC /swiper.js
const components = [
Device,
Support,
Browser,
Resize,
Observer,
//INSTALL_COMPONENTS
];
Copy the code
scripts/build-config.js
Package configuration files that record constants, such as Components, which record all components in swiper. When adding new components, add their names here.
The styles of 2.3.2 task
scripts/build-styles.js
The main thing is to use less, to compile and package less files, which I won’t go into here.
2.4 Import File
Let’s take a look at how Swiper is used, usually with two parameters:
var swiper = new Swiper(container,options);
- One is the
container
Is a selector (string orHTML Element
Object); - One is configuration items
options
Is an object:
/ / for
var swiper = new Swiper('.swiper-container', {
pagination: {
el: '.swiper-pagination'.dynamicBullets: true,}});Copy the code
So we initialize a series of components (such as pagination) with New Swiper(), so we need to understand the source code from the Swiper class.
2.4.1 Start from swiper.js
/build-js.js/Swiper/Swiper/Swiper /build-js.js/Swiper
input: './src/swiper.js'.Copy the code
src/swiper.js
Find swiper. Js and the first line of code looks like this. You may have noticed that this is the swiper class definition:
// Swiper Class
import Swiper from './components/core/core-class';
Copy the code
src/components/core/core-class.js
import SwiperClass from '.. /.. /utils/class';
class Swiper extends SwiperClass {
// ...
}
Copy the code
We found core-class, which is derived from SwiperClass, utils/class, so we stopped by.
src/utils/class.js
Alas, SwiperClass has finally arrived. Here is a class diagram of the two classes, listing the main methods and properties.
Figure 2: Swiper class diagram
Next, we will focus on analyzing these three JS in combination with the swimlane diagram below.
Figure 3: Swiper function call
2.4.2 After loading swiper.js, construct the swiper class
Let’s take a look at swiper.js.
// Swiper Class
import Swiper from './components/core/core-class';
//IMPORT_COMPONENTS
const components = [
Device,
Support,
Browser,
Resize,
Observer,
//INSTALL_COMPONENTS
];
if (typeof Swiper.use === 'undefined') {
Swiper.use = Swiper.Class.use;
Swiper.installModule = Swiper.Class.installModule;
}
// The use method is executed, and the component is processed. Let's see what the use method does
Swiper.use(components);
Copy the code
Using utils/class is a static method, line by line: utils/class
/** * is similar to Vue's use method **@static
* @param {*} Module Component or module *@param {*} params
* @returns
* @memberof SwiperClass* /
static use(module. params) {
const Class = this; // Class is SwiperClass
if (Array.isArray(module)) { // If an array is passed in, the registration is iterated
module.forEach((m) = > Class.installModule(m));
return Class;
}
// If a single component is registered directly, does it also provide an opportunity to register components on the run?
return Class.installModule(module. params); }/** * Register a single component **@static
* @param {*} module
* @param {*} params
* @returns
* @memberof SwiperClass* /
static installModule(module. params) {
const Class = this;
if(! Class.prototype.modules) Class.prototype.modules = {};// Module name. The default is name
const name = module.name || (`The ${Object.keys(Class.prototype.modules).length}_${Utils.now()}`);
// Add the component to modules in SwiperClass
Class.prototype.modules[name] = module;
// Bind methods on module.proto to swiperClass.prototype
if (module.proto) {
Object.keys(module.proto).forEach((key) = > {
Class.prototype[key] = module.proto[key];
});
}
// Class
// Bind methods on module.static to SwiperClass
if (module.static) {
Object.keys(module.static).forEach((key) = > {
Class[key] = module.static[key];
});
}
// Call the install method
if (module.install) {
module.install.apply(Class, params);
}
return Class;
}
Copy the code
So, after use and installModule method, SwiperClass. Prototype. The modules object contains all of the component object, SwiperClass. The prototype and SwiperClass binding a number of methods and properties.
2.4.3 New Swiper() example
With the use method, Swiper is ready to initialize the Swiper instance.
var swiper = new Swiper('.swiper-container', {
pagination: {
el: '.swiper-pagination'.dynamicBullets: true,}});Copy the code
The create method for each component is executed, and the events under each component on are collected to the eventsListeners on swiper.emit(‘init’). Triggers the initialization of all components.
The important thing is that two methods are executed
// Install Modules
swiper.useModules();
// Init
if (swiper.params.init) {
swiper.init();
}
Copy the code
useModules
useModules(modulesParams = {}) {
/ / swiper instance
const instance = this;
if(! instance.modules)return;
/ / traverse modules
Object.keys(instance.modules).forEach((moduleName) = > {
const module = instance.modules[moduleName];
const moduleParams = modulesParams[moduleName] || {};
// Extend instance methods and props
// If the component has an instance object, it binds the instance property traversal to instance and this object to. Here module. Instance is slightly different from instance.
if (module.instance) {
Object.keys(module.instance).forEach((modulePropName) = > {
const moduleProp = module.instance[modulePropName];
if (typeof moduleProp === 'function') {
instance[modulePropName] = moduleProp.bind(instance);
} else{ instance[modulePropName] = moduleProp; }}); }// Add event listeners
// Iterate through the events and handlers on the component's ON property, call the on method on swiper instance, and categorically bind to eventsListeners
if (module.on && instance.on) {
Object.keys(module.on).forEach((moduleEventName) = > {
instance.on(moduleEventName, module.on[moduleEventName]);
});
}
// Module create callback
// Execute create if the component has a create method and the object is a swiper instance.
if (module.create) {
module.create.bind(instance)(moduleParams); }}); }Copy the code
init
init() {
const swiper = this;
if (swiper.initialized) return;
// Triggers the beforeInit event
swiper.emit('beforeInit');
/ /... Omit code
// According to the browser environment, configure events such as touch and mouse.
swiper.attachEvents();
// Init Flag
swiper.initialized = true;
// Notify all init events on eventsListeners to be executed
swiper.emit('init');
}
Copy the code
So far, we have examined the process of component registration, class and instance initialization in Swiper. Now we can look at how to design and develop a component based on a single component.
2.4.4 summary
- When swiper.js is loaded via CDN, code construction is performed first
Swiper
Class, the main process is to register the component toSwiper
Of the classprototype
Object, the core method isuse
,installModule
; new Swiper
After that, it will executeSwiper
Of the classconstructor
Method to start based on the specifiedcontainer
De-instantiate the multicast, merge parameters, register events, and then initialize the component to get the multicast running. The core method isuseModules
,useModulesParams
,init
And so on.
2.5 Analyzing a Component
Take Pagination as an example, as shown in the figure below. Pagination encapsulated some common methods. The exported object contained four attributes: Name, params, Create, ON, Create and ON, which would be called when new Swiper was created. Name and params names and initialization parameters.
2.5.1 Pagination object
The create method is bound to the Pagination object, which will be called later, including the registration of listening events, and corresponding processing methods. The core functions of the component are implemented in these methods.
2.5.2 params
The default pager parameters defined in the useModulesParams method are merged into the params property of swiper instance objects.
2.5.3 the create
The create method, called on useModules, initializes the pagination property of Swiper instances;
2.5.4 on
All methods of the ON attribute are classified as useModules and stored in eventsListeners that emit specific events. These provide a global notification, such as the init event mentioned earlier, on swiper instances. Then initialize the Swiper components.
Known events, documented, some of which you should also use when customizing a new component.
init,touchStart,touchMove,touchEnd,slideChangeTransitionStart,
slideChangeTransitionEnd,imagesReady,transitionStart,transitionEnd,
touchMoveOpposite,sliderMove,click,tap,doubleTap,progress,reachBeginning,
beforeDestroy,reachEnd,setTransition,resize,setTranslate,
slideNextTransitionStart,slideNextTransitionEnd,slidePrevTransitionStart,
slidePrevTransitionEnd,fromEdge,toEdge,slideChange,autoplayStart,
autoplayStop,autoplay,beforeLoopFix,loopFix,observerUpdate,breakpoint
Copy the code
Develop a new component
Referring to Pagination, we hope to add a rotation button. When clicked, the current image can be rotated. The code structure is as follows, which is basically consistent with pagination.
Fourth, the ending
So far, the simple source code analysis is complete, the swiper source structure how to organize, code execution logic has a certain understanding of how to extend a component scheme, of course, there are a lot of details, you can go to read in detail.
Nanjing 300 Cloud Information Technology Co., LTD. (CHE 300) was founded on March 27, 2014. It is a mobile Internet enterprise rooted in Nanjing and currently located in Nanjing and Beijing. After 7 years of accumulation, the cumulative number of valuation has reached 5.2 billion times, and won the favor of many high-quality investment institutions at home and abroad, such as Sequoia Capital, SAIC Industry Fund. 300 Cloud is an outstanding domestic auto transaction and financial SaaS service provider with independent third party relying on artificial intelligence and standardization of auto transaction pricing and auto financial risk control as its core products.
Welcome to join 300 cloud, witness the booming development of the automobile industry together, look forward to walking with you hand in hand! Official website: www.sanbaiyun.com/ Resume: [email protected], please note from nuggets 😁