随着前端功能越来越复杂,前端代码日益膨胀,为了减少维护成本,提高代码的可复用性,前端模块化势在必行。
所有js文件都在一个html中引入,造成以下不良影响:
webpack中是这样定义的:
在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块。 每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。 精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。
模块应该是职责单一、相互独立、低耦合的、高度内聚且可替换的离散功能块。
模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职责单一,高度解耦且可替换的模块,系统中某一部分的变化将如何影响其它部分就会变得显而易见,系统的可维护性更加简单易得。
模块化是一种分治的思想,通过分解复杂系统为独立的模块实现细粒度的精细控制,对于复杂系统的维护和管理十分有益。模块化也是组件化的基石,是构成现在色彩斑斓的前端世界的前提条件。
前端开发和其他开发工作的主要区别,首先是前端是基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统。
function fn1(){
// ...
}
function fn2(){
// ...
}
通过 script 标签引入文件,调用相关的函数。这样需要手动去管理依赖顺序,容易造成命名冲突,污染全局,随着项目的复杂度增加维护成本也越来越高。
var output = {
_count: 0,
fn1: function(){
// ...
}
}
这样可以解决上面的全局污染的问题,有那么点命名空间的意思,但是随着项目复杂度增加需要越来越多的这样的对象需要维护,不说别的,取名字都是个问题。最关键的还是内部的属性还是可以被直接访问和修改。
var module = (function(){
var _count = 0;
var fn1 = function (){
// ...
}
var fn2 = function fn2(){
// ...
}
return {
fn1: fn1,
fn2: fn2
}
})()
module.fn1();
module._count; // undefined
这样就拥有独立的词法作用域,内存中只会存在一份 copy。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域,通过 return 暴露出公共接口供外界调用。这其实就是现代模块化实现的基础。
还有基于闭包实现的松耦合拓展、紧耦合拓展、继承、子模块、跨文件共享私有对象、基于 new 构造的各种方式,这种方式在现在看来都不再优雅。
// 松耦合拓展
// 这种方式使得可以在不同的文件中以相同结构共同实现一个功能块,且不用考虑在引入这些文件时候的顺序问题。
// 缺点是没办法重写你的一些属性或者函数,也不能在初始化的时候就是用module的属性。
var module = (function(my){
// ...
return my
})(module || {})
// 紧耦合拓展(没有传默认参数)
// 加载顺序不再自由,但是可以重载
var module = (function(my){
var old = my.someOldFunc
my.someOldFunc = function(){
// 重载方法,依然可通过old调用旧的方法...
}
return my
})(module)
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
目前实现模块化的规范主要有:
CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。
采用同步加载模块的方式,也就是说只有加载完成,才能执行后面的操作。CommonJS 代表:Node 应用中的模块,通俗的说就是你用 npm 安装的模块。
它使用 require 引用和加载模块,exports 定义和导出模块,module 标识模块。使用 require 时需要去读取并执行该文件,然后返回 exports 导出的内容。
//定义模块 math.js
var random=Math.random()*10;
function printRandom(){
console.log(random)
}
function printIntRandom(){
console.log(Math.floor(random))
}
//模块输出
module.exports={
printRandom:printRandom,
printIntRandom:printIntRandom
}
//加载模块 math.js
var math=require('math')
//调用模块提供的方法
math.printIntRandom()
math.printRandom()
|-js
|-dist //打包生成文件的目录
|-src //源码所在的目录
|-module1.js
|-module2.js
|-module3.js
|-app.js //应用主源文件
|-index.html //运行于浏览器上
|-package.json
{
"name": "browserify-test",
"version": "1.0.0"
}
注意:index.html文件要运行在浏览器上,需要借助browserify将app.js文件打包编译,如果直接在index.html引入app.js就会报错!
根目录下运行browserify js/src/app.js -o js/dist/bundle.js
在index.html文件中引入<script type="text/javascript" src="js/dist/bundle.js"></script>
异步模块定义,所谓异步是指模块和模块的依赖可以被异步加载,他们的加载不会影响它后面语句的运行。有效避免了采用同步加载方式中导致的页面假死现象。AMD代表:RequireJS。
AMD一开始是CommonJS规范中的一个草案,全称是Asynchronous Module Definition,即异步模块加载机制。后来由该草案的作者以RequireJS实现了AMD规范,所以一般说AMD也是指RequireJS。
RequireJS是一个工具库,主要用于客户端的模块管理。它的模块管理遵守AMD规范,RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。
它主要有两个接口:define 和 require。define 是模块开发者关注的方法,而 require 则是模块使用者关注的方法。
define(id?, dependencies?, factory);
//id :可选参数,它指的是模块的名字。
//dependencies:可选参数,定义中模块所依赖模块的数组。
//factory:模块初始化要执行的函数或对象
需要注意的是,dependencies有多少个元素,factory就有多少个传参,位置一一对应。 使用栗子:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
//return require("beta").verb();
}
});
require([module], callback);
//module:一个数组,里面的成员就是要加载的模块.
//callback:模块加载成功之后的回调函数。
需要注意的是 ,module 有多少个元素,callback 就有多少个传参,位置一一对应。
require(["a","b","c"],function(a,b,c){ //code here });
AMD 运行时核心思想是「Early Executing」,也就是提前执行依赖 AMD 的这个特性有好有坏:
然后将require.js导入项目: js/libs/require.js
|-js
|-libs
|-require.js
|-modules
|-alerter.js
|-dataService.js
|-main.js
|-index.html
// dataService.js文件
// 定义没有依赖的模块
define(function() {
let msg = 'www.baidu.com'
function getMsg() {
return msg.toUpperCase()
}
return { getMsg } // 暴露模块
});
//alerter.js文件
// 定义有依赖的模块
define(['dataService'], function(dataService) {
let name = 'Tom'
function showMsg() {
alert(dataService.getMsg() + ', ' + name)
}
// 暴露模块
return { showMsg }
});
// main.js文件
(function() {
require.config({
baseUrl: 'js/', //基本路径 出发点在根目录下
paths: {
//映射: 模块标识名: 路径
alerter: './modules/alerter', //此处不能写成alerter.js,会报错
dataService: './modules/dataService'
}
});
require(['alerter'], function(alerter) {
alerter.showMsg()
});
})();
// index.html文件
<!DOCTYPE html>
<html>
<head>
<title>Modular Demo</title>
</head>
<body>
<!-- 引入require.js并指定js主文件的入口 -->
<script data-main="js/main" src="js/libs/require.js"></script>
</body>
</html>
在index.html引入 <script data-main="js/main" src="js/libs/require.js"></script>
此外在项目中如何引入第三方库?只需在上面代码的基础稍作修改:
// alerter.js文件
define(['dataService', 'jquery'], function(dataService, $) {
let name = 'Tom'
function showMsg() {
alert(dataService.getMsg() + ', ' + name)
}
$('body').css('background', 'green')
// 暴露模块
return { showMsg }
});
// main.js文件
(function() {
require.config({
baseUrl: 'js/', //基本路径 出发点在根目录下
paths: {
//自定义模块
alerter: './modules/alerter', //此处不能写成alerter.js,会报错
dataService: './modules/dataService',
// 第三方库模块
jquery: './libs/jquery-1.10.1' //注意:写成jQuery会报错
}
})
require(['alerter'], function(alerter) {
alerter.showMsg()
})
})()
上例是在alerter.js文件中引入jQuery第三方库,main.js文件也要有相应的路径配置。 小结:通过两者的比较,可以得出AMD模块定义的方法非常清晰,不会污染全局环境,能够清楚地显示依赖关系。AMD模式可以用于浏览器环境,并且允许非同步加载模块,也可以根据需要动态加载模块。
CMD是SeaJS在推广过程中生产的对模块定义的规范,在Web浏览器端的模块加载器中,SeaJS与RequireJS并称,SeaJS作者为阿里的玉伯。
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD模块定义规范。
//定义没有依赖的模块
define(function(require, exports, module){
exports.xxx = value
module.exports = value
})
//定义有依赖的模块
define(function(require, exports, module){
//引入依赖模块(同步)
var module2 = require('./module2')
//引入依赖模块(异步)
require.async('./module3', function (m3) {
})
//暴露模块
exports.xxx = value
})
define(function (require) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
然后将sea.js导入项目: js/libs/sea.js
|-js
|-libs
|-sea.js
|-modules
|-module1.js
|-module2.js
|-module3.js
|-module4.js
|-main.js
|-index.html
// module1.js文件
define(function (require, exports, module) {
//内部变量数据
var data = 'atguigu.com'
//内部函数
function show() {
console.log('module1 show() ' + data)
}
//向外暴露
exports.show = show
});
// module2.js文件
define(function (require, exports, module) {
module.exports = {
msg: 'I Will Back'
}
});
// module3.js文件
define(function(require, exports, module) {
const API_KEY = 'abc123'
exports.API_KEY = API_KEY
});
// module4.js文件
define(function (require, exports, module) {
//引入依赖模块(同步)
var module2 = require('./module2')
function show() {
console.log('module4 show() ' + module2.msg)
}
exports.show = show
//引入依赖模块(异步)
require.async('./module3', function (m3) {
console.log('异步引入依赖模块3 ' + m3.API_KEY)
})
});
// main.js文件
define(function (require) {
var m1 = require('./module1')
var m4 = require('./module4')
m1.show()
m4.show()
})
<script type="text/javascript" src="js/libs/sea.js"></script>
<script type="text/javascript">
seajs.use('./js/modules/main')
</script>
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。所以说ES6是编译时加载,不同于CommonJS的运行时加载(实际加载的是一整个对象),ES6模块不是对象,而是通过export命令显式指定输出的代码,输入时也采用静态命令的形式。
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
严格模式主要有以下限制。
上面这些限制,模块都必须遵守。由于严格模式是 ES5 引入的,不属于 ES6,所以请参阅相关 ES5 书籍,本书不再详细介绍了。
其中,尤其需要注意this的限制。ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this。
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量。
function cUl(){
let ulEle = document.createElement("ul");
for(let i = 0; i < 5; i++){
let liEle = document.createElement("li");
liEle.innerHTML = "无序列表" + i;
ulEle.appendChild(liEle);
}
return ulEle;
}
let ul = cUl();
export {ul};
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
import {table} from "../test/test_table.js";
import {div} from "../test/test_div.js" ;
import {ul} from "../test/test_ul.js" ;
export {table, div, ul};
它们有两个重大差异:
1. CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
2. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
下面重点解释第一个差异,我们还是举上面那个CommonJS模块的加载机制例子:
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
ES6 模块的运行机制与 CommonJS 不一样。ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!
大家好,我是〖编程三昧〗的作者 隐逸王,我的公众号是『编程三昧』,欢迎关注,希望大家多多指教!
望收藏了我写的文章的你同时可以关注一下“小海前端”,因为这些文章都是连载的,并且是经过我系统的归纳过的。
【技术等级】初级
【承接文章】《CSS实现图片精灵,原来要这样使用背景属性,前端设计师必备知识》
本文小海老师为大家讲解利用CSS处理HTML中的列表,也就是CSS有关列表的属性。本文属于前端开发的初级教程,适合于刚刚开始接触CSS技术的学习者。
列表属性是指可以对HTML中的<ol></ol>标记对和<ul></ul>标记对进行样式设置的属性。这一组CSS属性包括以下三个:
list-style-type
list-style-image
list-style-position
一、设置列表的项目符号或编号:
CSS技术使用 list-style-type 设置列表的项目符号或编号
在HTML中,主要操作的列表有两种:
无序列表:用<ul></ul>标记对实现。无序列表项中左侧的标识我们把它称为“项目符号”。
有序列表:用<ol></ol>标记对实现。有序列表项中左侧的标识我们把它称为“编号”。
有序列表与无序列表
CSS技术利用 list-style-type 属性来设置HTML列表左侧标识的样式。并且在CSS看来,<ul></ul>和<ol></ol>两个标记对不再进行有序和无序的区分,使用list-style-type属性设置为哪个取值,就是对应的哪种列表。
该属性包括以下几种取值:
none,列表项无标记。
disc,默认值,标记为实心圆。
circle,标记为空心圆。
square,标记为实心方块。
decimal,标记为数字。
decimal-leading-zero,标记为0开头的数字(01、02、03 等)。
lower-roman,标记为小写罗马数字(i、ii、iii等)。
upper-roman,标记为大写罗马数字(I、II、III等)。
lower-alpha,标记为小写英文字母(a、b、c等)。
upper-alpha,标记为大写英文字母(A、B、C等)。
二、使用自定义图片来代替项目符号和编号:
CSS技术利用 list-style-image 属性来设置列表左侧的标识为指定的图片
CSS技术利用 list-style-image 属性来设置列表左侧的标识为指定的图片。
格式:list-style-image:url(Image_URL);
例如:ul{list-style-image:url(../images/01.jpg);}
三、设置列表中列表项的缩进:
CSS技术利用 list-style-position 属性来设置列表项的缩进
CSS技术利用 list-style-position 属性来设置列表项的缩进。
该属性包括以下两种取值:
loutside,默认值,列表项不缩进。
linside,列表项缩进。
这个属性使用在列表项<li></li>标记对上的,不能用在<ol></ol>或<ul></ul>之上。
下一篇文章中,小海老师会继续为大家向下讲解CSS属性,下一次我们讲解CSS中最为重要的一组属性:定位属性。这是CSS中非常常用的一组属性,希望大家千万不要错过!
如果大家希望得到更加全面的关于HTML和CSS技术讲解的内容,可以私信我,我会免费将小海老师自己编写的HTML和CSS的PDF教材发给你,帮助你在前端开发的道路上阔步前行。
在头条上发表的这些文章都是从前端开发的基础开始一步一步讲起的。我非常希望能有更多的前端开发初学者通过我写的文章,逐步学到一定的知识,甚至慢慢有了入门的感觉。这些文章都是我这几年教学过程中的经验,每写一篇时我都尽量把握好措辞,用简单易懂的语言描述,同时精心设计版面,让版面更加丰富,激发阅读兴趣。所以,每一篇文章可能篇幅不长,但是都要耗费小海老师很久的时间。
希望收藏了我写的文章的你同时可以关注一下“小海前端”,因为这些文章都是连载的,并且是经过我系统的归纳过的。
关注“小海前端”,我会继续为大家奉上更加深入的前端开发文章,也希望更多的初学者跟着学下去,我们共同将前端开发的路努力坚持的走下去。
、跳出新页面:
<basetarget=”_blank”>target="_self"不跳转
<form action="xxx.htm" target="_blank">form表单提交的跳转设置
2、点击按钮跳出别的页面添加
<a href="#" onclick="openZoosUrl();return false;">
onclick="return false"
3、display:block;块级元素,也就是说它可以设置一些宽高,独占一行,比如,div元素,p元素等display:inline-block,行级元素,也就说它可以使得同样设置成行级元素的元素一起在一行,然后可以设置宽高,这个适应于制作一个导航菜单,将每个菜单项设置成行级元素。它的宽和高默认是内容的宽和高,典型的元素是表单类的元素。dispaly:inline.行级元素,不可设置宽和高,默认宽高是内容的宽和高,典型的比如,span,
4、html鼠标小手:
cursor:pointer;
5、html背景图属性:
background-size:100%;,但是你的图片宽度,高度要设置成100% ,要注意的是.php的文件里面这个background-image:url();不好用,失效,你要使用网站的绝对路径background:url('/20151106/404/image/404.png') no-repeat 4px 5px;}background:url("11111.jpg");background-repeat:no-repeat;background-size:100%;width:100%;height:100%;
这个是给页面加背景的body{padding: 0px;margin: 0px;background-color:#494949;width:100%;height:100%;}.
还有在设置背景图片的时候可以使用背景background-image:url("");这个属性来设置背景,但是图片要用gif的格式
6、按输出方式来显示文本格式:<pre></pre>横线:<hr /><q></q>双引号标签下划线<ins></ins>
7、html---position/relative/absolute/fixed/三种布局定位方式的总结relative是按照自身来说,absolute是按照浏览器来说,但是要注意的是,如果他有父级元素的话,那么他就是依照父级元素来进行改变位置的。
8、无序列表去掉前面黑点li{list-style:none;}
9、隐藏元素 - display:none或visibility:hidden
display-这个元素,设置之后原本的元素不会占用当前的空间,不会影响布局,但是后者,隐藏之后还会占用空间
10、HTML隐藏多余
Div{overflow:hidden}
10、隐藏自适应:overflow:auto;
11、关于框架的问题
这个是接受你要显示页面
indx.php是框架显示的页面,最上面,也就是没按键显示
<iframe src="index.php" style="width:100%;height:100%;border:none " name="main"></iframe>
这个是你点击之后想在哪显示后面加:target=""
<a href='../admin/shopclass/add.php' target="main">添加分类</a>
12、关于背景的高的问题,也就是说你定义了一个div但是没有搞,是为了让你的图片在上面。那么就有这个属性了
overflow:hidden;
也就是你本身是属于父级元素的,但是你float就脱离了文本,变成浮动的,所有就不会在用父子元素的空间,所以就父级加上这个overflow:hidden;
13、锚点的设置
在你想跳转的页面的地方加上:<a name="miao">
然后在你想加链接的地方加上<a href="#miao">去找锚点</a>
14.点击换验证码图片
<img src="../public/common/yzm.php" alt="" style="cursor:pointer" onclick="this.src='../public/common/yzm.php?rand='+Math.random()">
15、圆角
border-radius:5px;
16、textarea的左侧文字在最左边
style="vertical-align:top"
17、html块状元素和内联元素的总结,块状元素可以设置margin,但是使用margin的时候要符合:1.块状元素,2.有宽高,其中内联元素不能设置margin和宽高的属性,只能设置padding
*请认真填写需求信息,我们会在24小时内与您取得联系。