
暂无个人介绍
简言 CSS居中是前端工程师经常要面对的问题,也是基本技能之一。今天有时间把CSS居中的方案汇编整理了一下,目前包括水平居中,垂直居中及水平垂直居中方案共15种。如有漏掉的,还会陆续的补充进来,算做是一个备忘录吧。 1 水平居中 1.1 内联元素水平居中 利用 text-align: center 可以实现在块级元素内部的内联元素水平居中。此方法对内联元素(inline), 内联块(inline-block), 内联表(inline-table), inline-flex元素水平居中都有效。 ** 核心代码:** .center-text { text-align: center; } ** 演示程序:** 演示代码 1.2 块级元素水平居中 通过把固定宽度块级元素的margin-left和margin-right设成auto,就可以使块级元素水平居中。 ** 核心代码:** .center-block { margin: 0 auto; } ** 演示程序:** 演示代码 1.3 多块级元素水平居中 1.3.1 利用inline-block 如果一行中有两个或两个以上的块级元素,通过设置块级元素的显示类型为inline-block和父容器的text-align属性从而使多块级元素水平居中。 ** 核心代码:** .container { text-align: center; } .inline-block { display: inline-block; } ** 演示程序:** 演示代码 1.3.2 利用display: flex 利用弹性布局(flex),实现水平居中,其中justify-content 用于设置弹性盒子元素在主轴(横轴)方向上的对齐方式,本例中设置子元素水平居中显示。 ** 核心代码:** .flex-center { display: flex; justify-content: center; } ** 演示程序:** 演示代码 2 垂直居中 2.1 单行内联(inline-)元素垂直居中 通过设置内联元素的高度(height)和行高(line-height)相等,从而使元素垂直居中。 ** 核心代码:** #v-box { height: 120px; line-height: 120px; } ** 演示程序:** 演示代码 2.2 多行元素垂直居中 2.2.1 利用表布局(table) 利用表布局的vertical-align: middle可以实现子元素的垂直居中。 ** 核心代码:** .center-table { display: table; } .v-cell { display: table-cell; vertical-align: middle; } ** 演示程序:** 演示代码 2.2.2 利用flex布局(flex) 利用flex布局实现垂直居中,其中flex-direction: column定义主轴方向为纵向。因为flex布局是CSS3中定义,在较老的浏览器存在兼容性问题。 ** 核心代码:** .center-flex { display: flex; flex-direction: column; justify-content: center; } ** 演示程序:** 演示代码 2.2.3 利用“精灵元素” 利用“精灵元素”(ghost element)技术实现垂直居中,即在父容器内放一个100%高度的伪元素,让文本和伪元素垂直对齐,从而达到垂直居中的目的。 ** 核心代码:** .ghost-center { position: relative; } .ghost-center::before { content: " "; display: inline-block; height: 100%; width: 1%; vertical-align: middle; } .ghost-center p { display: inline-block; vertical-align: middle; width: 20rem; } ** 演示程序:** 演示代码 2.3 块级元素垂直居中 2.3.1 固定高度的块级元素 我们知道居中元素的高度和宽度,垂直居中问题就很简单。通过绝对定位元素距离顶部50%,并设置margin-top向上偏移元素高度的一半,就可以实现垂直居中了。 ** 核心代码:** .parent { position: relative; } .child { position: absolute; top: 50%; height: 100px; margin-top: -50px; } ** 演示程序:** 演示代码 2.3.2 未知高度的块级元素 当垂直居中的元素的高度和宽度未知时,我们可以借助CSS3中的transform属性向Y轴反向偏移50%的方法实现垂直居中。但是部分浏览器存在兼容性的问题。 ** 核心代码:** .parent { position: relative; } .child { position: absolute; top: 50%; transform: translateY(-50%); } ** 演示程序:** 演示代码 3 水平垂直居中 3.1 固定宽高元素水平垂直居中 通过margin平移元素整体宽度的一半,使元素水平垂直居中。 ** 核心代码:** .parent { position: relative; } .child { width: 300px; height: 100px; padding: 20px; position: absolute; top: 50%; left: 50%; margin: -70px 0 0 -170px; } ** 演示程序:** 演示代码 3.2 未知宽高元素水平垂直居中 利用2D变换,在水平和垂直两个方向都向反向平移宽高的一半,从而使元素水平垂直居中。 ** 核心代码:** .parent { position: relative; } .child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } ** 演示程序:** 演示代码 3.3 利用flex布局 利用flex布局,其中justify-content 用于设置或检索弹性盒子元素在主轴(横轴)方向上的对齐方式;而align-items属性定义flex子项在flex容器的当前行的侧轴(纵轴)方向上的对齐方式。 ** 核心代码:** .parent { display: flex; justify-content: center; align-items: center; } ** 演示程序:** 演示代码 3.4 利用grid布局 利用grid实现水平垂直居中,兼容性较差,不推荐。 ** 核心代码:** .parent { height: 140px; display: grid; } .child { margin: auto; } ** 演示程序:** 演示代码 3.5 屏幕上水平垂直居中 屏幕上水平垂直居中十分常用,常规的登录及注册页面都需要用到。要保证较好的兼容性,还需要用到表布局。 ** 核心代码:** .outer { display: table; position: absolute; height: 100%; width: 100%; } .middle { display: table-cell; vertical-align: middle; } .inner { margin-left: auto; margin-right: auto; width: 400px; } ** 演示程序:** 演示代码 4 说明 文中所述文字及代码部分汇编于网络。因时间不足,能力有限等原因,存在文字阐述不准及代码测试不足等诸多问题。因此只限于学习范围,不适用于实际应用。 文中所述方案只是居中方案其中的一部分,并不是全部。另代码中涉及CSS3的flex,transform,grid等内容都存在兼容性问题。 原文发布时间为:2018年03月25日 原文作者:毛三十 本文来源前端乱炖如需转载请联系原作者
Java 8 发布三年多之后,即将快到2017年7月下一个版本发布的日期了。 你可能已经听说过 Java 9 的模块系统,但是这个新版本还有许多其它的更新。 这里有九个令人兴奋的新功能将与 Java 9 一起发布。 Java 平台级模块系统 Java 9 的定义功能是一套全新的模块系统。当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的增长。这时候就得面对两个基础的问题: 很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到, 这样就会导致无意中使用了并不想被公开访问的 API。此外,类路径本身也存在问题: 你怎么知晓所有需要的 JAR 都已经有了, 或者是不是会有重复的项呢? 模块系统把这俩个问题都给解决了。 模块化的 JAR 文件都包含一个额外的模块描述器。在这个模块描述器中, 对其它模块的依赖是通过 “ requires” 来表示的。另外, “ exports” 语句控制着哪些包是可以被其它模块访问到的。所有不被导出的包默认都封装在模块的里面。如下是一个模块描述器的示例,存在于 “module-info.java” 文件中: module blog {我们可以如下展示模块: 32130002475b31336ae7 请注意,两个模块都包含封装的包,因为它们没有被导出(使用橙色盾牌可视化)。 没有人会偶然地使用来自这些包中的类。Java 平台本身也使用自己的模块系统进行了模块化。通过封装 JDK 的内部类,平台更安全,持续改进也更容易。 当启动一个模块化应用时, JVM 会验证是否所有的模块都能使用,这基于 requires 语句——比脆弱的类路径迈进了一大步。模块允许你更好地强制结构化封装你的应用并明确依赖。你可以在这个 课程 中学习更多关于 Java 9 中模块工作的信息 。 如果你想学习Java可以来这个群,首先是二二零,中间是一四二,最后是九零六,里面可以学习和交流,也有资料可以下载。 Linking 当你使用具有显式依赖关系的模块和模块化的 JDK 时,新的可能性出现了。你的应用程序模块现在将声明其对其他应用程序模块的依赖以及对其所使用的 JDK 模块的依赖。为什么不使用这些信息创建一个最小的运行时环境,其中只包含运行应用程序所需的那些模块呢? 这可以通过 Java 9 中的新的 jlink 工具实现。你可以创建针对应用程序进行优化的最小运行时映像而不需要使用完全加载 JDK 安装版本。 JShell: 交互式 Java REPL 许多语言已经具有交互式编程环境,Java 现在加入了这个俱乐部。您可以从控制台启动 jshell ,并直接启动输入和执行 Java 代码。 jshell 的即时反馈使它成为探索 API 和尝试语言特性的好工具。 322d0003e3f6c42e3137 测试一个 Java 正则表达式是一个很好的说明 jshell 如何使您的生活更轻松的例子。 交互式 shell 还可以提供良好的教学环境以及提高生产力,您可以 在此 了解更多信息。在教人们如何编写 Java 的过程中,不再需要解释 “public static void main(String [] args)” 这句废话。 改进的 Javadoc 有时一些小事情可以带来很大的不同。你是否就像我一样在一直使用 Google 来查找正确的 Javadoc 页面呢? 这不再需要了。Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。此外,你会注意到,每个 Javadoc 页面都包含有关 JDK 模块类或接口来源的信息。 321000048ba2cfe25db6 集合工厂方法 通常,您希望在代码中创建一个集合(例如,List 或 Set ),并直接用一些元素填充它。 实例化集合,几个 “add” 调用,使得代码重复。 Java 9,添加了几种集合工厂方法: Set ints = Set.of(1, 2, 3);除了更短和更好阅读之外,这些方法也可以避免您选择特定的集合实现。 事实上,从工厂方法返回已放入数个元素的集合实现是高度优化的。这是可能的,因为它们是不可变的:在创建后,继续添加元素到这些集合会导致 “UnsupportedOperationException” 。 改进的 Stream API 长期以来,Stream API 都是 Java 标准库最好的改进之一。通过这套 API 可以在集合上建立用于转换的申明管道。在 Java 9 中它会变得更好。Stream 接口中添加了 4 个新的方法: dropWhile, takeWhile, ofNullable 。还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代: IntStream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);第二个参数是一个 Lambda,它会在当前 IntStream 中的元素到达 100 的时候返回 true。因此这个简单的示例是向控制台打印 1 到 99。 除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。现在可以通过 Optional 的新方法 stram 将一个 Optional 对象转换为一个(可能是空的) Stream 对象: Stream s = Optional.of(1).stream();在组合复杂的 Stream 管道时,将 Optional 转换为 Stream 非常有用。 私有接口方法 Java 8 为我们带来了接口的默认方法。 接口现在也可以包含行为,而不仅仅是方法签名。 但是,如果在接口上有几个默认方法,代码几乎相同,会发生什么情况? 通常,您将重构这些方法,调用一个可复用的私有方法。 但默认方法不能是私有的。 将复用代码创建为一个默认方法不是一个解决方案,因为该辅助方法会成为公共API的一部分。 使用 Java 9,您可以向接口添加私有辅助方法来解决此问题: public interface MyInterface { void normalInterfaceMethod(); default void interfaceMethodWithDefault() { init(); } default void anotherDefaultMethod() { init(); } // This method is not part of the public API exposed by MyInterface如果您使用默认方法开发 API ,那么私有接口方法可能有助于构建其实现。 HTTP/2 Java 9 中有新的方式来处理 HTTP 调用。这个迟到的特性用于代替老旧的 HttpURLConnection API,并提供对 WebSocket 和 HTTP/2 的支持。注意:新的 HttpClient API 在 Java 9 中以所谓的孵化器模块 交付。也就是说,这套 API 不能保证 100% 完成。不过你可以在 Java 9 中开始使用这套 API: HttpClient client = HttpClient.newHttpClient();除了这个简单的请求/响应模型之外,HttpClient 还提供了新的 API 来处理 HTTP/2 的特性,比如流和服务端推送。
一. 什么是Code Splitting? 在最开始使用Webpack的时候, 都是将所有的js文件全部打包到一个build.js文件中(文件名取决与在webpack.config.js文件中output.filename), 但是在大型项目中, build.js可能过大, 导致页面加载时间过长. 这个时候就需要code splitting, code splitting就是将文件分割成块(chunk), 我们可以定义一些分割点(split point), 根据这些分割点对文件进行分块, 并实现按需加载. 二. Code Splitting的作用? 第三方类库单独打包: 由于第三方类库的内容基本不会改变, 可以将其与业务代码分离出来, 这样就可以最大化的利用浏览器的缓存机制, 减少请求. 按需加载: Webpack支持定义分割点, 通过require.ensure进行按需加载. 三. 如何进行Code Splitting? 下面的代码是基于vue-cli的webpack-simple模板生成的演示文档 //cmd vue init webpack-simple code_spliting_demo 复制代码 (一) 第三方类库单独打包 我们假设项目中引入了jquery.js和respond.js, 那么我们可以在webpack.config.js中配置多入口来进行将这两个第三方类库单独打包. 在webpack.config.js进行配置 //webpack.config.js //在entry中添加相应第三方类库 entry: { bundle: './src/main.js', vendor: ['./src/lib/jquery-1.10.2.min.js', './src/lib/respond.min.js'] } //在plugins中添加CommonChunkPlugin plugins:[ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' }) ] 复制代码 执行npm run build, 此时dist目录下生成了两个文件, 分别是build.js和vendor.bundle.js npm run build后的生成文件 在index.html中引入, 注意: vendor.bundle.js优先于build.js引入 //index.html <script src="/dist/vendor.bundle.js"></script> <script src="/dist/build.js"></script> 复制代码 (二) 按需加载 我们可以在router中进行配置, 实现组件的按需加载, 在一些单个组件文件较大的时候, 采用按需加载能够减少build.js的体积, 优化加载速度(如果组件的体积较小, 那么采用按需加载会增加额外的http请求, 反倒增加了加载时间) 这里, 我们增加3个组件,分别是A.vue, B.vue, C.vue //A.vue <template> <h1>这里是A.vue组件</h1> </template> //B.vue <template> <h1>这里是B.vue组件</h1> </template> //C.vue <template> <h1>这里是C.vue组件</h1> </template> 复制代码 在路由中进行配置 (注意:这里是为了方便, 是在app.js中添加的路由, 在实际的项目中, 路由应该单独抽取出来) //app.js import Vue from 'vue' import App from './App.vue' import VueRouter from 'vue-router' Vue.use(VueRouter) //AMD规范的异步载入 const ComA = resolve => require(['./components/A.vue' ], resolve); const ComB = resolve => require(['./components/B.vue' ], resolve); const ComC = resolve => require(['./components/C.vue' ], resolve); const router = new VueRouter({ routes: [ { name: 'component-A', path: '/a', component: ComA }, { name: 'component-B', path: '/b', component: ComB }, { name: 'component-C', path: '/c', component: ComC } ] }) new Vue({ el: '#app', router: router, render: h => h(App) }) 复制代码 在webpack.config.js中进行配置output.chunkFilename, //webpack.config.js output: { path: path.resolve(__dirname, './dist'), publicPath: '/dist/', filename: 'build.js', //添加chundkFilename chunkFilename: '[name].[chunkhash:5].chunk.js' } 复制代码 执行npm run build, 此时dist目录下生成了5个文件, 多出的3个文件,就是对应的A.vue, B.vue, C.vue这三个组件 npm run build后生成的文件 CMD规范的异步载入 刚才在路由引入的时候, 使用的是AMD规范的异步载入. webpack提供了require.ensure()这个方法实现CMD规范的异步载入. 这同样也是webpack推荐的载入方式.想深入了解ensure, 请点击《webpack代码分离 ensure 看了还不懂,你打我》 下面的代码是使用require.ensure()方法对路由进行配置 //app.js import Vue from 'vue' import App from './App.vue' import VueRouter from 'vue-router' Vue.use(VueRouter) //AMD风格的异步加载 // const ComA = resolve => require(['./components/A.vue' ], resolve); // const ComB = resolve => require(['./components/B.vue' ], resolve); // const ComC = resolve => require(['./components/C.vue' ], resolve); //CMD风格的异步加载 const ComA = resolve => require.ensure([], () => resolve(require('./components/A.vue'))); const ComB = resolve => require.ensure([], () => resolve(require('./components/B.vue'))); const ComC = resolve => require.ensure([], () => resolve(require('./components/C.vue'))); const router = new VueRouter({ routes: [ { name: 'component-A', path: '/a', component: ComA }, { name: 'component-B', path: '/b', component: ComB }, { name: 'component-C', path: '/c', component: ComC } ] }) new Vue({ el: '#app', router: router, render: h => h(App) }) 复制代码 执行npm run build后, dist目录下同样生成5个文件 npm run build后生成的文件 按需加载效果演示: 按需加载效果演示 Lee_tanghui 发布在 https://www.jianshu.com/p/b3b8fb8a2336 原文发布时间为:2018年06月26日 原文作者:zhaiyy 本文来源掘金如需转载请联系原作者
前端想要写 APP 开篇想以这样的方式开头,从 APP 开始火到现在,前端同学就一直想要写 APP,各方技术也是为了让前端同学写上 APP 操碎了心。 为什么要前端同学来写 APP,站在整个技术链上来看,都是在做页面呈现,页面交互,对于技术而言只是将产品在不同的端上进行呈现,所以很早之前就有提倡说大前端的概念。既然功能都差不多,就没有分家的理由。 再者,开发客户端现在的常规平台有 iOS 和 android 两个大的平台,在前端领域越来越细分的大环境下,传统意义上的客户端开发至少需要两拨开发者来做,成本就会有增加。并且伴随着成本增加还带来了需要两套体系化的语言开发,开发效率也会大打折扣。相较于两大客户端平台的开发人员,前端的开发人员是要更多的,并且随着移动端的兴起前端开发者会有资源剩余的情况,前端来写 APP 也可以平衡资源。 所以不仅仅是前端同学想要来写 APP,更多的是未来发展需要这样的技术来提高生产力,所以才会有各种各样的方案出现,各种方案的诞生也发现了前端写 APP 的不足,所以又有了不断的演进来适应未来发展。送给每一个前端人,我们的征途是星辰大海 web APP 就是我们常说的 h5 应用,这个阶段属于满足展示功能阶段,首先是解决手机端能展示页面的问题。 实现方式就是客户端提供 webView 组件,就是一个基于 webkit 引擎、展现 web 页面的控件。web APP 实际上就是客户端提供了一个浏览器的宿主环境,能在手机上显示对应的网页内容,但是各大手机厂商对于内核都会有所谓的“优化”,这些所谓的优化或者内核版本升级所带来的兼容性问题,也是让前端同学咬牙切齿。 客户端提供了类似浏览器的宿主环境,前端将自己的 HTML/CSS/JS 运行起来,就可以看到页面了。但是在 PC 端原来我们看到的页面放在手机上,展示和交互都不太合适。之所以我们要叫 h5 应用,是说我们在移动端上需要用到 HTML5/CSS3 的新功能,通过这些功能能在客户端的浏览器上做适配展示页面。 响应式的布局方式,新式的 meta 标签,媒体查询等功能让前端以前显示在 PC 端上的页面能展示在手机端。随着 PWA 的出现,现在手机端逐渐对 Service Worker 的支持(Safari 还在踌躇犹豫),web APP 又重新焕发了青春。 优点: 基于 webView 的跨平台,调试方便(控制台调试) 开发速度快,只要有浏览器就能打开,适合小版本的试错 无需安装,不占内存,随时更新,维护成本低 缺点: 打开白屏时间长,用户体验较差,交互功能受限。 产品也受限于浏览器,并且留存低,适合拉新 不采用 PWA 的方案就无法离线,没有网络就失去了活力,现在不用网络的 APP 情况已经很少了。重复打开重复加载 代表产品: 所有可以使用手机浏览器打开的网页(不做兼容展示会有问题) 微信公众号里纯文章 hybrid 应用 跨过了 web APP 的满足展示功能阶段,这个时候开始想有更多的功能满足交互需求,比如调起原生的摄像头(虽然 input 也可以实现),这个时候催生了 hybrid APP,也进入了丰富功能阶段。 前端 webView 的交互实现无法直接与摄像头的 API 进行交互,类似这样的功能是客户端的能力,webView 想要完成这样的功能,如果不能直接完成是不是可以通过调用客户端来完成这样的功能,但是前端和客户端是两种不同的语言及实现方式,如何进行通信? 想要通信完成通信,其实就是需要再前端与和客户端搭建一个沟通桥梁,就是现在常说的 js bridge。介绍击中常见的 js bridge 通信方式。 js bridge js 调用 native: 请求拦截 弹窗拦截 注入 js 方法 native 调用 js: 直接执行 js 代码 请求拦截 webView 发送请求都会经过客户端的请求发送模块,客户端可以在请求发送出去之前做拦截,大家约定好一种 URI 的实现协议,如果符合实现协议的请求,就拦截下来进行约定协议解析,其他的就当做真正的请求发送出去。 首先约定一个简单的协议 eros://bmImage/camera?params={"imageNum":2,"allowCrop":true,"callbackId":"bmImage.camera1527235458519"} eros // 作为协议存在,用于做拦截的方式 bmImage/camera // 用于约定是调用客户端的方法名,可以是想要调用相机上传两种图片的接口 params // query 表示参数,其中有一个参数名叫 params 的参数是一个 json,是调用客户端的方法所需要的三个参数 复制代码 不管 js 如何封装,就是需要发送一个请求出去,最好前端能做统一封装通过 iframe 或者直接通过 ajax 发送请求。 客户端如何拦截 android 的拦截方式 shouldOverrideUrlLoading @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 根据协议判断是否需要拦截 if (true){ // 解析协议路径得知调用方法 // 解析 query 得到参数 // 通过反射的方式去调用对应的原生方法 return true; } return super.shouldOverrideUrlLoading(view, url); } 复制代码 iOS 的拦截方式(UIWebView) webView:shouldStartLoadWithRequest:navigationType: - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // 根据协议判断是否需要拦截 if (true){ // 解析协议路径得知调用方法 // 解析 query 得到参数 // 通过 AOP 的方式去调用去调用对应的原生方法 return NO; } return YES; } 复制代码 上述过程就完成了 js 向 native 的通信的一种方式,客户端完成了操作之后如何告知 js 后面会讲到。这种方式不好的地方在于只能支持异步的调用方式,网络 I/O 就决定了这种方式不支持同步。既然是 URI 的协议就会有长度限制,超长了请求就会被截断 更为严重的是无序性和有丢消息的可能,这也导致了这个方式非常不稳定,也是早期没有其他选择使用的方式。 弹窗拦截 js 调用弹窗时一般有 alert/confirm/prompt 三种弹窗,这三种弹窗对应客户端都会有方法实现,可以直接做拦截。 var actionInfo = { type: 'eros', action: 'bmImage/camera', params:{ "imageNum":2, "allowCrop":true, "callbackId":"bmImage.camera1527235458519" } } prompt(JSON.stringify([actionInfo])) 复制代码 android 拦截 prompt @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { // 解析传过来的字符串判断 type 类型是不是解析的方式 if (true){ // 解析协议路径得知调用方法 // 解析 query 得到参数 // 通过 AOP 的方式去调用去调用对应的原生方法 // 如果是异步返回 return true; // 如果是同步,待上面的程序执行完毕之后返回结果 // return res } return super.onJsPrompt(view, url, message, defaultValue, result); } 复制代码 iOS 拦截 prompt(使用 WKWebView) - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{ // 解析传过来的字符串判断 type 类型是不是解析的方式 if (true){ // 解析协议路径得知调用方法 // 解析 query 得到参数 // 通过 AOP 的方式去调用去调用对应的原生方法 // 如果是异步返回 NSInvocation *invocation = [执行方法] [invocation invoke]; return invocation; // 如果是同步,待上面的程序执行完毕之后返回结果 return nil }else{ 执行对应的弹窗 } } 复制代码 这种方式比请求拦截好的地方是可以支持同步调用了。但是 iOS 中有两种 UIWebView 和 WKWebView,前者在 webView 中屏蔽的弹窗的功能。后者虽然内存要比前者控制的好但是有很多兼容性的问题。 js 注入上下文 上面的使用方式还是比较曲折,发展到现在有了 JavaScriptCore,也是现在大部分混合应用解决方案核心,JavaScriptCore 没有 BOM 对象也没有 DOM 对象,甚至还缺失一些浏览器的方法,但是这块是 js 和 native 都能访问到的公共区域。在打开 webView 之后,往 js 的上下文中注入方法,供 js 进行调用。 iOS JavaScriptCore 注入(UIWebView) // 获取 WebView 中 JS上下文 JSContext *context = [webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; //注入 callNative 函数方法 context[@"callNative"] = ^( JSValue * params ) { // 解析参数找到对应的方法进行处理 // 同步回调 NSInvocation *invocation = [执行方法] [invocation invoke]; return invocation; // 异步回调 return nil } 复制代码 js 调用方式 callNative({ action: 'bmImage/camera', params:{ "imageNum":2, "allowCrop":true, "callbackId":"bmImage.camera1527235458519" } }); 复制代码 android webView 注入 // 通过 addJavascriptInterface 将对象映射到 JS 对象 // android 对象 // js 的对象名 mWebView.addJavascriptInterface(new JavaScriptBridge(), "callNative"); 复制代码 js 调用方式 callNative.bmImage.camera({ "imageNum":2, "allowCrop":true, "callbackId":"bmImage.camera1527235458519" }) 复制代码 这种方式就更接近写代码的方式了,不管是调用方式、传递参数的方式还是同步异步回调都更好了。但是这种方式也有需要注意的地方,首先需要注意客户端注入的时机,在 loadUrl 之前注入是无效的,但是在 FinishLoad 之后注入可能 webView 已经调用了方法,此时会出现调用不到该方法,所以还需要其他的机制来保证这个问题。比如微信公众号的 wx.config 接口。 native 调用 js 前面已经讲了 js 调用 客户端,js 在向客户端发出调用指令之后,如果是同步方法,比如 获取当前客户端版本能立即得到结果,如果是异步调用,之前每次调用客户端的时候都传递了一个 callbackId,这个就是为客户端回调 js 做准备。 首先 js 会提供一个方法等待客户端调用 window.nativeCallbackMap = {}; const callJs = (data) => { var data = JSON.parse(data); var callback = window.nativeCallbackMap[data['callbackId'] if(callback){ callback.call(null, data['resData']) } delete window.nativeCallbackMap[data['callbackId'] } 复制代码 iOS 调用 js NSString *resDataString = [self _serializeMessageData:data]; NSString* javascriptCommand = [NSString stringWithFormat:@"callJs('%@');", resDataString]; if ([[NSThread currentThread] isMainThread]) { [self.webView evaluateJavaScript:javascriptCommand completionHandler:nil]; } else { __strong typeof(self)strongSelf = self; dispatch_sync(dispatch_get_main_queue(), ^{ [strongSelf.webView evaluateJavaScript:javascriptCommand completionHandler:nil]; }); } 复制代码 android 调用 js final int version = Build.VERSION.SDK_INT; // 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断 if (version < 18) { mWebView.loadUrl("javascript:callJs()"); } else { mWebView.evaluateJavascript("javascript:callJs()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { // js 的同步返回 } }); } 复制代码 上述 js bridge 的实现大致就是现在大部分的客户端与 js 的通信方式,现在 webView 也丰富了自己的功能,有能力调用客户端提供的方法,完成所有客户端能做的功能,js bridge 设计完之后剩下的就是需求推动,根据所需的功能提供不同的方法供前端调用。 如果需要与原生页面间互相通信,应该约定一种 scheme,也可以理解成一种 URI 的实现,通过 js bridge 的接口调用客户端(此时还可以传一个回调到客户端,当客户端完成某个操作之后返回该页面执行回调,比如日期选择),客户端解析协议,打开对应的原生页面,完成对应的操作。scheme 还是手机浏览器会识别的一种协议,如果有对应的 APP 可以直接呼起 APP,但是当你打开客户端页面的参数太多时,你的 scheme 会变得超长,浏览器会将 URL 截断,这个时候还需要简单的短链服务转化 优点: 首先具有所有 webView 所有的优点 解决了单纯 webView 的交互功能受限,能调用原生接口完成需求 缺点 也无法避免 webView 所带来的性能问题,打开白屏时间长,用户体验较差,等问题,也存在受限与浏览器,及重复打开需要重复加载等问题 所有新需要客户端提供的功能都需要客户端发版 随着业务发展客户端定义的接口必须向下兼容,这会带来很多冗余代码 代表产品: 公众号使用到微信 sdk 的功能 AppCan、PhoneGap、cordova 等 hybrid 框架 小程序 在 hybrid 混合应用稳定之后,大家发现功能上已经能满足开发需求了,所以下个阶段应该追求体验和性能上的提升,就是 RN 的方案了,ReactNative 的方案已经逐渐被大家所熟知并逐步落到项目中,混合应用方案也是本文介绍的重点,后面会详述。 这里想先讲一讲小程序,因为在技术的演进上小程序才应该是下一小步的提升,并且小程序严格意义上来说并非 APP 的一种方案,更像是微信分发生态中的体验进化,在使用公众号这类 hybrid 的方案时,发现体验和交互上的一些问题,比如加载白屏时间,页面之间跳转的交互,页面内容的缓存等等。 由于小程序现在实现方案面向开发者也是一个黑盒,我也是一边了解一边猜小程序如何实现的,小程序的框架包含两部分:View 视图层和 APP service。前者用来渲染页面结构,后者用来做逻辑处理,接口调用。他们在两个进程里运行,有点类似在当前的页面里使用 web worker,关系如下图: APP View 我们写的视图层和逻辑代码是分离的,WXML 和 WXSS 构图了视图层的代码,WXML 通过 wcc 工具转换成 VDOM,WXSS 通过 wxsc 转化 style 标签。底层通过 WAWebview.js 来提供底层的封装,每一个视图就会有一个 webView 来渲染,这也就提高了页面渲染性能的问题,多个视图页面时就会有多个 webView 进程,所以小程序对页面层级是有限制的,内存受限。视图层主要包括以下内容: WeixinJSBridge 封装和上述的 hybrid 的 jsBridge 一样 小程序提供的组件注册,一些能操作 DOM 的 API 渲染的实现:VDOM、diff、render UI(在高人知道下了解到渲染出来的本质还是 webview,在原生端只支持 flex 布局,但是小程序里还支持 web 的布局,由此可以看出,这里一定是 webView 的渲染,并非原生) 页面生命周期管理 APP Service 逻辑处理的代码全部加载到一个进程 APP service 中,和视图 webView 不同,所有的代码逻辑都会一次性全部加载到这个进程中,因为主要的瓶颈还是来自于渲染性能,并且所有的逻辑代码都加载到进程中保证视图切换的流程性,并且加上小程序有 2MB 大小的限制,在现在的网络环境下一次加载体验会更好。APP Service 包含以下内容: WeixinJSBridge 封装和上述的 hybrid 的 jsBridge 一样 所有小程序提供的 API 方法注入,全局方法注入 AMD 模块化实现 小程序的开发环境 小程序运行在开发环境中和线上环境是不同的,线上环境 iOS 和 android 都有真正的 webView 环境提供,在开发过程中小程序提供了一个 IDE,IDE 是基于 nwjs 实现的,钉钉客户端也是基于这个实现的。其实就是在 PC 端的客户端环境下尽可能提供原生能力,如果是移动端才会有的差异化能力就会 mock 掉。两边环境不同还体现在 APP Service 中,APP Service 主要是调用客户端底层,所以底层的不同也影响着这层的封装。 APP View 与 APP service 通信 当我们理解了前面的 hybrid 的通信原理,这里的通信就比较好理解了。小程序的 bridge 实现原理就和 hybrid 一样了。iOS 和 android 就不多说了。基于 nwjs 的客户端是通过 window.postMessage 实现的,使用 chrome 扩展的接口注入一个 contentScript.js,封装了 postMessage 方法。 // 发送消息通过 window.postMessage(data, ‘*’); // 接受消息通过 window.addEventListener(‘message’, messageHandler); 复制代码 小程序的推动主要来自微信平台的大流量,这就是所谓的微信流量红利,公众号已经承载了传播和拉新的低成本方式,但是体验一直被诟病,限制于 hybrid 的体验问题让追求体验的开发者逐渐无法忍受,此时小程序原生的组件,良好多页面切换,几乎没有白屏时间的等待,让大家又有了探索无限的可能。 优点: 首先具有所有 hybrid 所有的优点 无需安装,极速打开 原生的组件有了体验上质的提升 性能上也有了新的飞跃,白屏时间,页面切换也有了更好的体验(为了减少白屏时间,小程序采用预加载的方案,而分不清哪个会是逻辑里的下一个页面,所以小程序将所有 webView 全局预加载,这也是页面层级和包大小限制的主要原因) 缺点 只能用于微信平台,如果有多端的用户需求,开发成本增加了 组件还是较少,很多操作 DOM 的方式也会有所限制,完成需求受限 为了性能的体验,包的大小受限,打开页面的层级受限 代表产品: 各种客户端的小程序 快应用 快应用是对标微信小程序的一场阻截,几大手机厂商联合发布这个方案,一瞬间吸引了大家的眼球,越来越多端让前端追都追不过来(这么多技术确实让人很绝望,甚至前段时间大家去恶意灌水了很多大项目的 issue,但这也是前端蓬勃发展的表现,当这些前沿的技术落地在项目中甚至你只是完成一个 demo 的时候,你还是会有抑制不住的兴奋和成就感) 快应用对自我的介绍是基于手机硬件平台的新型应用形态,用的是新型应用形态,并非新技术,类似这样的实现有 PWA,只是 PWA 缺少了手机硬件平台的支持。 快应用标准是由手机厂商组成的快应用联盟联合制定,快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台。底层的硬件平台提供底层 API 让开发者调用,原生渲染组件,hybrid bridge 通信,原理大致也与小程序实现类似,这里就不详细说明,下面是几张快应用发布会的 PPT 截图,如果理解了上面的原理,这个应该就是比较好理解了。 之所以说是小程序的一场阻截,小程序曾放话说,未来两年内,小程序将取代 80% 的 APP 市场,而手机厂商并不希望大量的 APP 被取代,所以催生了快应用的落地。但是建立在几大国内手机厂商硬件平台上的方案,就目前来看支持性,通用性,社交性上都是比不上小程序的。两者的前景不敢妄加揣测,但是小程序凭借微信平台的用户量和用户粘性,比几大手机厂商实现的标准化还是一目了然的。 优缺点就不详述了,一目了然 Flutter ReactNative 的开疆扩土进一步奠定了,React 的霸主地位,React 也由一个框架演进成了,以 React 为基础的前端多端解决方案,技术栈的生态方案。google 怎么可能放弃自己在科技领域的地位,即使是前端相关的技术,所以出了 Flutter 技术方案完成 APP 的一环。 借由本身的 android 和 chrome 的 平台优势,准备重磅推出 Fuchsia OS,打造自己不基于 Linux 的底层系统,而 Fuchsia OS 钦定 UI Toolkit 就是 Flutter。Flutter 最大的改进就是自己重做了渲染引擎去渲染页面,将混合应用的渲染性能推向了另一个高度。 Flutter 之于 RN 来讲最大的区别在于渲染,脱离了 JSFramework 的 Component 递归传递和逐个计算绘制,更像是 canvas 绘制,将 UI 直接绘制出来,Flutter 都是在状态变更时重新构建 Widget Tree,Flutter 的渲染引擎在将 Widget Tree 转化成渲染的 Render Tree,最后交给操作系统调用 GPU 去渲染,Flutter 由 Dart 程序写的,Dart 和 native 之间仍然存在一个接口,可以进行数据编码和解码,这可能比 JavaScript bridge 快好几个数量级。 使用 Dart 是整个框架不太被前端所接受的问题,但是代码都是相通的,上手还是很快,尝试 demo 期间还是很快就能模仿出一个页面,语言上的争论就不说了,毕竟都不如 PHP。 由于自己使用 Flutter 还在 demo 阶段,并没有真正围绕 Flutter 做过相关的解决方案,具体的细节实现也没有清楚的认知,也不适合展开详述,很早之前以矢量图起家的 Adobe 也尝试过类似的方案,但是最终没有把这条路走下去。 如果有兴趣可以移步: Flutter 原理简介 什么是 Flutter 革命 如何评价 Google 的 Fuchsia、Android、iOS 跨平台应用框架 Flutter? weex 和 ReactNative 在讲这两种混合应用之前,再啰嗦几句,上面大致了解了各种混合应用的方案,这些方案了解其原理和使用场景,在合适的场景去使用对应的方案,不要为了落地某项方案而把业务生搬硬套,没有一种方案是绝对的好,在不同的业务需求的驱动下权衡利弊再做决策。 这两者一直有人在试图去比较分析得出利弊,看哪种更好,甚至有人偏激的认为 Weex 就不配合 RN 相提并论,但是我还是想说理性的看待这个问题,客观的面对前端技术,曾经 React 和 Vue 也是这样的差距,直到现在依旧有人认为使用 Vue 低俗,使用 React 高雅,但雅俗之分真的如此吗?还是应该理解其原理,辨别自己的业务场景,团队学习成本,开发体验等等一系列的原因,然后再做评判。 就目前的各方面情况讲,RN 确实更优,横空出世,背靠当时火的不行 React,一路都是风光无限。这种解决方案出来之后,如果没有竞争者的挑战,没有对比,没有选择,也不一定是好事儿,虽然现在两者还有很大的差距。 我猜 Weex 始于 KPI,毕竟大厂造轮子来升级是非常好的途径之一,但是往后发展,却成了两大阵营完善生态的方案,现在基于 React 的一整套的前端解决方案覆盖PC、Web、Native 可谓是成了大公司前端方案的标准套路,后起之秀 Vue 用良好的开发体验和低门槛的入门方式开始抢占用户,各种前端培训学校让一些前端不懂 js 基础,但是 Vue 溜的飞起。但Vue 并没有形成对 Native 的覆盖,这个可能也是 Weex 和 Vue 一拍即合的原因,双方都有需求,就开始了合作。 扯会正题,在大前端逐渐融合的背景下,作为以 Vue 建立技术栈的团队开始寻找客户端的方案,做技术选型开始考虑业务达成、团队学习成本、开发效率,性能效率等问题,我们一开始也是将 Weex 和 RN 作为比较,在上一家公司使用的是 RN,但是现团队建立技术栈基于 Vue,考虑到第二个因素偏向 Weex,实际调研过程中发现 Weex 的坑确实很多,但是好在有很多问题已经有解决方案了,当然不管想要使用上述两种方案,都需要有一定的原生能力。实际开发过程中发现随着对 Weex 的了解越来越多,开发效率也越来越快,入坑之后才发现了第三个和第四个甚至第五第六个优势。 至于 Weex 最大的卖点,兼容三端,Web 端这个优势每个人都有自己的看法,我们尝试了去兼容 Web 但是发现反而牺牲了开发效率,有兼容的时间,单独开发一套也出来了,并且更重要的是由于用户习惯的不一致,Web 端和 Native 针对的用户群体也不一样,在这个流量就是金子的环境下牺牲用户体验和开发效率去兼容 Web 并非是我们的初衷。 当然也遇到了一些问题,一开始 Weex 没有托管 Apache 的时候还有 issue,很多问题确实不能及时得到解决,所以决定脱离 Weex 的所有 module,自行开发所有 module,重新设计,这也让我们对项目有了一些控制。 决定了自行开发 module 和组件之后,减少了对 Weex 本身的依赖,项目本身受到的限制也越来越小,业务很快也完成了。当然现在类似 demo 跑不起来,毁灭式的升级,市场组件无法接入,bug 横飞,组件不足以完成业务功能,兼容性不足,热更新,公共文件导致包过大,社区经营不好等等这些问题,也都是一个技术产品成长的必经之路。 两种方案在选型的时候,一定有可取的地方才会选择,工程师的精神就是趟坑,找准正确的方向然后一往无前,两种方案都有已经上线的优秀产品,说明是这条路至少是能走通的,当然我们也在过程中总结了我们的解决方案,希望能帮助在 Weex 路上举步维艰的同行人,不管选择哪种方案,选择了就把他做好。Eros项目地址请戳(不要吝啬你的 star)。Eros文档地址请戳。我们公司已有三个项目通过 Eros 上线,也有几十个应用通过 Eros 发布上线。 当然还有很多优秀的方案没有一一枚举,比如:kotlin、WebAssembly,每个方案都沉淀了很多前端工程师的积累,提供了各种能落地可实行的方案 phonegap -> cordova、mui、appcan、apicloud 等等 原文发布时间为:2018年06月08日 原文作者:还是怕麻烦 本文来源掘金如需转载请联系原作者
虽然全网上 Vue 仿饿了么、xx音乐的项目一大堆,但是我还是厚着脸皮来了,毕竟我也稍微标新立异,PC端为主,移动端为辅打造的 web 音乐播放器,所以说大佬们关爱下,毕竟我这个播放器刚从韩国回来!!! 模仿QQ音乐网页版界面,采用flexbox和position布局; mmPlayer虽然是响应式,但主要以为PC端为主,移动端只做相应适配(未做歌词显示); 只做主流浏览器兼容(对IE说拜拜并特别优化,想想以前做项目还要兼容IE7,都是泪啊!!!) api:一个开源的网易云音乐 NodeJS 版 API(有 api 才有动力写!!!) Vue-mmPlayer 源码地址 在线演示地址 服务器脆弱,小哥哥小姐姐要温柔对待哦(最好是 PC 浏览哦) 桌面版下载 有点简陋,别介意,主要人懒还有就是没空 如何安装与使用 mmPlayer git clone https://github.com/maomao1996/Vue-mmPlayer.git //下载mmPlayer cd mmPlayer //进入mmPlayer播放器目录 npm install //安装依赖 npm run dev //服务端运行 npm run build //项目打包 复制代码 后台服务器 cd mmPlayer/server //进入后台服务器目录 npm install //安装依赖 node app.js //服务端运行 访问 http://localhost:3000 复制代码 运行mmPlayer后无法获取音乐请检查后台服务器是否启动 api目录下music的url地址要和后台服务器地址一致 技术栈 Vue-Cli(Vue 脚手架工具) Vue(核心框架) Vue-Router(页面路由) Vuex(状态管理) ES 6 / 7 (JavaScript 语言的下一代标准) Less(CSS预处理器) Axios(网络请求) FastClick(解决移动端300ms点击延迟) 界面欣赏 PC端界面自我感觉还行, 就是移动端界面总觉得怪怪的,奈何审美有限,所以又去整了高仿网易云的 React 版本(如果小哥哥、小姐姐们有好看的界面,欢迎交流哈) PC 正在播放 排行榜 搜索 我的歌单 我听过的 歌曲评论 移动端 功能 播放器、快捷键操作、歌词滚动、正在播放、排行榜、歌单详情、搜索、播放历史、查看评论、同步网易云歌单 播放器(核心) 播放器功能其实也就那样,调用 HTML5 音频的方法、属性和事件,网上各种文章也都介绍烂了,但是骗赞要有诚意 我实现的功能有这些:上一曲、下一曲、暂停、播放、单曲循环、列表循环、随机播放、顺序播放、进度条、音量控制 在介绍这些功能之前先理理思路,这里用个小 demo 介绍,毕竟没有代码,虾扯蛋谁不会啊,先上代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Audio</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> </head> <body> <div id="Audio"> <audio ref="mmAudio" :src="src" controls></audio> <button @click="prev">上一曲</button> <button @click="play">暂停/播放</button> <button @click="next">下一曲</button> </div> <script> const vm = new Vue({ el: '#Audio', data: { list: [ 'https://music.163.com/song/media/outer/url?id=450424527.mp3', 'https://music.163.com/song/media/outer/url?id=557581284.mp3', 'https://music.163.com/song/media/outer/url?id=452986458.mp3' ],//歌曲数组 index: 0,//当前歌曲下标 }, computed: { src() { return this.list[this.index] // 当前播放歌曲 } }, methods: { prev() {//上一曲 let index = this.index - 1; if (index < 0) { index = this.list.length - 1 } this.index = index; this.$nextTick(() => this.$refs.mmAudio.play()) }, play() {//暂停/播放 this.$nextTick(() => this.$refs.mmAudio.paused ? this.$refs.mmAudio.play() : this.$refs.mmAudio.pause()) }, next() {//下一曲 let index = this.index + 1; if (index === this.list.length) { index = 0 } this.index = index; this.$nextTick(() => this.$refs.mmAudio.play()) } } }) </script> </body> </html> 复制代码 这段代码的逻辑非常简单,我们会添加一个 computed 动态生成 歌曲 src ,当点击暂停/播放的时候,会调用 play 方法,修改 播放状态;当点击上一曲或者下一曲的时候,会修改当前歌曲播放的 index ,然后会触发 computed 修改 src 然后调用 play 方法播放音乐 看完这个小 demo 这些功能都好理解了 上一曲/下一曲:修改当前歌曲播放的 index ,然后会触发 computed 修改 src ,然后调用 play 方法播放音乐 暂停/播放:通过 Audio 的 paused 属性判断音频是否处于暂停状态,如果返回 true 调用 play 播放音乐,如果返回 false 调用 paused 暂停音乐 单曲循环:调用 Audio 的 ended 事件,在当前歌曲播放结束后将 currentTime 属性重置为 0 列表循环:调用 Audio 的 ended 事件,在其回调中调用下一曲方法 随机播放:通过一个方法打乱歌曲数组,打乱数组前先用一个数组存放原始歌曲数组 顺序播放:调用 Audio 的 ended 事件,判断当前歌曲下标是否和歌曲数组长度 -1 相等,如果相等就不再调用下一曲方法 进度条/音量控制:使用自己封装的 progress 组件 来进行拖动,点击操作来修改对应的播放进度 currentTime 和音量 volume 小记:在 progress 的事件绑定中只有鼠标按下mousedown和触摸开始事件 touchstart 是绑定在对应的 DOM 节点上,其他鼠标移动mousemove和触摸移动touchmove、鼠标释放mouseup和触摸释放touchend等事件绑定的 DOM 都是 document ,不然会出现各种掉链子的问题,比如拖动过程中不小心焦点不在对应的 DOM 上了就会中断拖动 快捷键操作 上一曲 Ctrl + Left 播放暂停 Ctrl + Space 下一曲 Ctrl + Right 切换播放模式 Ctrl + O 音量加 Ctrl + Up 音量减 Ctrl + Down 歌词滚动 歌词滚动原理:根据当前音乐的播放时间 audio.currentTime 去匹配歌词 JSON 数据的时间,然后匹配后的歌词居中显示并高亮 先来张歌词 JSON 的迷人玉照给各位小哥哥、小姐姐们解解馋 { lyric: "[by:鱼丸啊鱼丸QAQ] [00:00.00] 作曲 : willen [00:01.00] 作词 : 口袋易百 [00:04.60]伴唱:willen [00:05.10]混音/母带:willen [00:55.37]外婆的话 还记得吗 [00:59.01]慈祥的笑容伴我长大 [01:02.75]每当庭院开满了桂花 [01:06.50]淡淡花香都是爱的牵挂 [01:10.30]外婆的话 还记得吗 [01:14.01]受伤的孩子别忘了回家 [01:17.66]夕阳西下 岁月染白了发 " } 复制代码 由于 audio.currentTime 是以秒计,而歌词 JSON 的格式是酱样子的 [00:00.00] 所以我们要先把歌词 JSON 化个妆 // 这是化妆过程,具体流程我就不多说了,毕竟我是厚着脸皮来掘金骗小心心的 function parseLyric(lrc) { let lyrics = lrc.split("\n"); let lrcObj = []; for (let i = 0; i < lyrics.length; i++) { let lyric = decodeURIComponent(lyrics[i]); let timeReg = /\[\d*:\d*((\.|\:)\d*)*\]/g; let timeRegExpArr = lyric.match(timeReg); if (!timeRegExpArr) continue; let clause = lyric.replace(timeReg, ''); for (let k = 0, h = timeRegExpArr.length; k < h; k++) { let t = timeRegExpArr[k]; let min = Number(String(t.match(/\[\d*/i)).slice(1)), sec = Number(String(t.match(/\:\d*/i)).slice(1)); let time = min * 60 + sec; if (clause !== '') { lrcObj.push({time: time, text: clause}) } } } return lrcObj; } 复制代码 我比较菜,火星文(正则)全靠搜索引擎,这个是歌词正则原地址,不过我的稍加修饰了下 当这一切 OK 后就只要匹配时间居中并高亮展示当前歌词就行啦! 目前我是通过 for 循环对比大小找到第一个比当前播放时间大的歌词时间,但是我一直觉得这样写不够优雅,无奈又想不到其他方法,希望知道优雅方法的小哥哥、小姐姐来指点迷津 正在播放 显示和管理当前播放的歌单,可以清空当前播放器列表、删除置顶歌曲,修改歌曲的播放状态 排行榜 调用对应 API 接口获取网易云音乐的排行榜列表(目前没做图片懒加载) 歌单详情 传入歌单 ID 调用对应 API 接口获取当前歌单下所有歌曲,由于是获取所有歌曲在移动端滑动时会有所卡顿,这个后期会加入Better-Scroll(一款重点解决移动端各种滚动场景需求的插件) 搜索 目前只实现了歌曲的搜索,后续会完善 专辑 / 歌手 / 歌单 / 用户 的搜索 通过搜索关键字请求 API 获取搜索数据并显示歌曲 分页:调用 scroll 事件,滚动到底部下载下一页,目前是50条每页,当所有数据请求完毕后会提示:没有更多歌曲啦! 在上次网易云音乐和 QQ 音乐版权之争中,周杰伦的所有单曲全部 GG ,然后我就在播放事件中先去请求当前歌曲的 url ,如果没有就会提示:当前歌曲无法播放;如果不做这个,万一又被怼那就不好了,毕竟用户是大佬,惹不起也躲不起 播放历史 调用 canplay 事件,将不会播放出错的歌曲通过 localStorage 存储 PS:一开始我是通过 play 事件 ,结果不管你能不能放都会加入播放历史,然后被吐槽了,最后各种研究发现 canplay 更优雅 查看评论 这个是段子云音乐的一大亮点,必须要加上 通过当前播放音乐的 id 调用对应的 API 接口 分别展示热门评论和最新评论 当时做这个的时候界面简直小意思,但是评论时间简直郁闷,有: 刚刚 / XX 分钟前 / XX:XX / XX 月 XX 日 / XX 年 XX 月 XX 日 大概花了半个多小时才 KO 掉,不过不知道为啥一直觉得我这么写不够优雅,希望知道优雅方法的小哥哥、小姐姐来指点迷津 同步网易云歌单 先去 网易云音乐 获取自己的 UID 然后通过调用对应的 API 接口 获取该用户的歌单,然后传入歌单 ID 获取歌单详情。 当对应的 UID 返回的 playlist 数组长度为 0 时提示 未查询找UID为 ${uid} 的用户信息 登陆成功后调用 localStorage 存储当前 UID ,下次打开时会先读取本地存储的 UID 进行登录操作 退出登录时清空 localStorage ,以免下次打开时还会登录 后续 代码提高复用率 优化移动端界面和体验,比如 Better-Scroll,图片懒加载 专辑 / 歌手 / 歌单 / 用户 的搜索 用 koa 重构后台服务 完善下桌面版的体验(毕竟太简陋,自己都看不下去了) ...(脑容量不够,暂时就想到这些) 感谢 HTML 音频/视频 DOM 参考手册 网易云音乐 NodeJS 版 API Vue.js 升级踩坑小记 Lodash(JavaScript 实用工具库) 其他 个人练手项目,主要有段时间闲得无聊,然后在逛 Gayhub 时发现个开源的音乐API —— 网易云音乐 NodeJS 版 API 最后就一边无耻的水群一边找好看的界面顺带整理下开发思路 曾经有段时间很多人问我用的什么什么 UI 框架,所以我另外再提一下,该项目基础 UI 全是个人结合项目和各大 UI 框架代码风格慢慢敲的,再推荐个 Vue 课程 —— Vue.js 音乐 App 高级实战课程 还有就是有木有 React 大佬带我,最近正在自学中,有很多迷津求解答 这是一边学一边做的项目 React移动端版本(高仿网易云音乐 自我感觉这高仿没毛病 原文发布时间为:2018年06月15日 原文作者:小小茂茂 本文来源掘金如需转载请联系原作者
如果你之前没有听说过CSS变量,那么现在我将告诉你:它是CSS的新特性,让你能够在样式表中使用变量的能力,并且无需任何配置。 实际上,CSS变量能够让你改变以往设置样式的老方法: h1{ font-size:30px; } navbar > a { font-size:30px; } 而使用了CSS变量之后: :root { --base-font-size: 30px; } h1 { font-size: var(--base-font-size); } navbar > a { font-size: var(--base-font-size); } 这样的词法有点奇怪,但它确实能够让你通过仅改变--base-font-size的值来改变app中所有原生的字体大小。 如果你想要学习CSS变量的知识,可以登录Scrimba看我的视频课程,或是阅读我在Medium上写的文章:如何学习CSS变量。 好了,现在让我们看看如何使用这个新知识来更加简单地制作响应式站点吧。 初始配置 让我们来把下面这个页面变成响应式的吧: 这个页面在PC端看上去很不错,不过你可以看到它在移动端的表现并不好。就像下面这样: 在下面这张图中,我们在样式上做了一些改进,让它看起来更好一点: 重新排列整个网格布局,使用垂直排列取代固定两列布局。 将框架整体上移了一点。 对字体进行了缩放。 目光转到CSS代码中,下面是我们要修改的代码: h1 { font-size: 30px; } #navbar { margin: 30px 0; } #navbar a { font-size: 30px; } .grid { margin: 30px 0; grid-template-columns: 200px 200px; } 更具体地说,我们需要在一个媒体查询中做出以下调整: 将h1的字体调整为20px; 减少#navbar的上外边距为15px; 将#navbar的字体大小减少到20px; 减少.grid的外边距为15px; 将.grid从两列布局变为单列布局。 注意:样式表里不仅仅是这些CSS声明,但是在这篇教程中我跳过它们,因为媒体查询并不影响它们的设置。你可以在这里获取完整的代码。 旧方法 不使用CSS变量确实可以做到同样的效果,但这样会增加许多不必要的代码,因为上面大部分修改都需要将声明在媒体查询中重写一遍。就像下面这样: @media all and (max-width: 450px) { navbar { margin: 15px 0; } navbar a { font-size: 20px; } h1 { font-size: 20px; } .grid { margin: 15px 0; grid-template-columns: 200px; } } 新的方法 现在让我们看看使用CSS变量是如何起作用的。首先,我们要声明需要更改或复用的变量: :root { --base-font-size: 30px; --columns: 200px 200px; --base-margin: 30px; } 然后,我们只需要在app中使用它们就可以了。非常简单: #navbar { margin: var(--base-margin) 0; } #navbar a { font-size: var(--base-font-size); } h1 { font-size: var(--base-font-size); } .grid { margin: var(--base-margin) 0; grid-template-columns: var(--columns); } 之后,我们可以在媒体查询中修改这些变量值: @media all and (max-width: 450px) { :root { --columns: 200px; --base-margin: 15px; --base-font-size: 20px; } 这样的代码是不是比之前要简洁多了?我们只需要专注于:root选择器就可以了。 我们将媒体查询中的4个声明减少到了1个,代码也从13行减少到了4行。 当然,这只是一个简单的例子。想象一下,在一个大中型网站中,有一个--base-margin变量控制着所有的外边距。当你想要在媒体查询时修改属性,并不需要用复杂的声明填充整个媒体查询,只是简简单单地修改这个变量值就可以了。 总之,CSS变量可以定义为未来的响应式。如果你想要学习更多的知识,我推荐你看我的免费教程。用不了多久你就能成为一个CSS变量大师。 原文发布时间为:2018年03月04日 原文作者:白吟灵 本文来源CSDN如需转载请联系原作者
什么是编码规范 编码规范就是指导如何编写和组织代码的一系列标准。通过阅读这些编码规范,你可以知道在各个公司里代码是如何编写的。 我们为什么需要编码规范 一个主要的原因是:每个人写代码的方式都是不同的。我可能喜欢这么写,而你喜欢用另一种方法写。如果我们只处理自己的代码,这样并没有什么问题。但如果有成千上万的程序员同时在一个代码库上面工作呢?如果没有规范,事情很快会变得一团糟。代码规范可以让新人迅速的熟悉相关的代码,并且也能写出让其他程序员简单易懂的代码。 Airbnb JavaScript Style Guide 号称是“最合理的编写 JavaScript 代码的方式”。 Airbnb 的这个代码规范可能是互联网最流行的 JavaScript 代码规范了,它在 Github 上足有 6 万 star,几乎覆盖了 JavaScript 的每一项特性。 地址: https://github.com/airbnb/javascript Google JavaScript Style Guide 只有遵守了这里的规则,一个 JavaScript 源文件才能被称为“Google Style”。很霸气,我行我素,同时也被不少公司沿用。 地址: https://google.github.io/styleguide/jsguide.html Idiomatic JavaScript Style Guide 符合语言习惯的 JavaScript 代码规范。 不管有多少人参与,不管是否在同一个代码库,所有的 JavaScript 代码风格都必须像同一个人写的。 另一个很强势的同时也很流行的 JavaScript 编码规范。它的野心也很大,不止想规范 JavaScript,其它语言也都想管起来。 地球上所有的代码都像同一个人写的?想想让人觉得不寒而栗啊…… 地址: https://github.com/rwaldron/idiomatic.js JavaScript Standard Style Guide 一个功能强大的 JavaScript 代码规范,自带 linter 和自动代码纠正,无需配置,自动格式化代码。可以在编码早期就发现代码中的低级错误。这个代码规范被很多知名公司所采用,比如 NPM、GitHub、mongoDB 等。 地址: https://github.com/standard/standard (这个 Github 地址霸气到不行。) jQuery JavaScript Style Guide jQuery 是多少人入门前端的好帮手啊,可惜如今只剩回忆了。它们的这个规范算是很早期的一个代码规范了,主要是针对它们的代码以及早期 JavaScript 版本进行规定。 地址: https://contribute.jquery.org/style-guide/js/ 你喜欢哪个代码规范,你的团队在用哪个规范呢?请留言告诉我们! 原文发布时间为:2018年01月29日 原文作者:JavaScript_w 本文来源CSDN如需转载请联系原作者
命令行工具 大多数库和框架都配备有一个命令行工具,通过输入一个命令,可以为我们启动一些框架项目,以快速创建我希望的东西。这通常包括一个启动脚本(有时用自动重新加载器),构建脚本,测试结构等等。当我们创建新项目时,这些工具可以减轻我们大量冗余文件的编写。让我们来看看更多其他的一些命令行工具。 Webpack 配置 配置你的 webpack 构建过程并真正理解你在做什么,可能是 2017 年更令人畏惧的学习曲线之一。幸运的是,他们的核心贡献者之一 Sean Larkin 奔走在世界各地,为我们提供了很棒的演讲和非常有趣和有用的教程。 现在许多框架不仅为您创建了 webpack 配置文件,甚至将它们填充到您甚至可能不需要看的地步。Vue 的 CLI 工具有一个 webpack 专用的模板,为您提供全功能的 Webpack 设置。为了让您充分了解命令行工具提供的内容,以下是 Vue CLI 模板包含的内容: npm run dev: 首要开发体验 用于 Vue 单文件组件的 Webpack + vue-loader 热更新中的状态保持 编译错误时的状态保持 保存时使用 ESLint 检查 源文件映射(Source Map) npm run build: 为生产环境准备好构建 使用 UglifyJS v3 最小化 JavaScript 使用 html-minifier 最小化 HTML 使用 cssnano 提取所有组件中的 CSS 并最小化 对静态资源计算 Hash 使之在缓存中长期有效,并自动为生产环境生成使用这些静态资源 URL 的 index.html 使用 npm run build --report 构建并生成含有流量分析的报告 npm run unit: 使用 Jest 在 JSDOM 中运行单元测试,或者在 PhantomJS 中使用 Karma + Mocha + karma-webpack 测试文件支持 ES2015+ 简单打桩 npm run e2e: 使用 Nightwatch 进行端到端测试 自动处理 Selenium 和 chromedriver 依赖 自动生成 Selenium 服务器 在多个浏览器中并行地运行测试 使用一个非常好的命令行工具: preact-cli,从另一个方面支持着 Webpack 的功能。如果你需要自定义 webpack 配置,只需要创建 preact.config.js,它导出一个函数来改变 webpack。大量的工具带来了大量的便捷性,开发人员们也在相互帮助。 Babel:启用还是关闭 弄明白了吗?Babel 听起来像巴比伦(Babylon)。我都快崩溃了。我并没有试图将 Babel 与 Babylon 联系在一起,但有人说过我们可能会放弃对转译(transpiling)的依赖。在过去几年里,Babel 一直是个大问题,因为我们想要 ECMAScript 提出的所有美好的特性,但又并不想等待浏览器跟上更新。随着 ECMAScript 转向年度小版本发布,浏览器可能会跟上。剔除一些非常棒的 kangax 兼容性图表的 JavaScript 发布是什么样的呢? 这些图表的截图不是很清晰,因为我想展示它们看起来是多么的绿!更多有关详细信息,请单击图像下方的链接以进一步查看图表。 es6 的兼容性 2016+ 的兼容性 在第一张图中,左侧的红色块是编译器(例如es-6 shim,Closure等)和较旧的浏览器(例如Kong 4.14和IE 11)。右边的五个红色列是服务器/编译器PJS、JXA、Node 4、DUK 1.8和DUK 2.2。在较低的图上,看起来像一只狗并且乱七八糟的感叹号的糟糕图形的红色区域是仅使用Node 6.5+具有绿色条纹的服务器/运行时。左边红色方块的构成是编译器/polyfils和IE 11。更重要的是,看看那些绿的!在最流行的浏览器中,我们几乎都是绿色的。2017年功能中的唯一红色标记是Firefox 52 ESR for Shared Memory和Atomics。 从一些角度来看,这里是来自维基百科的一些浏览器使用情况。 好的,关闭Babel可能会有点麻烦,因为当它落实之时,我们希望其能被尽可能多的用户尽可能地访问Babel。想想下我们可能能够摆脱那个额外的步骤,在我们没有使用转译器之时。 Tocy 翻译于 5个月前 1人顶 顶 翻译得不错哦! 谈谈 TypeScript 如果我们在谈 JavaScript,那就不得不谈谈 TypeScript。5 年前从微软办公室诞生的 TypeScript 发展到 2017 年,已经非常酷了。几乎没有什么会议在谈论“我们为什么喜欢 TypeScript”,但它为开发带来了新的体验,自然受到人们喜欢。对于 TypeScript,不需要赞美,我们只是谈谈开发者在使用它的时候为什么会感到轻松。 对于想在 JavaScript 中使用类型的人来说,TypeScript 在语法上是 JavaScript 的超集,为其带来了静态类型。如果你喜欢这种东西,就会觉得非常酷。当然,如果你看到了 JavaScript 状态调查的最新结果,你会发现实际上很多人都喜欢。 来自 JavaScript 的状态 我们看看 Brian Terlson 是怎么说的: 作为 2014 年为 JavaScript 提议加入类型的人,我不认为类型会在较短时间内实现。从标准的角度来说,这是一个极其复杂的问题。对于TypeScript 用户来说,采用 TypeScript 标准当然无可非议,不过也有其它一些J avaScript 超集支持类型,它们支持着一些相当重要的用法,比如 Closure Compiler 和 FLow。这些工具的行为各不相同,甚至不清楚它们是否存在一个共同的子集(我不认为有直观的表现)。我不确定类型标准更像哪一个,我和其他人会继续进行相关的调查研究,这可能是有意义的工作,但不要希望在短期内完成 - HashNode AMA with Brian Terlson 边城 翻译于 5个月前 1人顶 顶 翻译得不错哦! TypeScript 喜欢 Flow 在 2017 年,你大概看到了很多帖子在讨论 TypeScript + Flow 的组合。Flow 是 JavaScript的静态类型检查器。 通过 Flow 你可以在图表中看到 JavaScript 的状态,这里面的内容包含了你感兴趣和不感兴趣的。尽管很多人还没有听说过 Flow,但是他们应该会对一些状态感兴趣。如果人们在 2018 年学习了更多的 Flow,那他们就会发现 Minko Gechev 所做的有用的事: TypeScript 和 Flow 消除了你的产品中大约 15% 的 bug! 还觉得类型系统没有用么? https://t.co/koG7dFCSgF Angular 喜欢 TypeScript 你可能注意到在 Angular 文档中所有的代码例子就是由 TypeScript 写的。曾经在某个时候,有一种建议,你应该选择过一遍 JavaScript 或者 TypeScript 的手册,不过,看起来 Angular 的心已经动摇了。查看连接 Angular 到 JS 风格的图表,我们会看到实际上有一小部分会被Angular 连接到 ES6(TypeScript: 3777, ES6: 3997)。我们静待它在 2018 对 Angular 的影响。 来自 JavaScript的状态 无若 翻译于 5个月前 1人顶 顶 翻译得不错哦! 有关如何为您的下一个应用程序选择正确的 JavaScript 框架的一些专家建议,请参阅此白皮书。 毫无疑问,我们的 JavaScript 将在 2018 年快速发展。作为程序员,我们喜欢编写和使用那些让我们的生活更轻松的工具。不幸的是,这有时会导致更多的混乱和太多的选择。值得庆幸的是,命令行工具正在帮助我们减轻一些烦琐的工作,并且 TypeScript 已经满足了那些对类型错误感到厌恶的开发者。 JavaScript 的未来 想要深入了解我们在 JavaScript 的发展方向? 不妨查看我们的最新文章“2018 年 JavaScript 的未来及远方” 原文发布时间为:2018年01月15日 原文作者:oschina 本文来源开源中国如需转载请联系原作者
表格、表单、js常识 1.表格 - 在网页中可以通过表格来表示一些格式化的数据- 表格相关的标签- <table> 用来创建一个表格- <tr> 表示表格中的一行- <th> 表示表头中的单元格- <td> 表示表格中的单元格- 属性:colspan 横向的合并单元格rowspan 纵向的合并单元格- 例子:<table><tr><td></td><td></td></tr><tr><td></td><td></td></tr></table>- 长表格- <thead> 表格的头部- <tbody> 表格的主体- 注意:如果表格中没有写thead tbody tfoot,浏览器会自动向table中添加一个tbody并且将所有的tr都放到tbody中,tr是tbody的子元素,不是table的子元素- <tfoot> 表格的底部2.表单- 表单可以将用户的信息提交到服务器中- <form>- 用来创建一个表单- 属性:action:需要一个服务器地址,提交表单时表单中的内容将会被提交到该地址- 表单项- <input />- 它可以根据不同的type属性值,生成不同的表单项- type="text" 文本框 <input type="text" name="" />- type="password" 密码框 <input type="password" name="" />- type="radio" 单选按钮 <input type="radio" name="" value="" checked="checked" />- type="checkbox" 多选框 <input type="checkbox" name="" value="" checked="checked" />- type="submit" 提交按钮 <input type="submit" value="按钮上的文字" />- type="reset" 重置按钮 <input type="reset" value="按钮上的文字" />- type="button" 普通按钮 <input type="button" value="按钮上的文字" /> - <select>- 下拉列表- <select name=""><option value="" selected="selected"></option><option value=""> </option><option value=""></option></select>- <button>- 按钮功能input那几个按钮一样,但是它们要灵活一些<button type="submit">按钮的文字</button><button type="reset">按钮的文字</button><button type="button">按钮的文字</button>3.JavaScript- JavaScript负责页面中的的行为。- 它是一门运行在浏览器端的脚本语言。- JS的编写的位置1.可以编写到标签的指定属性中<button onclick="alert('hello');">我是按钮</button><a href="javascript:alert('aaa');">超链接</a>2.可以编写到script标签中 *****<script type="text/javascript">//编写js代码</script>3.可以将代码编写到外部的js文件中,然后通过标签将其引入 *****<script type="text/javascript" src="文件路径"></script>- 输出语句- alert("要输出的内容");- 该语句会在浏览器窗口中弹出一个警告框- document.write("要输出的内容");- 该内容将会被写到body标签中,并在页面中显示- console.log("要输出的内容");- 该内容会被写到开发者工具的控制台中- 基本的语法- 注释- 单行注释//注释内容- 多行注释/*注释内容*/- JS严格区分大小写 - JS中每条语句以分号(;)结尾,不写浏览器在解析的时候会自动加上- JS中会自动忽略多个空格和换行,所以我们可以利用空格和换行对代码进行格式化。- 字面量和变量- 字面量- 字面量实际上就是一些固定的值,比如 1 2 3 4 true false null NaN "hello"字面量都是不可以改变的。- 由于字面量不是很方便使用,所以在JS中很少直接使用字面量- 变量- 变量可以用来保存字面量,并且可以保存任意的字面量- 一般都是通过变量来使用字面量,而不直接使用字面量,而且也可以通过变量来对字面量进行一个描述- 声明变量- 使用var关键字来声明一个变量var a;var b;var c;- 为变量赋值a = 1;b = 2;c = 3;- 声明和赋值同时进行 *****var d = 456;var e = 789;- 标识符- 在JS中所有的可以自主命名的内容,都可以认为是一个标识符,是标识符就应该遵守标识符的规范。- 比如:变量名、函数名、属性名- 规范:1.标识符中可以含有字母、数字、_、$2.标识符不能以数字开头3.标识符不能是JS中的关键字和保留字4.标识符一般采用驼峰命名法 xxxYyyZzz 原文发布时间为:2018年04月21日 原文作者:Song-宋-Song 本文来源CSDN如需转载请联系原作者
CSS不是一门很复杂的语言,但是即使你已经写css很多年了,也很有可能遇到一些新玩意儿-某些属性从来没用过,某些值从来未曾考虑,或者某些规范细则你从来不知道。 我经常会遇到一些css小细节,所以我想在这片文章中和大家分享,需要承认的是,这篇文章中的很多东西并不具有实操价值,但也许你可以留作后用。 1、body上的color不只是应用于文字 让我们从最简单的开始吧,color属性是被广泛运用的属性,某些人可能不曾注意,它并不仅仅只是定义文本的颜色。 让我们看这个例子: css代码: body { color: yellow; background: #444; font-size: 20px; font-family: Arial, sans-serif; text-align: center; } ul { border: solid 2px; text-align: left; } ol { text-align: left; } hr { border-color: inherit; } a { color: white; } 请注意我们只是给body设定了color为yellow,但是你可以看到,页面里的元素都变成了黄色,他们包括: 图片的alt文字的值,就是当图片源载入不了时显示的文字 列表元素的边框 无序列表的点 有序列表的数字 hr元素 有趣的是,hr元素默认是不会继承color属性得,我需要强制他继承border-color: inherit,这对我来说有点怪异。 W3c规范是这么定义的: 这个属性用来描述元素的文本的前景颜色,附带被用来为其他接受颜色值的其他属性提供潜在的间接的值。 我不是很明确地知道有哪些是被当做所谓的前景的,如果你知道的话,请在评论中告诉我。 2、visibility还可以设置 “collapse”值 你可能已经用过visibility上千遍了,最常用的是visible和hidden,用来使元素显示或者隐藏。 还有第三个很少被用到的值是collapse,除了在表格的行,列中使用有差异外,他和hidden的作用是等同的。 下面让我们看看在表格元素中,collapse是怎么工作的,不过前提是table的border-collapse需要设定成separate才会有效果哦! HTML代码: <table cellspacing="0" class="table"> <tr> <th>Fruits</th> <th>Vegetables</th> <th>Rocks</th> </tr> <tr> <td>Apple</td> <td>Celery</td> <td>Granite</td> </tr> <tr> <td>Orange</td> <td>Cabbage</td> <td>Flint</td> </tr> </table> <p><button>COLLAPSE ROW 1</button></p> <p><button>HIDE ROW 1</button></p> <p><button>RESET</button></p> <p>See <a href="http://www.sitepoint.com/12-little-known-css-facts/">article</a> .</p> CSS代码: body { text-align: center; padding-top: 20px; font-family: Arial, sans-serif; } table { border-collapse: separate; border-spacing: 5px; border: solid 1px black; width: 500px; margin: 0 auto; } th, td { text-align: center; border: solid 1px black; padding: 10px; } .vc { visibility: collapse; } .vh { visibility: hidden; } button { margin-top: 5px; } CSS-Trick 网站的Almanac同学说不要用这个属性,因为这个属性存在兼容问题。 我的测试结果是: 在Chrome中,collapse和hidden的表现并无不同(请看bug报告和讨论) 在firefox,opera和ie11中,collpase的工作是正常的,那就是,表格的行被清除了,而且不再占据空间。 我得承认,这个值可能很少会被用到,但是他确实是存在的。 3、background这个简写又有了新值 在css2.1中,background是这5个值的缩写,background-color, background-image, background-repeat, background-attachment, background-position。现在,在css3中,又有三个成员被加进来了,现在总共有8个值,他们是: background: [background-color] [background-image] [background-repeat] [background-attachment] [background-position] / [ background-size] [background-origin] [background-clip]; 请注意那个正斜杠,和font,border-radius类似,这个正斜杠允许你在写完position后加上background-size。 另外,还有两个可选的值是background-origin和background-clip。 实操中语法会变成这个样子 .example { background: aquamarine url(img.png) no-repeat scroll center center / 50% content-box content-box; } 让我们在demo中来一起 感受它: 这些新值在现代浏览器中工作完美,但是你可能需要为不支持的浏览器优雅降级。 4、clip只对absolute元素和fixed元素有效 上边我们谈到了backgrond-clip,现在我们谈谈clip,我们一般是这么写的: .example { clip: rect(110px, 160px, 170px, 60px); } 我们用这个方法来剪切元素的一部分,但是它的前提是这个元素必须是absolute定位的(这里有解释),所以代码变成这样 .example { position: absolute; clip: rect(110px, 160px, 170px, 60px); } 你可以看到当我们切换这个元素absolute定位的时候,clip也会跟着变化: JS代码: CSS代码: HTML代码: 你也可以通过设定position:fixed来让clip变得有效,因为根据规范,fixed元素有资格被当做absolute元素。 5、垂直百分比是根据父层的宽度计算的,而不是父层高度计算的 这个说起来有一点麻烦,你应该知道百分比宽度是根据父层的宽度计算的,但是如果像padding,margin这样的属性用上百分比的时候,最终的结果是根据父层的宽度计算的,而不是根据父层的高度计算。 大家来看这个例子: HTML代码: CSS代码: body { font-family: Arial, sans-serif; padding-top: 30px; text-align: center; } .wrapper { width: 400px; margin: 0 auto; border: solid 1px black; } .box { width: 100px; height: 100px; background: gold; margin-left: auto; margin-right: auto; padding-top: 10%; padding-bottom: 10%; margin-bottom: 5%; } .range { display: block; margin: 20px auto; } output { text-align: center; display: block; font-weight: bold; padding-bottom: 20px; } output span { font-weight: normal; } JS代码: 注意当我们滑动滑块的时候,只是改变了父层容器的宽度,但是padding-bottom的值却产生了变化。 6、border实际上是简写属性的简写 我们都写过这样的语句: .example { border: solid 1px black; } border属性是border-style,border-width,border-color的简写 但是请不要忘了,这三个属性每个属性都包含有自身的简写,比如: .example { border-width: 2px 5px 1px 0; } 这样会让四个border获得不同的宽度,同理,border-color和border-style也是这样: HTML代码: CSS代码: body { font-family: Arial, sans-serif; } .box { width: 150px; height: 150px; margin: 20px auto; border-color: peachpuff chartreuse thistle firebrick; border-style: solid dashed dotted double; border-width: 10px 3px 1px 8px; } p { text-align: center; } 这里的重点是,你没法用border这个属性为四条边做出不同的颜色,宽度,样式,所以属性简写再简写后,表达就变得不那么精确了。 7、text-decoration实际上是三种属性的简写 我知道这篇文章所说的的可能会让你有一点点晕。 根据w3c规范,现在这个语句是符合标准的: a { text-decoration: overline aqua wavy; } text-decoration现在是这三个属性的缩写:text-decoration-line, text-decoration-color和text-decoration-style. 不幸的是,目前只有firefox一家支持这个新属性: HTML代码: CSS代码: body { padding: 30px; text-align: center; font-family: Arial, sans-serif; } a, a:visited { color: blue; background: aqua; -moz-text-decoration-color: aqua; -moz-text-decoration: overline; -moz-text-decoration-style: wavy; text-decoration-color: aqua; text-decoration: overline; text-decoration-style: wavy; } JS代码: 在这个demo中,我们用了类似text-decoration-color这样的写法,我知道这样写很不爽,因为目前很多浏览器不支持,如果我们直接写text-decoration: overline aqua wavy;的话,无疑目前的浏览器识别不了这样的写法,于是只能不解析有,所以为了向下兼容,我们只能这么写了。 8、border-width 支持关键字值 这个并不是那么惊天地泣鬼神,但是除了接受标准的值外(像5px或者1em),border-width同时还接受三个关键字值: medium, thin,和 thick。 实际上,border-width的初始值是medium,下面这个例子中用的是thick: HTML代码: CSS代码: body { font-family: Arial, sans-serif; text-align: center; } .example { width: 100px; height: 100px; margin: 20px auto; background: aqua; border: solid thick red; } 当浏览器渲染这些关键字值得时候,规范并没有要求他们用特定的宽度值,但是在我的测试中,所有的浏览器都是把这三个值转化成了1px,3px,和5px。 9、很少有人用border-image 我曾经写过一篇关于css3的 border-image的文章,这个特性已经被现代浏览器很好的支持了,除了ie10及以下版本。但是有人在意吗? 如果你不喜欢阅读英文,你可以阅读我早前写的一篇关于CSS3的border-image的基础教程。——@大漠 它看起来是一个很优美的特性,允许你创建流动的图片边框,在这个例子中,你可以缩放窗口来观察图片边框的流动。 HTML代码: CSS代码: body { font-family: Arial, sans-serif; text-align: center; } 不幸的是,border-image仍然像一个新奇事物一样并未被很多人使用。但也许我是错的。如果你知道有哪个真实案例中有使用border-image,或者你就使用过它的话,请在评论中让我知道,我会很乐意承认我错了。 10、还存在empty-cells 这样一个属性 这个属性是被广泛支持的,包括ie8,它写起来是这个样子的: table { empty-cells: hide; } 你也许已经知道了,它是用在表格中的,它告诉浏览器是否显示空的单元格。试着点击切换按钮来观察empty-cells的效果: HTML代码: <table cellspacing="0" id="table"> <tr> <th>Fruits</th> <th>Vegetables</th> <th>Rocks</th> </tr> <tr> <td></td> <td>Celery</td> <td>Granite</td> </tr> <tr> <td>Orange</td> <td></td> <td>Flint</td> </tr> </table> <button id="b" data-ec="hide">TOGGLE EMPTY-CELLS</button> <p>See <a href="http://www.sitepoint.com/12-little-known-css-facts/">article</a>.</p> CSS代码: body { text-align: center; padding-top: 20px; font-family: Arial, sans-serif; } table { border: solid 1px black; border-collapse: separate; border-spacing: 5px; width: 500px; margin: 0 auto; empty-cells: hide; background: lightblue; } th, td { text-align: center; border: solid 1px black; padding: 10px; } button { margin-top: 20px; } JS代码: 在这个例子中,需要确保表格的边框是可见的,而且border-collapse没有被设定成 collapsed。 11、font-style 还有一个值是“oblique” 当我们使用font-style属性得时候,经常用到的两个值是normal和italic,但是你还可以给它另一个值oblique: HTML代码: CSS代码: h1 { font-weight: normal; font-family: Georgia, serif; font-style: oblique; text-align: center; font-size: 50px; } h1:nth-child(2) { font-style: italic; } p { font-family: Arial, sans-serif; text-align: center; } 但是它到底是个神马意思呢?还有就是它和italic看起来一样吗? 规范对于oblique是这么解释的: 应用oblique样式,如果没有的话就用italic样式 规范对于italic的解释和oblique基本上差不多,oblique这个词是一个排版术语,表示是在normal的基础上倾斜的字体,而不是真正的斜体。 由于css处理oblique的方式,其实它和italic是通用的,除非这个字体就是一个oblique字体。 而我从未听说过有oblique字体,但是也许我是错的。我的研究是,oblique是当一个字体没有真斜体的时候的一个仿斜体。 所以,如果我没有错的话,这就意味着如果一个字体没有真斜体字体,那么如果我们写了font-style:italic实际上会让字体变成font-style:oblique的形式。 下边这个图可以很直观的知道仿斜体和真斜体的区别。灰色的是oblique仿斜体。 ——@大圆 12个很少被人知道的CSS事实 12、word-wrap和overflow-wrap是等同的 word-wrap不是一个被经常用到的属性,但在某些情况下是非常有用的,一个常见的例子是让长url换行,以免它撑开父容器,例子如下: HTML代码: CSS代码: body { font-family: Arial, sans-serif; text-align: center; } .p { font-size: 24px; text-align: center; width: 200px; margin: 20px auto; border: solid 1px black; min-height: 60px; word-wrap: break-word; } button { display: block; margin: 0 auto; } JS代码: var p = document.getElementById('p'), b = document.getElementById('b'); b.onclick = function () { if (this.getAttribute('data-ww') === 'break-word') { p.style.wordWrap = 'normal'; this.setAttribute('data-ww', 'normal'); } else { p.style.wordWrap = 'break-word'; this.setAttribute('data-ww', 'break-word'); } }; 由于这个属性是微软原创的,所以它被所有的浏览器支持了,包括ie5.5。 尽管它跨浏览器,而且被一贯地支持,W3C依然决定把word-wrap换成overflow-wrap- 我猜是之前的命名有点名不副实? overflow-wrap和word-wrap有着同样的值,而word-wrap被当作是overflow-wrap的一个后补语法。 现在有一些浏览器是支持overflow-wrap的,但这么做貌似是无意义的,因为所有旧的浏览器都把word-wrap解析得很好,而且由于历史原因所有的浏览器都被要求继续支持word-wrap。 我们可以在浏览器升级后开始使用overflow-wrap,但是直到现在,我依然看不到换成新语法的意义何在。 这里边有多少是你不知道的呢? 不知你从这篇文章中有没有学到什么,我希望是这样,也许大多数有经验的css开发者知道很多,但是对于css新手应该会受益多一点。 原文发布时间为:2018年02月27日 原文作者:web前端开发V 本文来源CSDN如需转载请联系原作者
1.文档流 - 所有的元素默认情况下都是在文档流中存在的- 文档流是网页的最底层- 元素在文档流中的特点:- 块元素1.默认宽度是父元素的全部2.默认高度被内容(子元素)撑开3.在页面中自上而下垂直排列- 内联元素1.默认高度和宽度都被内容撑开2.在页面中自左向右水平排列,如果一行不足以容下所有的元素则换到下一行继续从左向右2.浮动- 使用float来设置元素的浮动- 可选值:none 默认值,元素不浮动,就在文档流中left 元素向页面的左侧浮动right 元素向页面的右侧浮动- 浮动特点:1.元素设置浮动以后,会完全脱离文档流,并向页面的左上或右上浮动。直到遇到父元素的边框或其他的父元素时则停止浮动。2.如果浮动元素上边是一个没有浮动的块元素,元素不会超过该块元素。3.浮动元素的浮动位置不能超过他上边浮动的兄弟元素,最多一边齐4.浮动元素不会覆盖文字,文字会围绕在浮动元素的周围,所以可以通过浮动来实现文字环绕图片的效果。- 浮动以后元素会完全脱离文档流,脱离文档流以后元素会具有如下特点:1.块元素不独占一行2.块元素的宽度和高度都被内容撑开3.元素不在文档流占用位置4.内联元素会变成块元素- 高度塌陷- 在文档流中元素的高度默认被子元素撑开,当子元素浮动时,子元素会脱离文档流,此时将不能撑起父元素的高度,会导致父元素的高度塌陷。父元素高度塌陷会导致其他元素的位置上移,导致页面的布局混乱。- 可以通过开启元素的BFC来处理高度塌陷的问题。- BFC叫做Block Formatting Context- 它是一个隐含属性,默认情况是关闭,当开启以后元素会具有如下的特性:1.父元素的垂直外边距不会和子元素重叠2.开启BFC的元素不会被浮动元素覆盖3.父元素可以包含浮动的子元素 ******- 开启BFC的方式很多:1.设置元素浮动2.设置元素绝对定位3.设置元素为inline-block4.将元素的overflow设置为一个非默认值- 一般我们采取副作用比较小的方式overflow:hidden;3.定位- 通过定位可以将元素摆放到页面的任意位置- 使用position来设置元素的定位- 可选值:- static 默认值 元素不开启定位- relative 开启元素的相对定位- absolute 开启元素的绝对定位- fixed 开启元素的固定定位- 相对定位1.相对于元素自身在文档流中的位置进行定位2.相对定位的元素不会脱离文档流,定位元素的性质不会改变,块还是块,内联还是内联3.如果不设置偏移量,元素不会发生任何的变化4.会提升元素的层级- 绝对定位1.相对于离它最近的开启了定位的祖先元素进行定位,如果祖先元素都没有开启定位则相对于浏览器窗口进行定位。2.绝对定位会使元素完全脱离文档流,会改变元素的性质,内联变成块元素,块元素的宽度被内容撑开3.绝对定位的元素如果不设置偏移量,元素的位置不会发生变化4.会提升元素的层级- 固定定位- 固定定位也是一种绝对定位,它的大部分特点都和绝对定位是相同的。- 不同的是:- 固定定位永远相对于浏览器窗口进行定位- 固定定位会固定在浏览器的指定的位置,不会随页面一起滚动- 偏移量- 当元素开启了定位以后,可以通过四个偏移量来设置元素的位置top:相对于定位位置的顶部的偏移量bottom:相对于定位位置的底部的偏移量left:相对于定位位置的左侧的偏移量right:相对于定位位置的右侧的偏移量- 一般只需要使用两个值即可给元素进行定位top lefttop rightbottom leftbottom right- 偏移量也可以指定一个负值,如果是负值则元素会向相反的方向移动- 层级- 当元素开启定位以后,可以通过z-index来设置层级,它需要一个正整数作为参数,值越大层级越高,层级越高越优先显示如果层级一样,则后边的会盖住前边的,父元素永远都不会盖住子元素。- 文档流 < 浮动 < 定位 - 元素的透明使用opacity来设置元素的透明度- 需要一个0-1之间的值- 0 表示完全透明- 1 表示完全不透明IE8及以下的浏览器不支持该样式,需要使用如下方式来设置filter:alpha(opacity=透明度);- 需要一个0-100之间的值- 0 表示完全透明- 100 表示完全不透明 原文发布时间为:2018年04月21日 原文作者:Song-宋-Song 本文来源CSDN如需转载请联系原作者
1. 前期准备 1、Node.js简介 简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。Node.js 的包管理器 npm,是全球最大的开源库生态系统。 2、下载Node.js 打开官网下载链接:https://nodejs.org/en/download/ 我这里下载的是node-v8.9.4-x64.msi,如下图: 四、开始安装###### 1、下载完成后,双击“node-v8.9.4-x64.msi”,开始安装Node.js 2.选择安装目录 安装目录在D:\nodejs\install 3.选择安装组件 是nodejs 是npm包管理工具,类似maven 是添加到系统环境变量 4.安装结束 5.cmd下测试 Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。 C:\Users\Administrator>node -v v8.9.4 C:\Users\Administrator>npm -v 5.6.0 C:\Users\Administrator> 1 2 3 4 5 6 7 8 9 10 node -v 查看nodejs是否安装成功 npm -v查看npm是否安装成功 6.安装完后的目录如下图所示: 原文发布时间为:2018年02月07日 原文作者:九师兄-梁川川 本文来源CSDN如需转载请联系原作者
前言:jQuery下的方法有很多,而且都很实用。比如each方法,我们可以$.each()这样去使用,也可以$('div').each()这样去使用,两者有什么区别呢? var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); } jQuery.each = function(){} 前者是jQuery下的方法,可以直接使用,我们习惯性称为工具方法; -------- jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function(){} } jQuery.fn.each = function(){ } 后者是jQuery原型下的方法,需要实例jQuery对象后使用,我们习惯性称为jQuert实例对象方法。 一、模拟jQuery创建方法、扩展方法。 (function(window,undefined){ var jQ = function(selector){ return new jQ.fn.init(selector); }; jQ.fn = jQ.prototype = { jquery:'2.0.3', //jquery版本号信息 constructor: jQ, //添加构造器属性 length:0, //初始length属性 selector:'', //初始selector属性 init: function(selector){ //初始化jQuery对象 }, toArray: function(){}, get: function(){}, pushStack: function(){}, each: function(){}, ready: function(){}, slice: function(){}, first: function(){}, last: function(){}, eq: function(){}, map: function(){}, end: function(){}, push: function(){}, sort: function(){}, splice: function(){} }; jQ.fn.init.prototype = jQ.fn; jQ.extend = jQ.fn.extend = function(){ } jQ.extend({ each: function(){}, type: function(){}, parseJSON: function(){} /*.............*/ }); jQ.fn.extend({ attr: function(){}, removeAttr: function(){}, addClass: function(){}, removeClass: function(){}, toggleClass: function(){}, val: function(){}, css: function(){}, on: function(){} /*.............*/ }); window.$$ = jQ; })( window ); ①、像jQ原型下有一些比较重要的方法,而且不会经常需要修改、优化,或者删除的方法。 ②、而如果要继续添加、扩展方法。都是通过extend()去扩展方法。 jQ.extend = jQ.fn.extend = function(){ } ③、扩展工具方法 jQ.extend({ each: function(){}, type: function(){}, parseJSON: function(){} /*.............*/ }); ④、扩展jQuery对象方法 jQ.fn.extend({ attr: function(){}, removeAttr: function(){}, addClass: function(){}, removeClass: function(){}, toggleClass: function(){}, val: function(){}, css: function(){}, on: function(){} /*.............*/ }); 这样使得代码的更好维护,如果要添加方法只需要在extend中去操作,而不需要在核心代码中去操作。 二、extend扩展方法源码 在研究extend源码之前,来看看extend几种用法。 1、简单的说extend有四种用法: ①、扩展jquery工具方法 ②、扩展jQuery实例对象方法 ③、浅拷贝 ④、深拷贝 2、进行细分的话,extend有以下几种情况 var obj1 = { name:'freddy', hobit:["basketball"], sex:null }; var obj2 = { age:18 }; var obj3 = {}; var obj4 = {}; var obj5 = {}; $.extend({}); //①扩jQuery展工具方法 $.fn.extend({}); //②扩展jQuery实例对象方法 $.extend(obj3,obj1); //③浅拷贝 $.extend(obj3,obj1,obj2); //③浅拷贝多个对象 $.extend(true,obj4,obj1); //④深拷贝 $.extend(true,obj4,obj1,obj2); //④深拷贝多个对象 $.extend(obj5,{name:'nick'},{age:18}); //⑤扩展对象 console.log(obj3); console.log(obj4); console.log(obj5); 对于浅拷贝、深拷贝不熟悉的可以看看我以前的文章【JavaScript】对象引用、浅拷贝、深拷贝详解 3、直接上extend源码(这里的目标对象为“被扩展的对象”或者“拷贝别人”的对象) jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, //设置第一个参数为目标对象 i = 1, //i为1是浅拷贝情况下,被拷贝的对象是arguments[1],从二个参数开始 length = arguments.length, deep = false; //默认是浅拷贝 //$(true,arr4,arr1) || $(true,arr4,arr1,arr2); if ( typeof target === "boolean" ) { //深拷贝情况第一个参数为true,布尔类型 deep = target; target = arguments[1] || {}; //目标对象变成第二个参数了 i = 2; //被拷贝对象是arguments[2],从第三个参数开始 } //看目标对象是否是对象 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } //$.extend({}) || $.fn.extend({}) 扩展方法 if ( length === i ) { //只有一个参数的情况 target = this; //目标对象变成了$ 或者 $.fn --i; //i变成0 } for ( ; i < length; i++ ) { //for循环用于解决->拷贝多个对象的情况 if ( (options = arguments[ i ]) != null ) { //如果该参数对象不为undefined或null for ( name in options ) { src = target[ name ]; //保存目标对象属性 copy = options[ name ]; //保存该属性的值 //如果出现$.extend(obj1,{ name:obj1 }); 跳过本次循环 if ( target === copy ) { continue; } //如果该属性下的值是"对象自变量"或者"数组",就进行深拷贝 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { //深拷贝 if ( copyIsArray ) { //如果该属性下的值是"数组" copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { //如果该属性下的值是"对象自变量" clone = src && jQuery.isPlainObject(src) ? src : {}; } target[ name ] = jQuery.extend( deep, clone, copy ); //然后进行递归操作 } else if ( copy !== undefined ) { //浅拷贝 target[ name ] = copy; } } } } return target; }; 注释写上去之后,一些都明了了,也并没有什么难点。如果有不明白的地方可以下方留言。 三、扩展方法 <body> <script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script> <script> $.extend({ freddy: function(){ console.log('扩展jQuery工具方法'); } }); $.fn.extend({ freddy: function(){ console.log('扩展jQuery实例对象方法'); } }); $.freddy(); $(document).freddy(); </script> </body> 运行结果 这样是不是很方面,就算不熟悉jquery源码,也能很快扩展出自己想要的方法。不过这里要注意的是,如果扩展的方法名如果跟jQuery原生的方法名重名(如css,attr),会发生我们扩展的方法覆盖了原生的jQuery方法。 原文发布时间为:2018年06月30日 原文作者:穆弘 本文来源CSDN如需转载请联系原作者
前言:jQuery下的方法有很多,而且都很实用。比如each方法,我们可以$.each()这样去使用,也可以$('div').each()这样去使用,两者有什么区别呢? var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); } jQuery.each = function(){} 前者是jQuery下的方法,可以直接使用,我们习惯性称为工具方法; -------- jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function(){} } jQuery.fn.each = function(){ } 后者是jQuery原型下的方法,需要实例jQuery对象后使用,我们习惯性称为jQuert实例对象方法。 一、模拟jQuery创建方法、扩展方法。 (function(window,undefined){ var jQ = function(selector){ return new jQ.fn.init(selector); }; jQ.fn = jQ.prototype = { jquery:'2.0.3', //jquery版本号信息 constructor: jQ, //添加构造器属性 length:0, //初始length属性 selector:'', //初始selector属性 init: function(selector){ //初始化jQuery对象 }, toArray: function(){}, get: function(){}, pushStack: function(){}, each: function(){}, ready: function(){}, slice: function(){}, first: function(){}, last: function(){}, eq: function(){}, map: function(){}, end: function(){}, push: function(){}, sort: function(){}, splice: function(){} }; jQ.fn.init.prototype = jQ.fn; jQ.extend = jQ.fn.extend = function(){ } jQ.extend({ each: function(){}, type: function(){}, parseJSON: function(){} /*.............*/ }); jQ.fn.extend({ attr: function(){}, removeAttr: function(){}, addClass: function(){}, removeClass: function(){}, toggleClass: function(){}, val: function(){}, css: function(){}, on: function(){} /*.............*/ }); window.$$ = jQ; })( window ); ①、像jQ原型下有一些比较重要的方法,而且不会经常需要修改、优化,或者删除的方法。 ②、而如果要继续添加、扩展方法。都是通过extend()去扩展方法。 jQ.extend = jQ.fn.extend = function(){ } ③、扩展工具方法 jQ.extend({ each: function(){}, type: function(){}, parseJSON: function(){} /*.............*/ }); ④、扩展jQuery对象方法 jQ.fn.extend({ attr: function(){}, removeAttr: function(){}, addClass: function(){}, removeClass: function(){}, toggleClass: function(){}, val: function(){}, css: function(){}, on: function(){} /*.............*/ }); 这样使得代码的更好维护,如果要添加方法只需要在extend中去操作,而不需要在核心代码中去操作。 二、extend扩展方法源码 在研究extend源码之前,来看看extend几种用法。 1、简单的说extend有四种用法: ①、扩展jquery工具方法 ②、扩展jQuery实例对象方法 ③、浅拷贝 ④、深拷贝 2、进行细分的话,extend有以下几种情况 var obj1 = { name:'freddy', hobit:["basketball"], sex:null }; var obj2 = { age:18 }; var obj3 = {}; var obj4 = {}; var obj5 = {}; $.extend({}); //①扩jQuery展工具方法 $.fn.extend({}); //②扩展jQuery实例对象方法 $.extend(obj3,obj1); //③浅拷贝 $.extend(obj3,obj1,obj2); //③浅拷贝多个对象 $.extend(true,obj4,obj1); //④深拷贝 $.extend(true,obj4,obj1,obj2); //④深拷贝多个对象 $.extend(obj5,{name:'nick'},{age:18}); //⑤扩展对象 console.log(obj3); console.log(obj4); console.log(obj5); 对于浅拷贝、深拷贝不熟悉的可以看看我以前的文章【JavaScript】对象引用、浅拷贝、深拷贝详解 3、直接上extend源码(这里的目标对象为“被扩展的对象”或者“拷贝别人”的对象) jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, //设置第一个参数为目标对象 i = 1, //i为1是浅拷贝情况下,被拷贝的对象是arguments[1],从二个参数开始 length = arguments.length, deep = false; //默认是浅拷贝 //$(true,arr4,arr1) || $(true,arr4,arr1,arr2); if ( typeof target === "boolean" ) { //深拷贝情况第一个参数为true,布尔类型 deep = target; target = arguments[1] || {}; //目标对象变成第二个参数了 i = 2; //被拷贝对象是arguments[2],从第三个参数开始 } //看目标对象是否是对象 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } //$.extend({}) || $.fn.extend({}) 扩展方法 if ( length === i ) { //只有一个参数的情况 target = this; //目标对象变成了$ 或者 $.fn --i; //i变成0 } for ( ; i < length; i++ ) { //for循环用于解决->拷贝多个对象的情况 if ( (options = arguments[ i ]) != null ) { //如果该参数对象不为undefined或null for ( name in options ) { src = target[ name ]; //保存目标对象属性 copy = options[ name ]; //保存该属性的值 //如果出现$.extend(obj1,{ name:obj1 }); 跳过本次循环 if ( target === copy ) { continue; } //如果该属性下的值是"对象自变量"或者"数组",就进行深拷贝 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { //深拷贝 if ( copyIsArray ) { //如果该属性下的值是"数组" copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { //如果该属性下的值是"对象自变量" clone = src && jQuery.isPlainObject(src) ? src : {}; } target[ name ] = jQuery.extend( deep, clone, copy ); //然后进行递归操作 } else if ( copy !== undefined ) { //浅拷贝 target[ name ] = copy; } } } } return target; }; 注释写上去之后,一些都明了了,也并没有什么难点。如果有不明白的地方可以下方留言。 三、扩展方法 <body> <script src="https://cdn.bootcss.com/jquery/2.0.3/jquery.js"></script> <script> $.extend({ freddy: function(){ console.log('扩展jQuery工具方法'); } }); $.fn.extend({ freddy: function(){ console.log('扩展jQuery实例对象方法'); } }); $.freddy(); $(document).freddy(); </script> </body> 运行结果 这样是不是很方面,就算不熟悉jquery源码,也能很快扩展出自己想要的方法。不过这里要注意的是,如果扩展的方法名如果跟jQuery原生的方法名重名(如css,attr),会发生我们扩展的方法覆盖了原生的jQuery方法。 原文发布时间为:2018年06月30日 原文作者:穆弘 本文来源CSDN如需转载请联系原作者
1、前言 最流行的 JS 库,应用范围广: web、安卓、IOS、浏览器端、服务器端等 React 笔者很早就接触了, 出于情怀,先选择国产的 Vue,后来感到有点鸡肋。 或许是作为主要使用Java的后端开发人员,对React的面向组件的开发逻辑,感到轻车熟路 React 好比后端开发语言 Java(严谨完整)、Vue 好比后端开发语言 Python(力求简洁) 或许是出自强迫症,一向严谨的秉性,对那些莫名的简洁,感到些许不安 做项目最基本的技能来了,CRUD UI:layui,国产,简单,还自带简单过渡 JS交互:React 后台:SpringBoot:https://github.com/larger5/CRUDspringboot.git 2、演示 2.1、主页 2.2、删除 2.3、新增 2.4、修改 2.5、查询 3、CRUD代码 3.1、主页 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ITAEM</title> <!-- React的核心库 --> <script src="js/react.development.js"></script> <!-- 提供操作DOM的react扩展库 --> <script src="js/react-dom.development.js"></script> <!-- 解析JSX语法代码转为纯JS语法代码的库 --> <script src="js/babel.min.js"></script> <!-- 发送 ajax 请求--> <script src="js/fetch.js"></script> <!-- LayUI CSS 样式 --> <link type="text/css" rel="stylesheet" href="layui/css/layui.css"> </head> <body> <div id="cun"></div> <script type="text/babel"> class CrudComponent extends React.Component{ constructor(props){ super(props) this.state={ users:[] } } componentDidMount () {// 在此方法中启动定时器/绑定监听/发送ajax请求 const getAllUsersUrl="http://120.79.197.130/crudTest-0.0.1-SNAPSHOT/user/getAllUsers" fetch(getAllUsersUrl,{method:"GET"}) .then(response=>response.json()) .then(data=>{ console.log(data) this.setState({ users:data }) }) } getUserByUserName(){ const getUserByUserName="http://120.79.197.130/crudTest-0.0.1-SNAPSHOT/user/getUserByUserName/"+this.text1.value fetch(getUserByUserName,{method:"GET"}) .then(response=>response.json()) .then(data=>{ console.log(data) this.setState({ users:data }) }) } deleteUserById(id,userName){ if(window.confirm("确定要删除 "+userName+" 吗?")){ const getUserById="http://120.79.197.130/crudTest-0.0.1-SNAPSHOT/user/deleteUserById/"+id fetch(getUserById,{method:"DELETE"}) .then(response=>response.json()) .then(data=>{ console.log(data) this.setState({ users:data }) }) } } addUser(){ window.location.href="http://localhost:63342/ReacTest/pageTest/10.CRUD.add.html?_ijt=ti5s31h50tdkekgf4ivl57dd48" } updateUser(id){ window.location.href="http://localhost:63342/ReacTest/pageTest/10.CRUD.update.html?_ijt=ot6mkr486r7iothtqcfcbmvo44#"+id } render(){ return ( <div> <div className="layui-row layui-col-space2"> <div className="layui-col-md1"> <input type="text" id="query" name="q" required lay-verify="required" placeholder="用户名" className="layui-input" ref={text1=>this.text1=text1} /> </div> <div className="layui-col-md1"> <button id="btn2" onClick={this.getUserByUserName.bind(this)} className="layui-btn"> <i className="layui-icon">&#xe602;</i>搜索 </button> </div> </div> <table className="layui-table"> <thead> <tr> <th>id</th> <th>用户名</th> <th>密码</th> <th>修改</th> <th>删除</th> </tr> </thead> <tbody> { this.state.users.map( (user, index) => <tr key={user.id}> <td>{user.id}</td> <td>{user.userName}</td> <td>{user.password}</td> <td> <button className="layui-btn layui-btn-normal" onClick={this.updateUser.bind(this,user.id)}> <i className="layui-icon">&#xe642;</i>修改 </button> </td> <td> <button className="layui-btn layui-btn-danger" onClick={this.deleteUserById.bind(this,user.id,user.userName)}> <i className="layui-icon">&#xe640;</i>删除 </button> </td> </tr>) } </tbody> </table> <button className="layui-btn layui-btn-warm" onClick={this.addUser.bind(this)}> <i className="layui-icon">&#xe654;</i> 添加 </button> </div> ) } } ReactDOM.render(<CrudComponent/>,document.getElementById("cun")) </script> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 3.2、增加页 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ITAEM</title> <!-- React的核心库 --> <script src="js/react.development.js"></script> <!-- 提供操作DOM的react扩展库 --> <script src="js/react-dom.development.js"></script> <!-- 解析JSX语法代码转为纯JS语法代码的库 --> <script src="js/babel.min.js"></script> <!-- 发送 ajax 请求--> <script src="js/fetch.js"></script> <!-- LayUI CSS 样式 --> <link type="text/css" rel="stylesheet" href="layui/css/layui.css"> </head> <body> <div id="cun"></div> <script type="text/babel"> class CrudComponent extends React.Component{ constructor(props){ super(props) this.state={ users:[] } } addUser(){ const insertUser="http://120.79.197.130/crudTest-0.0.1-SNAPSHOT/user/insertUser/"+this.userName.value+"/"+this.password.value fetch(insertUser,{method:"POST"}) .then(response=>response.json()) .then(data=>{ console.log(data) }) alert("添加成功") window.location.href="http://localhost:63342/ReacTest/pageTest/10.CRUD.html?_ijt=qgmiem8qco2usprrmlul78r7vu" } render(){ return ( <div> <fieldset className="layui-elem-field"> <legend>Add User</legend> <div className="layui-field-box"> <div className="layui-row layui-col-space2"> <div className="layui-col-md1"> <input type="text" id="userName" name="userName" required lay-verify="required" placeholder="用户名" className="layui-input" ref={userName=>this.userName=userName} /> </div> <hr className="layui-bg-green" /> <div className="layui-col-md1"> <input type="text" id="password" name="password" required lay-verify="required" placeholder="密码" className="layui-input" ref={password=>this.password=password} /> </div> <hr className="layui-bg-green" /> <div className="layui-col-md1"> <button id="btn2" className="layui-btn" onClick={this.addUser.bind(this)}> <i className="layui-icon">&#xe608;</i>添加 </button> </div> </div> </div> </fieldset> </div> ) } } ReactDOM.render(<CrudComponent/>,document.getElementById("cun")) </script> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 3.3、修改页 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>ITAEM</title> <!-- React的核心库 --> <script src="js/react.development.js"></script> <!-- 提供操作DOM的react扩展库 --> <script src="js/react-dom.development.js"></script> <!-- 解析JSX语法代码转为纯JS语法代码的库 --> <script src="js/babel.min.js"></script> <!-- 发送 ajax 请求--> <script src="js/fetch.js"></script> <!-- LayUI CSS 样式 --> <link type="text/css" rel="stylesheet" href="layui/css/layui.css"> </head> <body> <div id="cun"></div> <script type="text/babel"> class CrudComponent extends React.Component{ constructor(props){ super(props) } componentDidMount () { var userId = location.hash; const getUserByUserId="http://120.79.197.130/crudTest-0.0.1-SNAPSHOT/user/getUserByUserId/"+userId.substring(1) fetch(getUserByUserId,{method:"GET"}) .then(response=>response.json()) .then(data=>{ console.log(data[0]) this.id.value=data[0].id this.userName.value=data[0].userName this.password.value=data[0].password }) } updateUser(){ const getUserByUserId="http://120.79.197.130/crudTest-0.0.1-SNAPSHOT/user/updateUser/"+this.id.value+"/"+this.userName.value+"/"+this.password.value fetch(getUserByUserId,{method:"PUT"}) .then(response=>response.json()) .then(data=>{ console.log(data) }) alert("修改成功") window.location.href="http://localhost:63342/ReacTest/pageTest/10.CRUD.html?_ijt=gdi6jpm674miigqtmehhe26j0u" } render(){ return ( <div> <fieldset className="layui-elem-field"> <legend>Update User</legend> <div className="layui-field-box"> <div className="layui-row layui-col-space2"> <div className="layui-col-md1"> <input type="text" id="id" name="id" required lay-verify="required" placeholder="id" className="layui-input" ref={id=>this.id=id} disabled="true" /> </div> <hr className="layui-bg-green" /> <div className="layui-col-md1"> <input type="text" id="userName" name="userName" required lay-verify="required" placeholder="用户名" className="layui-input" ref={userName=>this.userName=userName} /> </div> <hr className="layui-bg-green" /> <div className="layui-col-md1"> <input type="text" id="password" name="password" required lay-verify="required" placeholder="密码" className="layui-input" ref={password=>this.password=password} /> </div> <hr className="layui-bg-green" /> <div className="layui-col-md1"> <button id="btn2" className="layui-btn" onClick={this.updateUser.bind(this)}> <i className="layui-icon">&#xe642;</i>修改 </button> </div> </div> </div> </fieldset> </div> ) } } ReactDOM.render(<CrudComponent/>,document.getElementById("cun")) </script> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 4、最后 4.1、JS基础 回调函数:你没有调用,它自己调用 在HTML里边,一个{}表示里边写JS代码,两个即{{}}表示里边为JS对象 4.2、React 工程化 npm install -g create-react-app create-react-app react-app cd react-app npm start 4.3、几种常见的Ajax请求: ① $.ajax ② jsonp ③ axios ④ fetch ⑤ vue-resource(基于Vue) 4.4、React编程思想: 面向组件编程,使用虚拟DOM、diff算法,以最小代价渲染、更新页面 原文发布时间为:2018年05月13日 原文作者:larger5 本文来源CSDN如需转载请联系原作者
我们通常会通过PS,美图秀秀等来编辑照片,制作比较符合意境的的效果图片(图骗),但是编辑器和PS的切换是有成本的,如果能在编辑器中快捷并且批量的处理图片岂不是很好。这篇文章没有多么高深的代码,只是一些平时容易忽略并且很受用的小技巧。 修图利器之 CSS Filters P图怎么能少了滤镜呢,css提供了很多种滤镜: drop-shadow sepia blur hue-rotate invert brightness contrast opacity grayscale saturate drop-shadow 下落式阴影 添加阴影效果可不只有text-shadow和box-shadow哦,text-shadow是为文字添加阴影,box-shadow给一个元素添加阴影,drop-shadow在图片是非png情况下和box-shadow有些相似,然而png图片才是她大放异彩的地方 拿一张jpg图片来举个栗子看下drop-shadow 和 box-shadow的区别: //从左往右依次是原图,添加drop-shadow-jpg,添加box-shadow .drop-shadow-jpg{ -webkit-filter: drop-shadow(10px 10px 10px rgba(255,235,59,0.74)); } .box-shadow{ box-shadow: 10px 10px 10px rgba(255,235,59,0.74); } drop-shadow明显更柔和一些,并且图片的上面和左边也是有阴影的哦。 再来看下drop-shadow在png图片的表现吧,左边为原图: .drop-shadow-png{ -webkit-filter: drop-shadow(10px 10px 10px rgba(255,235,59,0.74)); } 因为png图片背景是透明的,所以drop-shadow直接作用于图片的内容,图中的小女孩是不是更萌了呢。 sepia 乌贼墨,深褐色,深棕色影 如果想要个老照片效果 .sepia-50{ -webkit-filter: sepia(50%); } .sepia-100{ -webkit-filter: sepia(100%) } //safari浏览器不支持 参数可以是小数也可以是百分比,为0的时候是左边原图的效果,1或100%是最右的效果图哦 blur 模糊 背景图片太清晰有喧宾夺主之嫌了?可以设置模糊的效果啊 .blur{ -webkit-filter: blur(3px); } blur用来给图像设置高斯模糊。参数值设定高斯函数的标准差,或者是屏幕上以多少像素融在一起,这个值设置为百分比除外的css长度值,默认是0效果为左边的原图,值越大越模糊,上面的图片设置成100px时就什么都没有了。 opacity 透明度 opacity会调整图片的透明度,这个和filter中的opacity效果是一样哒,但是并不是一个属性呢,因为他们是可以叠加使用的 .opacity-20{ opacity: 0.2; } .filter-opacity-20{ filter:opacity(0.2) } .opacity-both{ opacity: 0.2; filter:opacity(0.2) } 他们接受的参数也是有一些差别的,opacity只能接受小数,filter:opactiy()既可以接受小数也可以接受百分比,值越小越透明。 hue-rotate 色相旋转 hue-rotate通过改变图片的色相来改变图片 .hue-rotate-90{ -webkit-filter: hue-rotate(90deg); } .hue-rotate-270{ -webkit-filter: hue-rotate(270deg); } hue-rotate 参数是一个角度值,他会接受这个值并把图片中的颜色的色相做对应的旋转 invert 反转 invert会把图片上的所有颜色进行反转,如果是希望做个相机底片效果,真的是太合适了 .invert-20{ filter: invert(20%); } .invert-100{ filter: invert(100%) } 和hue-rotate相比,直接反转就用不着接受颜色变化的角度了,但是你可以设置0~100%来控制反转的程度 saturate 饱和度 色彩三要素色相,明度,饱和度。饱和度也即颜色的纯度,彩度。无彩色的色饱和度为0,也就是上面的grayscale灰度值为1的时候,饱和度越高,颜色中的灰度越低。 .saturate-50{ filter: saturate(50%); } .saturate-200{ filter: saturate(200%); } 饱和度100%时为左一原图,接受大于100%的值。 brightness 亮度 说完了色相和饱和度再来看看brightness,brightness给图片应用一种线性乘法来调整整个图片的亮度,效果和手机电脑上的的亮度调节是一样的 .brightness-4{ filter:brightness(40%) } .brightness-8{ filter:brightness(80%) } brightness的参数可以用百分比来表示也可以用小数来表示,当参数值为0的时候整个图片都是黑色的了,超过100%的时候比原图更亮一些 contrast 对比度 contrast用来调整图像的对比度 .contrast-50 { filter: contrast(50%) } .contrast-200{ filter:contrast(200%) } contrast的参数接受百分比形式的数值也接受小数形式的,值为0 的时候是整个图片都是灰黑色的,为1时是原图,值越大对比度越大,默认值为1。 grayscale 灰度模式 有格调的灰度模式开启 .gray-scale-50{ filter:grayscale(50%) } .gray-scale-100{ filter:grayscale(100%) } grayscale的参数接受百分比和小数,默认参数是100%,完全灰度,1以内的值越大越靠近完全灰度,大于等于1的值的效果是一样哒 修图利器之 Blend Modes CSS3的混合模式决定了多个图片/图层叠加在一起的时候显示的效果。关于混合模式的算法可以在维基百科上了解。不同的模式值对应了不同的算法,最后决定了图片混合模式效果。相关的两个属性是mix-blend-mode和background-blend-mode,background-blend-mode主要是作用于同一个background属性下的背景图片或者背景色。 混合模式的值的对应效果可以完全类比PS中图层模式效果,他们的对应关系是: normal 正常模式 multiply 正片叠底模式 screen 滤色模式 overlay 叠加模式 darken 变暗模式 lighten 变亮模式 color-burn 颜色加深模式 hard-light 强光模式 soft-light 柔光模式 difference 差值模式 exclusion 排除模式 hue 色相模式 saturation 饱和度模式 color 颜色模式 luminosity 亮度模式 mix-blend-mode 式 mix-blend-mode主要作用是把目标元素和其下方的背景元素混合。 图片来自于caniuse.com 快速开始: 这是两张原图 <div class="mix-blend-mode"> <img src="./images/girl.jpg" alt="girl.jpg" > <img src="./images/minion.jpg" alt="minion.jpg" > </div> /*让两张图片重叠在一起*/ .mix-blend-mode{ position:relative } .mix-blend-mode img{ position:absolute } 然后就可以给小黄人图片添加mix-blend-mode啦,因为小女孩图片排在小黄人下面,所以如果在不给小黄人设置mix-blend-mode的情况下只给小女孩图片添加效果的话是看不到任何效果的。 .mix-normal{ mix-blend-mode: normal; } .mix-color{ mix-blend-mode: color; } .mix-color-burn{ mix-blend-mode:color-burn; } .mix-color-dodge{ mix-blend-mode: color-dodge; } .mix-darken{ mix-blend-mode: darken; } .mix-difference{ mix-blend-mode: difference; } .mix-exclusion{ mix-blend-mode: exclusion; } .mix-hard-light{ mix-blend-mode: hard-light; } .mix-hue{ mix-blend-mode: hue; } .mix-inherit{ mix-blend-mode: inherit; } .mix-initial{ mix-blend-mode: initial; } .mix-lighten{ mix-blend-mode: lighten; } .mix-luminosity{ mix-blend-mode: luminosity; } .mix-overlay{ mix-blend-mode: overlay; } .mix-saturation{ mix-blend-mode: saturation; } .mix-screen{ mix-blend-mode: screen; } .mix-soft-light{ mix-blend-mode: soft-light; } .mix-unset{ mix-blend-mode: unset; } 添加了mix-blend-mode属性的图片除了可以对其下面的图片叠加,还可以对其背景色叠加,左一为原图,依次给右边4张图片添加下面css中的样式,并且给他们的父元素设置蓝色背景,然后,各种艺术形态的小黄人出现了! .mix-background-lighten{ mix-blend-mode: lighten; } .mix-background-screen{ mix-blend-mode: screen; } .mix-background-difference{ mix-blend-mode: difference; } .mix-background-luminosity{ mix-blend-mode: luminosity; } background-blend-mode 兼容性如下: 图片来自于caniuse.com background-blend-mode顾名思义是作用于background-image,background-color的。并且是写在一个background属性后面的图片,颜色哦。 .background-blend-mode-self{ background: url(./images/g.jpg) #673AB7 no-repeat; background-blend-mode: unset; } .background-blend-mode-color{ background: url(./images/g.jpg) #673AB7 no-repeat; background-blend-mode: screen; } .background-blend-mode-luminosity{ background: url(./images/g.jpg) #673AB7 no-repeat; background-blend-mode: luminosity; } .background-blend-mode-exclusion{ background: url(./images/g.jpg) #673AB7 no-repeat; background-blend-mode: exclusion; } .background-blend-mode-overlay{ background: url(./images/g.jpg) #673AB7 no-repeat; background-blend-mode: overlay; } .background-blend-mode-soft-light{ background: url(./images/g.jpg) #673AB7 no-repeat; background-blend-mode: soft-light; } 篇幅有限,其他的background-blend-mode效果就不贴代码啦。 代码地址 如何用CSS修出好看的照片 参考文献 css filters Blend modes - Wikipedia 其实这些功能综合运用会有很神奇的效果,后续会写文章介绍哒。 原文发布时间为:2017年12月15日 原文作者:如梦令 本文来源前端外刊如需转载请联系原作者
1. 前言 对于一张网页,我们往往希望它是结构良好,内容清晰的,这样搜索引擎才能准确地认知它。 而反过来,又有一些情景,我们不希望内容能被轻易获取,比方说电商网站的交易额,教育网站的题目等。因为这些内容,往往是一个产品的生命线,必须做到有效地保护。这就是爬虫与反爬虫这一话题的由来。 2. 常见反爬虫策略 但是世界上没有一个网站,能做到完美地反爬虫。 如果页面希望能在用户面前正常展示,同时又不给爬虫机会,就必须要做到识别真人与机器人。因此工程师们做了各种尝试,这些策略大多采用于后端,也是目前比较常规单有效的手段,比如: User-Agent + Referer检测 账号及Cookie验证 验证码 IP限制频次 而爬虫是可以无限逼近于真人的,比如: chrome headless或phantomjs来模拟浏览器环境 tesseract识别验证码 代理IP淘宝就能买到 所以我们说,100%的反爬虫策略?不存在的。 更多的是体力活,是个难易程度的问题。 不过作为前端工程师,我们可以增加一下游戏难度,设计出一些很(sang)有(xin)意(bing)思(kuang)的反爬虫策略。 3. 前端与反爬虫 3.1 FONT-FACE拼凑式 例子:猫眼电影 猫眼电影里,对于票房数据,展示的并不是纯粹的数字。 页面使用了font-face定义了字符集,并通过unicode去映射展示。也就是说,除去图像识别,必须同时爬取字符集,才能识别出数字。 并且,每次刷新页面,字符集的url都是有变化的,无疑更大难度地增加了爬取成本。 3.2 BACKGROUND拼凑式 例子:美团 与font的策略类似,美团里用到的是background拼凑。数字其实是图片,根据不同的background偏移,显示出不同的字符。 并且不同页面,图片的字符排序也是有区别的。不过理论上只需生成0-9与小数点,为何有重复字符就不是很懂。 页面A: 页面B: 3.3 字符穿插式 例子:微信公众号文章 某些微信公众号的文章里,穿插了各种迷之字符,并且通过样式把这些字符隐藏掉。 这种方式虽然令人震惊…但其实没有太大的识别与过滤难度,甚至可以做得更好,不过也算是一种脑洞吧。 对了,我的手机流量可以找谁报销吗? 3.4 伪元素隐藏式 例子:汽车之家 汽车之家里,把关键的厂商信息,做到了伪元素的content里。 这也是一种思路:爬取网页,必须得解析css,需要拿到伪元素的content,这就提升了爬虫的难度。 3.5 元素定位覆盖式 例子:去哪儿 还有热爱数学的去哪儿,对于一个4位数字的机票价格,先用四个i标签渲染,再用两个b标签去绝对定位偏移量,覆盖故意展示错误的i标签,最后在视觉上形成正确的价格… 这说明爬虫会解析css还不行,还得会做数学题。 3.6 IFRAME异步加载式 例子:网易云音乐 网易云音乐页面一打开,html源码里几乎只有一个iframe,并且它的src是空白的:about:blank。接着js开始运行,把整个页面的框架异步塞到了iframe里面… 不过这个方式带来的难度并不大,只是在异步与iframe处理上绕了个弯(或者有其他原因,不完全是基于反爬虫考虑),无论你是用selenium还是phantom,都有API可以拿到iframe里面的content信息。 3.7 字符分割式 例子:全网代理IP 在一些展示代理IP信息的页面,对于IP的保护也是大费周折。 他们会先把IP的数字与符号分割成dom节点,再在中间插入迷惑人的数字,如果爬虫不知道这个策略,还会以为自己成功拿到了数值;不过如果爬虫注意到,就很好解决了。 3.8 字符集替换式 例子:去哪儿移动侧 同样会欺骗爬虫的还有去哪儿的移动版。 html里明明写的3211,视觉上展示的却是1233。原来他们重新定义了字符集,3与1的顺序刚好调换得来的结果… 原文发布时间为:2017年07月09日 原文作者:Litten 本文来源微信如需转载请联系原作者
使用meta标签:viewport viewport是用户网页的可视区域。翻译为中文叫做“视区” 手机浏览器是把页面放在一个虚拟的“窗口”(viewpoint)中,通常这个虚拟的“窗口”(viewport)比屏幕宽,这样就不用把每个网页挤到很小的窗口中,用户可以通过平移和缩放来看网页的不同部分。 viewport的代码如下: <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/> 每个属性的介绍如下: 属性名 取值 描述 width 正整数 或 device-width 定义视口的宽度,单位为像素 height 正整数 或 device-height 定义视口的高度,单位为像素,一般不用 initial-scale [0.0 - 10.0] 定义初始缩放值 minimun-scale [0.0 - -10.0] 定义缩小最小比例,它必须小于或等于maximun-scale的设置 maximun-scale [0.0 - 10.0] 定义放大最大比例,它必须大于或等于minimun-scale设置 user-scalable yes/no 定义是否允许用户手动缩放页面,默认值yes 使用css3单位:rem em是CSS3新增的一个相对单位(root em,根em),使用rem为元素设定字体大小时,是相对大小,但相对的只是HTML根元素。通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。 目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。下面就是一个例子: p {font-size:14px; font-size:.875rem;} 默认html的front-size是16px,即1rem=16px,如果某div宽度为32px你可以设置为2rem。 通常情况下,为了便于计算数值则使用62.5%,即默认的10px作为技术。当然这个基数可以为任何数值,视具体情况而定。设置方法如下: html { font-size:62.5%(10/16*100%) } 具体不同屏幕下的规则定义,即基数的定义方式:可以通过CSS定义,不同宽度范围里定义不同的基数值,当然也可以通过js一次定义方法如下: (function (doc, win) { var docEl = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function () { var clientWidth = docEl.clientWidth; if (!clientWidth) return; docEl.style.fontSize = 20 * (clientWidth / 320) + 'px'; //其中“20”根据你设置的html的font-size属性值做适当的变化 }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener('DOMContentLoaded', recalc, false); })(document, window); 使用媒体查询 媒体查询也是css3的方法,我们要解决的问题是适应手机屏幕,这个媒体查询正是为解决这个问题而生。媒体查询的功能就是为不同的媒体设置不同的css样式,这里的“媒体”包括页面尺寸,设备屏幕尺寸等。 例如:如果浏览器窗口小于 500px, 背景将变为浅蓝色: @media only screen and (max-width: 500px) { body { background-color: lightblue; } } 使用百分比 百分比指的是父元素,所有百分比都是这样的。子元素宽度50%,那么父元素的宽度就是100%; 所以body默认宽度是屏幕宽度(PC中指的是浏览器宽度)子孙元素按百分比定位(或指定尺寸)就可以了,这只适合布局简单的页面,复杂的页面实现很困难。 原文发布时间为:2017年12月24日 原文作者:娜娜娜娜 本文来源前端乱炖如需转载请联系原作者
各种页面常见布局+知名网站实例分析+相关阅读推荐 阅前必看:本文总结了各种常见的布局实现,每个方法的优缺点分析往后在github上陆续补充。还有就是这篇文章没提到的其他布局,待本人后续想到或遇到定会在github上及时更新。 由于文章篇幅较长,排版有些混乱,希望别介意哈。掘金PC端是会自动生成目录的,为了方便移动端阅读,还特意做了个锚点目录,一个个标题重写,真心累!(==后来发现掘金对文章的标题经过处理的,锚点不生效,在其他网站没问题的,移动端可以进去github的在线demo阅读)。各位读者如果发现问题或者有什么意见,欢迎提出!——欢迎收藏!欢迎Star! from github github.com/Sweet-KK/cs… 本文原创,转载请标明出处,摘要引流则随意。 目录 注:PC端推荐用法后面加▲,至于移动端在兼容性允许的情况下优先考虑flex 一、水平居中 (1)文本/行内元素/行内块级元素▲ (2)单个块级元素▲ (3)多个块级元素 (4)使用绝对定位实现▲ (5)任意个元素(flex) 本章小结: 二、垂直居中 (1)单行文本/行内元素/行内块级元素▲ (2)多行文本/行内元素/行内块级元素 (3)图片▲ (4)单个块级元素 --(1) 使用tabel-cell实现: --(2) 使用绝对定位实现:▲ --(3) 使用flex实现: (5)任意个元素(flex) 本章小结: 三、水平垂直居中 (1)行内/行内块级/图片▲ (2)table-cell (3)button作为父元素 (4)绝对定位▲ (5)绝对居中▲ (6)flex (7)视窗居中 本章小结: 四、两列布局 4.1 左列定宽,右列自适应 --(1)利用float+margin实现 --(2)利用float+margin(fix)实现 --(3)使用float+overflow实现▲ --(4)使用table实现▲ --(5)使用绝对定位实现 --(6)使用flex实现 --(7)使用Grid实现 4.2 左列自适应,右列定宽 --(1)使用float+margin实现 --(2)使用float+overflow实现▲ --(3)使用table实现▲ --(4)使用绝对定位实现 --(5)使用flex实现 --(6)使用Grid实现 4.3 一列不定,一列自适应 --(1)使用float+overflow实现▲ --(2)使用flex实现 --(3)使用Grid实现 五、三列布局 5.1 两列定宽,一列自适应 --(1)使用float+margin实现 --(2)使用float+overflow实现▲ --(3)使用table实现▲ --(4)使用flex实现 --(5)使用Grid实现 5.2 两侧定宽,中间自适应 5.2.1 双飞翼布局方法 5.2.2 圣杯布局方法 5.2.3 使用Grid实现 5.2.4 其他方法 --(1)使用table实现▲ --(2)使用flex实现 --(3)使用position实现▲ 六、多列布局 6.1 等宽布局 6.1.1四列等宽 --(1)使用float实现▲ --(2)使用table实现▲ --(3)使用flex实现 6.1.2多列等宽 --(1)使用float实现▲ --(2)使用table实现▲ --(3)使用flex实现 --(4)使用Grid实现 6.2 九宫格布局 --(1)使用table实现▲ --(2)使用flex实现 --(3)使用Grid实现 6.3 栅格系统▲ --(1)用Less生成 七、全屏布局 (1)使用绝对定位实现▲ (2)使用flex实现 (3)使用Grid实现 八、网站实例布局分析: 8.1 小米官网 8.1.1 兼容IE9+的方法 --(1)页面整体 --(2)局部——header --(3)局部——top --(4)局部——center --(5)局部——bottom --(6)局部——footer --(7)全部代码(优化后) 8.1.2 Flexbox+Grid搭配用法(未来...) 九、其他补充: 9.1 移动端viewport --设置viewport: --阅读推荐: 9.2 媒体查询 --代码示例: --阅读推荐: 9.3 REM --阅读推荐: 9.4 Flexbox --阅读推荐: 9.5 CSS Grid --阅读推荐: End:感谢 一、水平居中 一,二,三章都是parent+son的简单结构,html代码和效果图就不贴出来了,第四章以后才有 (1)文本/行内元素/行内块级元素▲ 原理:text-align只控制行内内容(文字、行内元素、行内块级元素)如何相对他的块父元素对齐 #parent{ text-align: center; } 复制代码 优缺点 优点:简单快捷,容易理解,兼容性非常好 缺点:只对行内内容有效;属性会继承影响到后代行内内容;如果子元素宽度大于父元素宽度则无效,只有后代行内内容中宽度小于设置text-align属性的元素宽度的时候,才会水平居中 (2)单个块级元素▲ 原理:根据规范介绍得很清楚了,有这么一种情况:在margin有节余的同时如果左右margin设置了auto,将会均分剩余空间。另外,如果上下的margin设置了auto,其计算值为0 #son{ width: 100px; /*必须定宽*/ margin: 0 auto; } 复制代码 优缺点 优点:简单;兼容性好 缺点:必须定宽,并且值不能为auto;宽度要小于父元素,否则无效 (3)多个块级元素 原理:text-align只控制行内内容(文字、行内元素、行内块级元素)如何相对他的块父元素对齐 #parent{ text-align: center; } .son{ display: inline-block; /*改为行内或者行内块级形式,以达到text-align对其生效*/ } 复制代码 优缺点 优点:简单,容易理解,兼容性非常好 缺点:只对行内内容有效;属性会继承影响到后代行内内容;块级改为inline-block换行、空格会产生元素间隔 (4)使用绝对定位实现▲ 原理:子绝父相,top、right、bottom、left的值是相对于父元素尺寸的,然后margin或者transform是相对于自身尺寸的,组合使用达到水平居中的目的 #parent{ height: 200px; width: 200px; /*定宽*/ position: relative; /*父相*/ background-color: #f00; } #son{ position: absolute; /*子绝*/ left: 50%; /*父元素宽度一半,这里等同于left:100px*/ transform: translateX(-50%); /*自身宽度一半,等同于margin-left: -50px;*/ width: 100px; /*定宽*/ height: 100px; background-color: #00ff00; } 复制代码 优缺点 优点:使用margin-left兼容性好;不管是块级还是行内元素都可以实现 缺点:代码较多;脱离文档流;使用margin-left需要知道宽度值;使用transform兼容性不好(ie9+) (5)任意个元素(flex) 原理:就是设置当前主轴对齐方式为居中。说不上为什么,flex无非就是主轴侧轴是重点,然后就是排列方式的设置,可以去看看文末的flex阅读推荐 #parent{ display: flex; justify-content: center; } 复制代码 优缺点 优点:功能强大;简单方便;容易理解 缺点:PC端兼容性不好,移动端(Android4.0+) 本章小结: 对于水平居中,我们应该先考虑,哪些元素有自带的居中效果,最先想到的应该就是 text-align:center 了,但是这个只对行内内容有效,所以我们要使用 text-align:center 就必须将子元素设置为 display: inline; 或者 display: inline-block; ; 其次就是考虑能不能用margin: 0 auto; ,因为这都是一两句代码能搞定的事,实在不行就是用绝对定位去实现了。 移动端能用flex就用flex,简单方便,灵活并且功能强大,无愧为网页布局的一大利器! 二、垂直居中 一,二,三章都是parent+son的简单结构,html代码和效果图就不贴出来了,第四章以后才有 (1)单行文本/行内元素/行内块级元素▲ 原理:line-height的最终表现是通过inline box实现的,而无论inline box所占据的高度是多少(无论比文字大还是比文字小),其占据的空间都是与文字内容公用水平中垂线的。 #parent{ height: 150px; line-height: 150px; /*与height等值*/ } 复制代码 优缺点 优点:简单;兼容性好 缺点:只能用于单行行内内容;要知道高度的值 (2)多行文本/行内元素/行内块级元素 原理同上 #parent{ /*或者用span把所有文字包裹起来,设置display:inline-block转换成图片的方式解决*/ height: 150px; line-height: 30px; /*元素在页面呈现为5行,则line-height的值为height/5*/ } 复制代码 优缺点 优点:简单;兼容性好 缺点:只能用于行内内容;需要知道高度和最终呈现多少行来计算出line-height的值,建议用span包裹多行文本 (3)图片▲ 原理:vertical-align和line-height的基友关系 #parent{ height: 150px; line-height: 150px; font-size: 0; } img#son{vertical-align: middle;} /*默认是基线对齐,改为middle*/ 复制代码 优缺点 优点:简单;兼容性好 缺点:需要添加font-size: 0; 才可以完全的垂直居中;不过需要主要,html#parent包裹img之间需要有换行或空格 (4)单个块级元素 html代码: <div id="parent"> <div id="son"></div> </div> 复制代码 (4-1) 使用tabel-cell实现: 原理:CSS Table,使表格内容对齐方式为middle #parent{ display: table-cell; vertical-align: middle; } 复制代码 优缺点 优点:简单;宽高不定;兼容性好(ie8+) 缺点:设置tabl-cell的元素,宽度和高度的值设置百分比无效,需要给它的父元素设置display: table; 才生效;table-cell不感知margin,在父元素上设置table-row等属性,也会使其不感知height;设置float或position会对默认布局造成破坏,可以考虑为之增加一个父div定义float等属性;内容溢出时会自动撑开父元素 (4-2) 使用绝对定位实现:▲ /*原理:子绝父相,top、right、bottom、left的值是相对于父元素尺寸的,然后margin或者transform是相对于自身尺寸的,组合使用达到水平居中的目的*/ #parent{ height: 150px; position: relative; /*父相*/ } #son{ position: absolute; /*子绝*/ top: 50%; /*父元素高度一半,这里等同于top:75px;*/ transform: translateY(-50%); /*自身高度一半,这里等同于margin-top:-25px;*/ height: 50px; } /*优缺点 - 优点:使用margin-top兼容性好;不管是块级还是行内元素都可以实现 - 缺点:代码较多;脱离文档流;使用margin-top需要知道高度值;使用transform兼容性不好(ie9+)*/ 或 /*原理:当top、bottom为0时,margin-top&bottom会无限延伸占满空间并且平分*/ #parent{position: relative;} #son{ position: absolute; margin: auto 0; top: 0; bottom: 0; height: 50px; } /*优缺点 - 优点:简单;兼容性较好(ie8+) - 缺点:脱离文档流*/ 复制代码 (4-3) 使用flex实现: 原理:flex设置对齐方式罢了,请查阅文末flex阅读推荐 #parent{ display: flex; align-items: center; } 或 #parent{display: flex;} #son{align-self: center;} 或 /*原理:这个尚未搞清楚,应该是flex使margin上下边界无限延伸至剩余空间并平分了*/ #parent{display: flex;} #son{margin: auto 0;} 复制代码 优缺点 优点:简单灵活;功能强大 缺点:PC端兼容性不好,移动端(Android4.0+) (5)任意个元素(flex) 原理:flex设置对齐方式罢了,请查阅文末flex阅读推荐 #parent{ display: flex; align-items: center; } 或 #parent{ display: flex; } .son{ align-self: center; } 或 #parent{ display: flex; flex-direction: column; justify-content: center; } 复制代码 优缺点 优点:简单灵活;功能强大 缺点:PC端兼容性不好,移动端(Android4.0+) 本章小结: 对于垂直居中,最先想到的应该就是 line-height 了,但是这个只能用于行内内容; 其次就是考虑能不能用vertical-align: middle; ,不过这个一定要熟知原理才能用得顺手,建议看下vertical-align和line-height的基友关系 ; 然后便是绝对定位,虽然代码多了点,但是胜在适用于不同情况; 移动端兼容性允许的情况下能用flex就用flex 三、水平垂直居中 一,二,三章都是parent+son的简单结构,html代码和效果图就不贴出来了,第四章以后才有 (1)行内/行内块级/图片▲ 原理:text-align: center; 控制行内内容相对于块父元素水平居中,然后就是line-height和vertical-align的基友关系使其垂直居中,font-size: 0; 是为了消除近似居中的bug #parent{ height: 150px; line-height: 150px; /*行高的值与height相等*/ text-align: center; font-size: 0; /*消除幽灵空白节点的bug*/ } #son{ /*display: inline-block;*/ /*如果是块级元素需改为行内或行内块级才生效*/ vertical-align: middle; } 复制代码 优缺点 优点:代码简单;兼容性好(ie8+) 缺点:只对行内内容有效;需要添加font-size: 0; 才可以完全的垂直居中;不过需要注意html中#parent包裹#son之间需要有换行或空格;熟悉line-height和vertical-align的基友关系较难 (2)table-cell 原理:CSS Table,使表格内容垂直对齐方式为middle,然后根据是行内内容还是块级内容采取不同的方式达到水平居中 #parent{ height: 150px; width: 200px; display: table-cell; vertical-align: middle; /*text-align: center;*/ /*如果是行内元素就添加这个*/ } #son{ /*margin: 0 auto;*/ /*如果是块级元素就添加这个*/ width: 100px; height: 50px; } 复制代码 优缺点 优点:简单;适用于宽度高度未知情况;兼容性好(ie8+) 缺点:设置tabl-cell的元素,宽度和高度的值设置百分比无效,需要给它的父元素设置display: table; 才生效;table-cell不感知margin,在父元素上设置table-row等属性,也会使其不感知height;设置float或position会对默认布局造成破坏,可以考虑为之增加一个父div定义float等属性;内容溢出时会自动撑开父元素 (3)button作为父元素 原理:button的默认样式,再把需要居中的元素表现形式改为行内或行内块级就好 button#parent{ /*改掉button默认样式就好了,不需要居中处理*/ height: 150px; width: 200px; outline: none; border: none; } #son{ display: inline-block; /*button自带text-align: center,改为行内水平居中生效*/ } 复制代码 优缺点 优点:简单方便,充分利用默认样式 缺点:只适用于行内内容;需要清除部分默认样式;水平垂直居中兼容性很好,但是ie下点击会有凹陷效果! (4)绝对定位 原理:子绝父相,top、right、bottom、left的值是相对于父元素尺寸的,然后margin或者transform是相对于自身尺寸的,组合使用达到几何上的水平垂直居中 #parent{ position: relative; } #son{ position: absolute; top: 50%; left: 50%; /*定宽高时等同于margin-left:负自身宽度一半;margin-top:负自身高度一半;*/ transform: translate(-50%,-50%); } 复制代码 优缺点 优点:使用margin兼容性好;不管是块级还是行内元素都可以实现 缺点:代码较多;脱离文档流;使用margin需要知道宽高;使用transform兼容性不好(ie9+) (5)绝对居中 原理:当top、bottom为0时,margin-top&bottom设置auto的话会无限延伸占满空间并且平分;当left、right为0时,margin-left&right设置auto的话会无限延伸占满空间并且平分 #parent{ position: relative; } #son{ position: absolute; margin: auto; width: 100px; height: 50px; top: 0; bottom: 0; left: 0; right: 0; } 复制代码 优缺点 优点:无需关注宽高;兼容性较好(ie8+) 缺点:代码较多;脱离文档流 (6)flex 原理:flex设置对齐方式罢了,请查阅文末flex阅读推荐 #parent{ display: flex; } #son{ margin: auto; } 或 #parent{ display: flex; justify-content: center; align-items: center; } 或 #parent{ display: flex; justify-content: center; } #son{ align-self: center; } 复制代码 优缺点 优点:简单灵活;功能强大 缺点:PC端兼容性不好,移动端(Android4.0+) (7)视窗居中 原理:vh为视口单位,视口即文档可视的部分,50vh就是视口高度的50/100,设置50vh上边距再 #son{ /*0如果去掉,则会多出滚动条并且上下都是50vh的margin。如果去掉就给body加上overflow:hidden;*/ margin: 50vh auto 0; transform: translateY(-50%); } 复制代码 优缺点 优点:简单;容易理解;两句代码达到屏幕水平垂直居中 缺点:兼容性不好(ie9+,Android4.4+) 本章小结: 一般情况下,水平垂直居中,我们最常用的就是绝对定位加负边距了,缺点就是需要知道宽高,使用transform倒是可以不需要,但是兼容性不好(ie9+); 其次就是绝对居中,绝对定位设置top、left、right、bottom为0,然后margin:auto; 让浏览器自动平分边距以达到水平垂直居中的目的; 如果是行内/行内块级/图片这些内容,可以优先考虑line-height和vertical-align 结合使用,不要忘了还有text-align ,这个方法代码其实不多,就是理解原理有点困难,想要熟练应对各种情况还需好好研究; 移动端兼容性允许的情况下能用flex就用flex。 四、两列布局 4.1 左列定宽,右列自适应 效果: (1)利用float+margin实现 html代码: <body> <div id="left">左列定宽</div> <div id="right">右列自适应</div> </body> 复制代码 css代码: #left { background-color: #f00; float: left; width: 100px; height: 500px; } #right { background-color: #0f0; height: 500px; margin-left: 100px; /*大于等于#left的宽度*/ } 复制代码 (2)利用float+margin(fix)实现 html代码: <body> <div id="left">左列定宽</div> <div id="right-fix"> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #left { background-color: #f00; float: left; width: 100px; height: 500px; } #right-fix { float: right; width: 100%; margin-left: -100px; /*正值大于或等于#left的宽度,才能显示在同一行*/ } #right{ margin-left: 100px; /*大于或等于#left的宽度*/ background-color: #0f0; height: 500px; } 复制代码 (3)使用float+overflow实现 html代码: <body> <div id="left">左列定宽</div> <div id="right">右列自适应</div> </body> 复制代码 css代码: #left { background-color: #f00; float: left; width: 100px; height: 500px; } #right { background-color: #0f0; height: 500px; overflow: hidden; /*触发bfc达到自适应*/ } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注定宽的宽度,利用bfc达到自适应效果 缺点:浮动脱离文档流,需要手动清除浮动,否则会产生高度塌陷;不支持ie6 (4)使用table实现 html代码: <div id="parent"> <div id="left">左列定宽</div> <div id="right">右列自适应</div> </div> 复制代码 css代码: #parent{ width: 100%; display: table; height: 500px; } #left { width: 100px; background-color: #f00; } #right { background-color: #0f0; } #left,#right{ display: table-cell; /*利用单元格自动分配宽度*/ } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注定宽的宽度,利用单元格自动分配达到自适应效果 缺点:margin失效;设置间隔比较麻烦;不支持ie8- (5)使用绝对定位实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent{ position: relative; /*子绝父相*/ } #left { position: absolute; top: 0; left: 0; background-color: #f00; width: 100px; height: 500px; } #right { position: absolute; top: 0; left: 100px; /*值大于等于#left的宽度*/ right: 0; background-color: #0f0; height: 500px; } 复制代码 (6)使用flex实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent{ width: 100%; height: 500px; display: flex; } #left { width: 100px; background-color: #f00; } #right { flex: 1; /*均分了父元素剩余空间*/ background-color: #0f0; } 复制代码 (7)使用Grid实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent { width: 100%; height: 500px; display: grid; grid-template-columns: 100px auto; /*设定2列就ok了,auto换成1fr也行*/ } #left { background-color: #f00; } #right { background-color: #0f0; } 复制代码 4.2 左列自适应,右列定宽 效果: (1)使用float+margin实现 html代码: <body> <div id="parent"> <div id="left">左列自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent{ height: 500px; padding-left: 100px; /*抵消#left的margin-left以达到#parent水平居中*/ } #left { width: 100%; height: 500px; float: left; margin-left: -100px; /*正值等于#right的宽度*/ background-color: #f00; } #right { height: 500px; width: 100px; float: right; background-color: #0f0; } 复制代码 (2)使用float+overflow实现 html代码: <body> <div id="parent"> <div id="right">右列定宽</div> <div id="left">左列自适应</div> <!--顺序要换一下--> </div> </body> 复制代码 css代码: #left { overflow: hidden; /*触发bfc*/ height: 500px; background-color: #f00; } #right { margin-left: 10px; /*margin需要定义在#right中*/ float: right; width: 100px; height: 500px; background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注定宽的宽度,利用bfc达到自适应效果 缺点:浮动脱离文档流,需要手动清除浮动,否则会产生高度塌陷;不支持ie6 (3)使用table实现 html代码: <body> <div id="parent"> <div id="left">左列自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent{ width: 100%; height: 500px; display: table; } #left { background-color: #f00; display: table-cell; } #right { width: 100px; background-color: #0f0; display: table-cell; } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注定宽的宽度,利用单元格自动分配达到自适应效果 缺点:margin失效;设置间隔比较麻烦;不支持ie8- (4)使用绝对定位实现 html代码: <body> <div id="parent"> <div id="left">左列自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent{ position: relative; /*子绝父相*/ } #left { position: absolute; top: 0; left: 0; right: 100px; /*大于等于#rigth的宽度*/ background-color: #f00; height: 500px; } #right { position: absolute; top: 0; right: 0; background-color: #0f0; width: 100px; height: 500px; } 复制代码 (5)使用flex实现 html代码: <body> <div id="parent"> <div id="left">左列自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent{ height: 500px; display: flex; } #left { flex: 1; background-color: #f00; } #right { width: 100px; background-color: #0f0; } 复制代码 (6)使用Grid实现 html代码: <body> <div id="parent"> <div id="left">左列自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: grid; grid-template-columns: auto 100px; /*设定2列,auto换成1fr也行*/ } #left { background-color: #f00; } #right { background-color: #0f0; } 复制代码 4.3 一列不定,一列自适应 (盒子宽度随着内容增加或减少发生变化,另一个盒子自适应) 效果图: 变化后: (1)使用float+overflow实现 html代码: <body> <div id="parent"> <div id="left">左列不定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #left { margin-right: 10px; float: left; /*只设置浮动,不设宽度*/ height: 500px; background-color: #f00; } #right { overflow: hidden; /*触发bfc*/ height: 500px; background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注宽度,利用bfc达到自适应效果 缺点:浮动脱离文档流,需要手动清除浮动,否则会产生高度塌陷;不支持ie6 (2)使用flex实现 html代码: <body> <div id="parent"> <div id="left">左列不定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent{ display: flex; } #left { /*不设宽度*/ margin-right: 10px; height: 500px; background-color: #f00; } #right { height: 500px; background-color: #0f0; flex: 1; /*均分#parent剩余的部分*/ } 复制代码 (3)使用Grid实现 html代码: <body> <div id="parent"> <div id="left">左列不定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent{ display: grid; grid-template-columns: auto 1fr; /*auto和1fr换一下顺序就是左列自适应,右列不定宽了*/ } #left { margin-right: 10px; height: 500px; background-color: #f00; } #right { height: 500px; background-color: #0f0; } 复制代码 左列自适应,右列不定宽同理(参考4.1和4.3对应代码示例) 五、三列布局 5.1 两列定宽,一列自适应 效果图: (1)使用float+margin实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent{ min-width: 310px; /*100+10+200,防止宽度不够,子元素换行*/ } #left { margin-right: 10px; /*#left和#center间隔*/ float: left; width: 100px; height: 500px; background-color: #f00; } #center{ float: left; width: 200px; height: 500px; background-color: #eeff2b; } #right { margin-left: 320px; /*等于#left和#center的宽度之和加上间隔,多出来的就是#right和#center的间隔*/ height: 500px; background-color: #0f0; } 复制代码 (2)使用float+overflow实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent{ min-width: 320px; /*100+10+200+20,防止宽度不够,子元素换行*/ } #left { margin-right: 10px; /*间隔*/ float: left; width: 100px; height: 500px; background-color: #f00; } #center{ margin-right: 10px; /*在此定义和#right的间隔*/ float: left; width: 200px; height: 500px; background-color: #eeff2b; } #right { overflow: hidden; /*触发bfc*/ height: 500px; background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注定宽的宽度,利用bfc达到自适应效果 缺点:浮动脱离文档流,需要手动清除浮动,否则会产生高度塌陷;不支持ie6 (3)使用table实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent { width: 100%; height: 520px; /*抵消上下间距10*2的高度影响*/ margin: -10px 0; /*抵消上下边间距10的位置影响*/ display: table; /*左右两边间距大了一点,子元素改用padding设置盒子间距就没有这个问题*/ border-spacing: 10px; /*关键!!!设置间距*/ } #left { display: table-cell; width: 100px; background-color: #f00; } #center { display: table-cell; width: 200px; background-color: #eeff2b; } #right { display: table-cell; background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解,无需关注定宽的宽度,利用单元格自动分配达到自适应效果 缺点:margin失效;设置间隔比较麻烦;不支持ie8- (4)使用flex实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: flex; } #left { margin-right: 10px; /*间距*/ width: 100px; background-color: #f00; } #center { margin-right: 10px; /*间距*/ width: 200px; background-color: #eeff2b; } #right { flex: 1; /*均分#parent剩余的部分达到自适应*/ background-color: #0f0; } 复制代码 (5)使用Grid实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间定宽</div> <div id="right">右列自适应</div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: grid; grid-template-columns: 100px 200px auto; /*设置3列,固定第一第二列的宽度,第三列auto或者1fr*/ } #left { margin-right: 10px; /*间距*/ background-color: #f00; } #center { margin-right: 10px; /*间距*/ background-color: #eeff2b; } #right { background-color: #0f0; } 复制代码 5.2 两侧定宽,中间自适应 5.2.1 双飞翼布局方法 效果图: html代码: <body> <div id="header"></div> <!--中间栏需要放在前面--> <div id="parent"> <div id="center"> <div id="center_inbox">中间自适应</div> <hr> <!--方便观察原理--> </div> <div id="left">左列定宽</div> <div id="right">右列定宽</div> </div> <div id="footer"></div> </body> 复制代码 css代码: #header { height: 60px; background-color: #ccc; } #left { float: left; width: 100px; height: 500px; margin-left: -100%; /*调整#left的位置,值等于自身宽度*/ background-color: #f00; opacity: 0.5; } #center { height: 500px; float: left; width: 100%; background-color: #eeff2b; } #center_inbox{ height: 480px; border: 1px solid #000; margin: 0 220px 0 120px; /*关键!!!左右边界等于左右盒子的宽度,多出来的为盒子间隔*/ } #right { float: left; width: 200px; height: 500px; margin-left: -200px; /*使right到指定的位置,值等于自身宽度*/ background-color: #0f0; opacity: 0.5; } #footer { clear: both; /*注意清除浮动!!*/ height: 60px; background-color: #ccc; } 复制代码 5.2.2 圣杯布局方法 效果图: html代码: <body> <div id="header"></div> <div id="parent"> <!--#center需要放在前面--> <div id="center">中间自适应 <hr> </div> <div id="left">左列定宽</div> <div id="right">右列定宽</div> </div> <div id="footer"></div> </body> 复制代码 css代码: #header{ height: 60px; background-color: #ccc; } #parent { box-sizing: border-box; height: 500px; padding: 0 215px 0 115px; /*为了使#center摆正,左右padding分别等于左右盒子的宽,可以结合左右盒子相对定位的left调整间距*/ } #left { margin-left: -100%; /*使#left上去一行*/ position: relative; left: -115px; /*相对定位调整#left的位置,正值大于或等于自身宽度*/ float: left; width: 100px; height: 500px; background-color: #f00; opacity: 0.5; } #center { float: left; width: 100%; /*由于#parent的padding,达到自适应的目的*/ height: 500px; box-sizing: border-box; border: 1px solid #000; background-color: #eeff2b; } #right { position: relative; left: 215px; /*相对定位调整#right的位置,大于或等于自身宽度*/ width: 200px; height: 500px; margin-left: -200px; /*使#right上去一行*/ float: left; background-color: #0f0; opacity: 0.5; } #footer{ height: 60px; background-color: #ccc; } 复制代码 5.2.3 使用Grid实现 效果图: html代码: <body> <div id="parent"> <div id="header"></div> <!--#center需要放在前面--> <div id="center">中间自适应 <hr> </div> <div id="left">左列定宽</div> <div id="right">右列定宽</div> <div id="footer"></div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: grid; grid-template-columns: 100px auto 200px; /*设定3列*/ grid-template-rows: 60px auto 60px; /*设定3行*/ /*设置网格区域分布*/ grid-template-areas: "header header header" "leftside main rightside" "footer footer footer"; } #header { grid-area: header; /*指定在哪个网格区域*/ background-color: #ccc; } #left { grid-area: leftside; background-color: #f00; opacity: 0.5; } #center { grid-area: main; /*指定在哪个网格区域*/ margin: 0 15px; /*设置间隔*/ border: 1px solid #000; background-color: #eeff2b; } #right { grid-area: rightside; /*指定在哪个网格区域*/ background-color: #0f0; opacity: 0.5; } #footer { grid-area: footer; /*指定在哪个网格区域*/ background-color: #ccc; } 复制代码 5.2.4 其他方法 效果图: (1)使用table实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent { width: 100%; height: 500px; display: table; } #left { display: table-cell; width: 100px; background-color: #f00; } #center { display: table-cell; background-color: #eeff2b; } #right { display: table-cell; width: 200px; background-color: #0f0; } 复制代码 优缺点: 优点:代码简洁,容易理解; 缺点:margin失效,采用border-spacing表格两边的间隔无法消除;不支持ie8- (2)使用flex实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: flex; } #left { width: 100px; background-color: #f00; } #center { flex: 1; /*均分#parent剩余的部分*/ background-color: #eeff2b; } #right { width: 200px; background-color: #0f0; } 复制代码 (3)使用position实现 html代码: <body> <div id="parent"> <div id="left">左列定宽</div> <div id="center">中间自适应</div> <div id="right">右列定宽</div> </div> </body> 复制代码 css代码: #parent { position: relative; /*子绝父相*/ } #left { position: absolute; top: 0; left: 0; width: 100px; height: 500px; background-color: #f00; } #center { height: 500px; margin-left: 100px; /*大于等于#left的宽度,或者给#parent添加同样大小的padding-left*/ margin-right: 200px; /*大于等于#right的宽度,或者给#parent添加同样大小的padding-right*/ background-color: #eeff2b; } #right { position: absolute; top: 0; right: 0; width: 200px; height: 500px; background-color: #0f0; } 复制代码 优缺点: 优点:容易理解,兼容性比较好 缺点:需手动计算宽度确定边距;脱离文档流;代码繁多 六、多列布局 6.1 等宽布局 6.1.1 四列等宽 (1)使用float实现 效果图: html代码: <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { margin-left: -20px; /*使整体内容看起来居中,抵消padding-left的影响*/ } .column{ padding-left: 20px; /*盒子的边距*/ width: 25%; float: left; box-sizing: border-box; border: 1px solid #000; background-clip: content-box; /*背景色从内容开始绘制,方便观察*/ height: 500px; } .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解;兼容性较好 缺点:需要手动清除浮动,否则会产生高度塌陷 (2)使用table实现 效果图: html代码: <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { height: 540px; /*抵消上下边20*2间距的高度影响*/ display: table; margin: -20px 0; /*抵消上下边20*2间距的位置影响*/ /*两边离页面间距较大,改用子元素设置padding来当成间隔就不会有这样的问题*/ border-spacing: 20px; /*设置间距*/ } .column{ display: table-cell; } .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解;无需关注宽度,单元格自动等分 缺点:margin失效;设置间隔比较麻烦;不支持ie8- (3)使用flex实现 效果图: html代码: <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { margin-left: -15px; /*使内容看起来居中*/ height: 500px; display: flex; } .column{ flex: 1; /*一起平分#parent*/ margin-left: 15px; /*设置间距*/ } .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 多列等宽 效果图: (1)使用float实现 html代码: <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">5 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">6 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { height: 500px; } .column{ float: left; /*添加浮动*/ width: 16.66666666666667%; /*100÷列数,得出百分比*/ height: 500px; } .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解;兼容性较好 缺点:需要手动清除浮动,否则会产生高度塌陷 (2)使用table实现 html代码 <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">5 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">6 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { width: 100%; height: 500px; display: table; } .column{ display: table-cell; /*无需关注列数,单元格自动平分*/ } .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 优缺点: 优点:代码简单,容易理解;无需关注宽度。单元格自动等分 缺点:margin失效;设置间隔比较麻烦;不兼容ie8- (3)使用flex实现 html代码: <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">5 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">6 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: flex; } .column{ flex: 1; /*无需关注列数,一起平分#parent*/ } .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 (4)使用Grid实现 html代码: <body> <div id="parent"> <div class="column">1 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">2 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">3 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">4 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">5 <p>我是文字我是文字我输文字我是文字我是文字</p></div> <div class="column">6 <p>我是文字我是文字我输文字我是文字我是文字</p></div> </div> </body> 复制代码 css代码: #parent { height: 500px; display: grid; grid-template-columns: repeat(6,1fr); /*6就是列数*/ } .column{} .column:nth-child(odd){ background-color: #f00; } .column:nth-child(even){ background-color: #0f0; } 复制代码 6.2 九宫格布局 效果图: (1)使用table实现 html代码: <body> <div id="parent"> <div class="row"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> <div class="row"> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> </div> <div class="row"> <div class="item">7</div> <div class="item">8</div> <div class="item">9</div> </div> </div> </body> 复制代码 css代码: #parent { width: 1200px; height: 500px; margin: 0 auto; display: table; } .row { display: table-row; } .item { border: 1px solid #000; display: table-cell; } 复制代码 优缺点: 优点:代码简洁,容易理解; 缺点:margin失效,采用border-spacing表格两边的间隔无法消除;不支持ie8- (2)使用flex实现 html代码: <body> <div id="parent"> <div class="row"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> <div class="row"> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> </div> <div class="row"> <div class="item">7</div> <div class="item">8</div> <div class="item">9</div> </div> </div> </body> 复制代码 css代码: #parent { width: 1200px; height: 500px; margin: 0 auto; display: flex; flex-direction: column; } .row { display: flex; flex: 1; } .item { flex: 1; border: 1px solid #000; } 复制代码 (3)使用Grid实现 CSS Grid非常强大,可以实现各种各样的三维布局,可查阅本文结尾的阅读推荐 html代码: <body> <div id="parent"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> <div class="item">4</div> <div class="item">5</div> <div class="item">6</div> <div class="item">7</div> <div class="item">8</div> <div class="item">9</div> </div> </body> 复制代码 css代码: #parent { width: 1200px; height: 500px; margin: 0 auto; display: grid; grid-template-columns: repeat(3, 1fr); /*等同于1fr 1fr 1fr,此为重复的合并写法*/ grid-template-rows: repeat(3, 1fr); /*等同于1fr 1fr 1fr,此为重复的合并写法*/ } .item { border: 1px solid #000; } 复制代码 6.3 栅格系统 优缺点: 优点:代码简洁,容易理解;提高页面内容的流动性,能适应多种设备; (1)用Less生成 /*生成栅格系统*/ @media screen and (max-width: 768px){ .generate-columns(12); /*此处设置生成列数*/ .generate-columns(@n, @i: 1) when (@i <= @n) { .column-xs-@{i} { width: (@i * 100% / @n); } .generate-columns(@n, (@i+1)); } } @media screen and (min-width: 768px){ .generate-columns(12); /*此处设置生成列数*/ .generate-columns(@n, @i: 1) when (@i <= @n) { .column-sm-@{i} { width: (@i * 100% / @n); } .generate-columns(@n, (@i+1)); } } div[class^="column-xs-"]{ float: left; } div[class^="column-sm-"]{ float: left; } 复制代码 编译后的CSS代码: @media screen and (max-width: 768px) { .column-xs-1 { width: 8.33333333%; } .column-xs-2 { width: 16.66666667%; } .column-xs-3 { width: 25%; } .column-xs-4 { width: 33.33333333%; } .column-xs-5 { width: 41.66666667%; } .column-xs-6 { width: 50%; } .column-xs-7 { width: 58.33333333%; } .column-xs-8 { width: 66.66666667%; } .column-xs-9 { width: 75%; } .column-xs-10 { width: 83.33333333%; } .column-xs-11 { width: 91.66666667%; } .column-xs-12 { width: 100%; } } @media screen and (min-width: 768px) { .column-sm-1 { width: 8.33333333%; } .column-sm-2 { width: 16.66666667%; } .column-sm-3 { width: 25%; } .column-sm-4 { width: 33.33333333%; } .column-sm-5 { width: 41.66666667%; } .column-sm-6 { width: 50%; } .column-sm-7 { width: 58.33333333%; } .column-sm-8 { width: 66.66666667%; } .column-sm-9 { width: 75%; } .column-sm-10 { width: 83.33333333%; } .column-sm-11 { width: 91.66666667%; } .column-sm-12 { width: 100%; } } div[class^="column-xs-"]{ float: left; } div[class^="column-sm-"]{ float: left; } 复制代码 七、全屏布局 效果图: (1)使用绝对定位实现 html代码: <body> <div id="parent"> <div id="top">top</div> <div id="left">left</div> <div id="right">right</div> <div id="bottom">bottom</div> </div> </body> 复制代码 css代码: html, body, #parent {height: 100%;overflow: hidden;} #parent > div { border: 1px solid #000; } #top { position: absolute; top: 0; left: 0; right: 0; height: 100px; } #left { position: absolute; top: 100px; /*值大于等于#top的高度*/ left: 0; bottom: 50px; /*值大于等于#bottom的高度*/ width: 200px; } #right { position: absolute; overflow: auto; left: 200px; /*值大于等于#left的宽度*/ right: 0; top: 100px; /*值大于等于#top的高度*/ bottom: 50px; /*值大于等于#bottom的高度*/ } #bottom { position: absolute; left: 0; right: 0; bottom: 0; height: 50px; } 复制代码 优缺点: 优点:容易理解 缺点:代码繁多;需要计算好各个盒子的宽高; (2)使用flex实现 html代码: <body> <div id="parent"> <div id="top">top</div> <div id="middle"> <div id="left">left</div> <div id="right">right</div> </div> <div id="bottom">bottom</div> </div> </body> 复制代码 css代码: *{ margin: 0; padding: 0; } html,body,#parent{ height:100%; } #parent { display: flex; flex-direction: column; } #top { height: 100px; } #bottom { height: 50px; } #middle { flex: 1; display: flex; } #left { width: 200px; } #right { flex: 1; overflow: auto; } 复制代码 (3)使用Grid实现 html代码: <body> <div id="parent"> <div id="top">top</div> <div id="left">left</div> <div id="right">right</div> <div id="bottom">bottom</div> </div> </body> 复制代码 css代码: *{ margin: 0; padding: 0; } html, body, #parent { height: 100%; } #parent { width: 100%; height: 100%; display: grid; /*分成2列,第一列宽度200px,第二列1fr平分剩余的部分,此处换成auto也行*/ grid-template-columns: 200px 1fr; /*分成3行,第一行高度100px,第二行auto为自适应,此处换成1fr也行,第3行高度为50px*/ grid-template-rows: 100px auto 50px; /*定义网格区域分布*/ grid-template-areas: "header header" "aside main" "footer footer"; } #parent>div{ border: 1px solid #000; } #top{ grid-area: header; /*指定在哪个网格区域*/ } #left{ grid-area: aside; /*指定在哪个网格区域*/ } #right{ grid-area: main; /*指定在哪个网格区域*/ } #bottom{ grid-area: footer; /*指定在哪个网格区域*/ } 复制代码 八、网站实例布局分析: 由于方法众多,分析的时候想到哪种用哪种了,只要IE9和谷歌上表现一致,我就不一一测试其他浏览器了,如果有什么问题或意见,请留言! 8.1 小米官网 https://www.mi.com/ 8.1.1 兼容IE9+的方法 (1)页面整体 整个页面我们可以分成顶、上、中、下、底五个结构,如图所示: html代码: <body> <div class="header"></div> <div class="top"></div> <div class="center"></div> <div class="bottom"></div> <div class="footer"></div> </body> 复制代码 css代码: *{ /*为了方便,就这样清空默认样式了*/ margin: 0; padding: 0; box-sizing: border-box; list-style: none; } body{ background-color: #f5f5f5; } .header{ margin-bottom: 20px; height: 40px; background-color: #333; } .top{ height: 1210px; background-color: #fff; } .center{ width: 1226px; margin: 0 auto; margin-bottom: 60px; height: 1791px; background-color: #fff; } .bottom{ height: 274px; background-color: #fff; } .footer{ margin: 0 auto; width: 1226px; height: 166px; border: 1px solid #000; } 复制代码 (2)局部——header header部分首先是一个水平居中的内容,内容盒子可以分成左右两个部分,如图所示: html代码: <div class="header"> <div class="container"> <div class="header-left"></div> <div class="header-rigth"></div> </div> </div> 复制代码 css代码: .container{ /*后面会继续用到*/ width: 1226px; height: 100%; margin: 0 auto; border: 1px solid #f00; } .header-left{ width: 380px; height: 100%; float: left; background-color: #0f0; } .header-rigth{ width: 260px; height: 100%; float: right; background-color: #0f0; } 复制代码 (3)局部——top top部分先有一个水平居中的内容,再就是内容由上到下可以分成四个部分,然后每个部分再细分......说不下去了,直接上图: html代码: <div class="top"> <div class="container"> <div class="top-nav"></div> <div class="top-slider"> <div class="slider-navbar"></div> </div> <div class="top-recommend"> <div class="recommend-left"></div> <div class="recommend-right"> <ul> <li></li> <li></li> <li></li> </ul> </div> </div> <div class="top-flashsale"> <div class="flashsale-title"></div> <div class="flashsale-content"> <div class="content-timer"></div> <ul class="content-shops"> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> </div> </div> 复制代码 css代码: .top { height: 1210px; background-color: #fff; } .top-nav { height: 100px; background-color: #f00; } .top-slider { margin-bottom: 14px; position: relative; height: 460px; background-color: #00f; } .slider-navbar { position: absolute; top: 0; left: 0; width: 234px; height: 100%; background-color: black; opacity: .5; } .top-recommend { margin-bottom: 26px; height: 170px; background-color: #0f0; } .recommend-left { float: left; height: 100%; width: 234px; background-color: skyblue; } .recommend-right { float: right; width: 978px; height: 100%; border: 1px solid #000; } .recommend-right > ul { height: 100%; } .recommend-right > ul li { float: left; width: 316px; height: 100%; background-color: deepskyblue; } .recommend-right > ul li + li { margin-left: 14px; } .top-flashsale { height: 438px; background-color: #ff4455; } .flashsale-title { height: 58px; background-color: purple; } .flashsale-content { border: 1px solid #000; padding-bottom: 40px; height: 380px; } .content-timer { margin-right: 14px; float: left; width: 234px; height: 100%; background-color: #fff; } .content-shops { overflow: hidden; height: 100%; background-color: #6effb1; } .content-shops > li { float: left; width: 234px; height: 100%; background-color: #fff; } .content-shops > li+li { margin-left: 12.5px; } 复制代码 (4)局部——center center部分都是一些单元格展示,有很多类似的模块,就挑几个来实现了,直接看图吧: html代码: <div class="center"> <div class="center-phone"> <div class="phone-title"></div> <div class="phone-content"> <div class="phone-left"></div> <ul class="phone-right"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> <div class="center-household"> <div class="household-title"></div> <div class="household-content"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li> <p></p> <p></p> </li> </div> </div> <div class="center-video"> <div class="video-title"></div> <ul class="video-content"> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> 复制代码 css代码: .center { margin: 0 auto; margin-bottom: 60px; padding-top: 60px; width: 1226px; height: 1791px; background-color: #fff; } .center-phone{ margin-bottom: 8px; height: 686px; background-color: yellow; } .phone-title{ height: 58px; background-color: black; } .phone-content{ height: 628px; background-color: pink; } .phone-left{ margin-right: 14px; float: left; width: 234px; height: 100%; background-color: darkseagreen; } .phone-right{ overflow: hidden; height: 100%; background-color: #ccc; } .phone-right>li{ margin-bottom: 28px; padding-left: 14px; float: left; width: 25%; height: 300px; border: 1px solid #000; background-color: #f00; background-clip: content-box; } .phone-right>li:nth-child(1), .phone-right>li:nth-child(5){ margin-left: 0; } .center-household{ margin-bottom: 8px; height: 686px; background-color: yellow; } .household-title{ height: 58px; background-color: black; } .household-content{ height: 614px; } .household-content>li{ position: relative; margin-left: 14px; margin-bottom: 28px; float: left; width: 234px; height: 300px; background-color: #d7d7d7; } .household-content>li:nth-child(1), .household-content>li:nth-child(6){ margin-left: 0; } .household-content>li:last-child p:first-child{ position: absolute; top: 0; left: 0; right: 0; height: 143px; border: 1px solid #000; } .household-content>li:last-child p:last-child{ position: absolute; bottom: 0; left: 0; right: 0; height: 143px; border: 1px solid #000; } .center-video{ height: 343px; background-color: pink; } .video-title{ height: 58px; background-color: black; } .video-content{ height: 285px; } .video-content>li{ float: left; width: 296px; height: 100%; border: 1px solid #000; } .video-content>li+li{ margin-left: 14px; } 复制代码 (5)局部——bottom bottom部分首先是一个水平居中的内容,然后内容可以划分为上下两部分,每个部分都是浮动的li,如图: html代码: <div class="bottom"> <div class="container"> <div class="bottom-service"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <div class="bottom-links"> <div class="links-left"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <div class="links-right"></div> </div> </div> </div> 复制代码 css代码: .bottom { height: 274px; background-color: #fff; } .bottom-service{ height: 80px; background-color: seagreen; } .bottom-service>ul{ height: 100%; } .bottom-service>ul li{ position: relative; padding: 0 50px; float: left; width: 20%; height: 100%; background-color: goldenrod; background-clip: content-box; } .bottom-service>ul li+li::before{ position: absolute; top: 28px; left: 0; content: ''; width: 1px; height: 24px; background-color: #999; } .bottom-links{ height: 192px; background-color: #8545e0; } .links-left{ float: left; width: 960px; height: 100%; background-color: yellow; } .links-left>ul{ height: 100%; } .links-left>ul li{ padding-right: 60px; float: left; width: 16.666666666666667%; height: 100%; border: 1px solid #000; background-color: #ff0000; background-clip: content-box; } .links-right{ float: right; width: 252px; height: 100%; background-color: yellow; } 复制代码 (6)局部——footer footer划分如图: html代码: <div class="footer"> <div class="footer-info"> <div class="info-left"></div> <div class="info-right"></div> </div> <div class="footer-slogan"></div> </div> 复制代码 css代码: .footer { margin: 0 auto; padding: 30px 0; width: 1226px; height: 166px; border: 1px solid #000; } .footer-info{ height: 57px; background-color: #6effb1; } .info-left{ float: left; width: 630px; height: 100%; border: 1px solid #000; } .info-right{ float: right; width: 436px; height: 100%; border: 1px solid #000; } .footer-slogan{ margin-top: 30px; height: 19px; background-color: #8545e0; } 复制代码 (7)全部代码(优化后) html代码: <body> <div class="header"> <div class="container"> <div class="header-left fl"></div> <div class="header-rigth fr"></div> </div> </div> <div class="top"> <div class="container"> <div class="top-nav"></div> <div class="top-slider"> <div class="slider-navbar"></div> </div> <div class="top-recommend"> <div class="recommend-left fl"></div> <div class="recommend-right fr"> <ul> <li></li> <li></li> <li></li> </ul> </div> </div> <div class="top-flashsale"> <div class="flashsale-title common-title"></div> <div class="flashsale-content"> <div class="content-timer fl"></div> <ul class="content-shops"> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> </div> </div> <div class="center"> <div class="center-phone module-box"> <div class="phone-title common-title"></div> <div class="phone-content"> <div class="phone-left fl"></div> <ul class="phone-right"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> <div class="center-household module-box"> <div class="household-title common-title"></div> <div class="household-content"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li> <p></p> <p></p> </li> </div> </div> <div class="center-video"> <div class="video-title common-title"></div> <ul class="video-content"> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> <div class="bottom"> <div class="container"> <div class="bottom-service"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <div class="bottom-links"> <div class="links-left fl"> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <div class="links-right fr"></div> </div> </div> </div> <div class="footer"> <div class="footer-info"> <div class="info-left fl"></div> <div class="info-right fr"></div> </div> <div class="footer-slogan"></div> </div> </body> 复制代码 css代码: /*-------------------抽取公共样式-----------------*/ * { /*为了方便,就这样清空默认样式了*/ margin: 0; padding: 0; box-sizing: border-box; list-style: none; } body { background-color: #f5f5f5; } .container { /*水平居中的内容盒子*/ width: 1226px; height: 100%; margin: 0 auto; border: 1px solid #f00; } .common-title { height: 58px; background-color: #000; } .fl {float: left;} .fr {float: right;} .recommend-right, .flashsale-content, .phone-right > li, .household-content > li:last-child > p, .video-content > li, .links-left > ul li, .footer, .info-left, .info-right {border: 1px solid #000;} /*添加边框样式只是为了方便观察,不是布局必须,可删*/ /*-----header部分-----*/ .header { margin-bottom: 20px; height: 40px; background-color: #333; } .header-left { width: 380px; height: 100%; background-color: #0f0; } .header-rigth { width: 260px; height: 100%; background-color: #0f0; } /*--------top部分--------*/ .top { /*height: 1210px;*/ background-color: #fff; } .top-nav { height: 100px; background-color: #f00; } .top-slider { margin-bottom: 14px; position: relative; /*父相*/ height: 460px; background-color: #00f; } .slider-navbar { position: absolute; /*子绝*/ top: 0; left: 0; width: 234px; height: 100%; background-color: black; opacity: .5; } .top-recommend { margin-bottom: 26px; height: 170px; background-color: #0f0; } .recommend-left { height: 100%; width: 234px; background-color: skyblue; } .recommend-right { width: 978px; height: 100%; } .recommend-right > ul {height: 100%;} .recommend-right > ul li { float: left; /*三列等宽,浮动布局*/ width: 316px; height: 100%; background-color: deepskyblue; } .recommend-right > ul li + li { margin-left: 14px;} /*设置浮动间隔*/ .top-flashsale { height: 438px; background-color: #ff4455; } .flashsale-title {} .flashsale-content { padding-bottom: 40px; height: 380px; } .content-timer { margin-right: 14px; width: 234px; height: 100%; background-color: #fff; } .content-shops { overflow: hidden; /*触发bfc,以达到自适应*/ height: 100%; background-color: #6effb1; } .content-shops > li { float: left; /*四列等宽,浮动布局*/ width: 234px; height: 100%; background-color: #fff; } .content-shops > li + li {margin-left: 12.5px;} /*设置浮动间隔*/ /*--------center部分--------*/ .module-box { /*类似的模块*/ margin-bottom: 8px; height: 686px; } .center { margin: 0 auto; margin-bottom: 60px; padding-top: 60px; width: 1226px; /*height: 1791px;*/ background-color: #fff; } .center-phone {background-color: yellow;} .phone-title {} .phone-content { height: 628px; background-color: pink; } .phone-left { width: 234px; height: 100%; background-color: darkseagreen; } .phone-right { overflow: hidden; /*触发bfc以达到自适应*/ height: 100%; background-color: #ccc; } .phone-right > li { margin-bottom: 28px; /*设置下边距*/ padding-left: 14px; /*用padding模拟盒子间隔*/ float: left; /*四列等宽,浮动布局*/ width: 25%; height: 300px; background-color: #f00; background-clip: content-box; /*背景色从content开始绘起*/ } .center-household {background-color: yellow;} .household-title {} .household-content {height: 614px;} .household-content > li { position: relative; /*父相*/ margin-left: 14px; /*设置浮动间隔*/ margin-bottom: 28px; /*设置下边距*/ float: left; /*五列等宽,浮动布局*/ width: 234px; height: 300px; background-color: #d7d7d7; } .household-content > li:nth-child(1), .household-content > li:nth-child(6) {margin-left: 0; } /*消除每行第一个的间隔*/ .household-content > li:last-child p:first-child { position: absolute; /*子绝*/ top: 0; left: 0; right: 0; height: 143px; } .household-content > li:last-child p:last-child { position: absolute; /*子绝*/ bottom: 0; left: 0; right: 0; height: 143px; } .center-video { height: 343px; background-color: pink; } .video-title {} .video-content {height: 285px;} .video-content > li { float: left; /*四列等宽,浮动布局*/ width: 296px; height: 100%; } .video-content > li + li {margin-left: 14px; } /*设定浮动间隔*/ /*--------bottom部分--------*/ .bottom { /*height: 274px;*/ background-color: #fff; } .bottom-service { height: 80px; background-color: seagreen; } .bottom-service > ul {height: 100%;} .bottom-service > ul li { position: relative; /*父相*/ padding: 0 50px; /*用padding模拟盒子间隔*/ float: left; /*五列等宽,浮动布局*/ width: 20%; height: 100%; background-color: goldenrod; background-clip: content-box; /*背景色从content开始绘起*/ } .bottom-service > ul li + li::before { /*用伪元素模拟分割线*/ position: absolute; /*子绝*/ top: 28px; left: 0; content: ''; /*伪元素必须有content*/ width: 1px; height: 24px; background-color: #999; } .bottom-links { height: 192px; background-color: #8545e0; } .links-left { width: 960px; height: 100%; background-color: yellow; } .links-left > ul {height: 100%;} .links-left > ul li { padding-right: 60px; float: left; /*六列等宽,浮动布局*/ width: 16.666666666666667%; height: 100%; background-color: #ff0000; background-clip: content-box; /*背景色从content开始绘起*/ } .links-right { width: 252px; height: 100%; background-color: yellow; } /*--------footer部分---------*/ .footer { margin: 0 auto; padding: 30px 0; width: 1226px; height: 166px; } .footer-info { height: 57px; background-color: #6effb1; } .info-left { width: 630px; height: 100%; } .info-right { width: 436px; height: 100%; } .footer-slogan { margin-top: 30px; height: 19px; background-color: #8545e0; } 复制代码 以上就是优化后的代码了,由于在下才疏学浅,所用方法不敢保证是最简单的,优化也肯定不是最优的,仅仅是的我的一种思路而已,各位参考参考就好。 8.1.2 Flexbox+Grid搭配用法(未来...) html代码: <body> <div class="header"> <div class="container"> <div class="header-left"></div> <div class="header-rigth"></div> </div> </div> <div class="top"> <div class="container"> <div class="top-nav"></div> <div class="top-slider"> <div class="slider-navbar"></div> </div> <div class="top-recommend-left"></div> <div class="top-recommend-right"> <ul> <li></li> <li></li> <li></li> </ul> </div> <div class="top-flashsale-title"></div> <div class="top-flashsale-timer"></div> <ul class="top-flashsale-shops"> <li></li> <li></li> <li></li> <li></li> </ul> </div> </div> <div class="center"> <div class="center-phone-title"></div> <div class="center-phone-content"> <div class="phone-content-item1"></div> <div class="phone-content-item2"></div> <div class="phone-content-item3"></div> <div class="phone-content-item4"></div> <div class="phone-content-item5"></div> <div class="phone-content-item6"></div> <div class="phone-content-item7"></div> <div class="phone-content-item8"></div> <div class="phone-content-item9"></div> </div> <div class="center-household-title"></div> <div class="center-household-content"> <div class="row"> <div class="household-content-item"></div> <div class="household-content-item"></div> <div class="household-content-item"></div> <div class="household-content-item"></div> <div class="household-content-item"></div> </div> <div class="row"> <div class="household-content-item"></div> <div class="household-content-item"></div> <div class="household-content-item"></div> <div class="household-content-item"></div> <div class="household-content-item"> <p></p> <p></p> </div> </div> </div> <div class="center-video-title"></div> <ul class="center-video-content"> <li></li> <li></li> <li></li> <li></li> </ul> </div> <div class="bottom"> <div class="container"> <div class="bottom-service"> <div class="service-item"></div> <div class="service-item"></div> <div class="service-item"></div> <div class="service-item"></div> <div class="service-item"></div> </div> <div class="bottom-links-left"> <div class="links-left-item"></div> <div class="links-left-item"></div> <div class="links-left-item"></div> <div class="links-left-item"></div> <div class="links-left-item"></div> <div class="links-left-item"></div> </div> <div class="bottom-links-right"></div> </div> </div> <div class="footer"> <div class="footer-info"> <div class="info-left"></div> <div class="info-right"></div> </div> <div class="footer-slogan"></div> </div> </body> 复制代码 css代码: /*-------------------抽取公共样式-----------------*/ * { /*为了方便,就这样清空默认样式了*/ margin: 0; padding: 0; list-style: none; } body { background-color: #f5f5f5; display: grid; /*整体布局 设置网格列,设置网格行,再设定网格区域*/ grid-template-columns: 1fr 1226px 1fr; grid-template-rows: 40px 20px auto auto 274px 166px; grid-template-areas: "header header header" ". . ." "top top top" ". center ." "bottom bottom bottom" ". footer ."; } .container { /*水平居中的内容盒子*/ width: 1226px; height: 100%; margin: 0 auto; border: 1px solid #f00; } .top-recommend-right, .top-flashsale-timer, .top-flashsale-shops li, .center-phone-content > div, .center-household-content .row, .household-content-item:last-of-type p, .center-video-content li, .service-item, .links-left-item, .info-left, .info-right, .info-right {border: 1px solid #000;} /*添加边框样式只是为了方便观察,不是布局必须,可删*/ /*-----header部分-----*/ .header { grid-area: header; /*指定网格区域*/ background-color: #333; } .header .container { display: flex; justify-content: space-between; } .header-left { width: 380px; background-color: #0f0; } .header-rigth { width: 260px; background-color: #0f0; } /*--------top部分--------*/ .top { grid-area: top; /*指定网格区域*/ background-color: #fff; } .top .container { display: grid; /*top部分布局 设置网格行,设置网格列,再设定网格区域*/ grid-template-rows: 100px 460px 14px 170px 26px 58px 340px 40px; grid-template-columns: auto 14px 978px; grid-template-areas: "top-nav top-nav top-nav" "top-slider top-slider top-slider" ". . ." "recommend-left . recommend-right" ". . ." "flashsale-title flashsale-title flashsale-title" "flashsale-timer . flashsale-shops" ". . ."; } .top-nav { grid-area: top-nav; background-color: #f00; } .top-slider { position: relative; grid-area: top-slider; background-color: #00f; } .top-slider .slider-navbar { position: absolute; top: 0; left: 0; bottom: 0; width: 234px; background-color: black; opacity: .5; } .top-recommend-left { grid-area: recommend-left; background-color: skyblue; } .top-recommend-right {grid-area: recommend-right;} .top-recommend-right > ul { display: flex; justify-content: space-between; height: 100%; } .top-recommend-right li { width: 316px; background-color: deepskyblue; } .top-flashsale-title { grid-area: flashsale-title; background-color: #000; } .top-flashsale-timer { grid-area: flashsale-timer; background-color: #fff; } .top-flashsale-shops { display: flex; justify-content: space-between; grid-area: flashsale-shops; background-color: #6effb1; } .top-flashsale-shops li {width: 234px;} /*--------center部分--------*/ .center { margin-bottom: 60px; /*边距可以在网格分区的时候考虑进去,把边距设成一行或一列,不要放内容就好了*/ padding-top: 60px; grid-area: center; /*指定网格区域*/ display: flex; flex-direction: column; background-color: #fff; } .center-phone-title { height: 58px; background-color: black; } .center-phone-content { margin-bottom: 8px; display: grid; /*这里用flex分格更好,代码更少更简洁*/ grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(2, 1fr); grid-template-areas: "big1 normal2 normal3 normal4 normal5" "big1 normal6 normal7 normal8 normal9"; grid-gap: 14px; /*网格间隔*/ height: 628px; background-color: pink; } .phone-content-item1 {grid-area: big1;} .phone-content-item2 {grid-area: normal2;} .phone-content-item3 {grid-area: normal3;} .phone-content-item4 {grid-area: normal4;} .phone-content-item5 {grid-area: normal5;} .phone-content-item6 {grid-area: normal6;} .phone-content-item7 {grid-area: normal7;} .phone-content-item8 {grid-area: normal8;} .phone-content-item9 {grid-area: normal9;} .center-household-title { height: 58px; background-color: black; } .center-household-content { margin-bottom: 8px; display: flex; flex-direction: column; height: 614px; background-color: pink; } .center-household-content .row { display: flex; justify-content: space-between; flex: 1; } .row .household-content-item { display: flex; flex-direction: column; justify-content: space-between; width: 234px; background-color: #fff; } .household-content-item:last-of-type p {height: 143px;} .center-video-title { height: 58px; background-color: black; } .center-video-content { display: flex; justify-content: space-between; height: 285px; background-color: pink; } .center-video-content li {width: 296px;} /*--------bottom部分--------*/ .bottom { grid-area: bottom; /*指定网格区域*/ background-color: #fff; } .bottom .container { display: grid; grid-template-columns: auto 252px; grid-template-rows: 80px auto; grid-template-areas: "service service" "links-left links-right"; } .container .bottom-service { display: flex; grid-area: service; background-color: seagreen; } .service-item {flex: 1;} .container .bottom-links-left { display: flex; grid-area: links-left; background-color: yellow; } .links-left-item {flex: 1;} .container .bottom-links-right { grid-area: links-right; background-color: yellowgreen; } /*--------footer部分---------*/ .footer { padding: 30px 0; grid-area: footer; /*指定网格区域*/ } .footer-info { display: flex; justify-content: space-between; height: 57px; background-color: #6effb1; } .info-left {width: 630px;} .info-right {width: 436px;} .footer-slogan { margin-top: 30px; height: 19px; background-color: #8545e0; } 复制代码 九、其他补充: 9.1 移动端viewport 设置viewport: <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> 复制代码 阅读推荐: 解读 viewport—网页自适应移动 app 神器 https://juejin.im/entry/58e750a02f301e0062367ded 9.2 媒体查询 代码示例: @media (max-width: 767px) { ...css代码... } @media (min-width: 768px) and (max-width: 991px) { ...css代码... } @media (min-width: 992px) and (max-width: 1199px) { ...css代码... } @media (min-width: 1200px) { ...css代码... } 复制代码 阅读推荐: MDN文档介绍 https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Media_queries 随方逐圆 -- 全面理解 CSS 媒体查询 https://juejin.im/entry/595b6208f265da6c3902041e 9.3 REM 阅读推荐: Rem布局的原理解析 http://yanhaijing.com/css/2017/09/29/principle-of-rem-layout/ rem是如何实现自适应布局的? http://caibaojian.com/web-app-rem.html 9.4 Flexbox 阅读推荐 理解Flexbox:你需要知道的一切 https://www.w3cplus.com/css3/understanding-flexbox-everything-you-need-to-know.html 深入理解 flex 布局以及计算 https://www.w3cplus.com/css3/flexbox-layout-and-calculation.html?from=groupmessage 9.5 CSS Grid 原文发布时间为:2018年03月13日 原文作者:Sweet_KK 本文来源掘金如需转载请联系原作者
最初试过 box2dweb 与 cax框架 结合使用,发现 box2dweb 的代码会导致 webpack 编译出的 cax 包模块执行顺序乱套。 box2dweb 貌似也没有官方文档和维护地址,所以弃坑转战 Matter-js。 Matter-js 是 Github 上最流行的 Web 2D 物理引擎,主要有如下特性: 支持刚体、混合体、复合体 支持凹凸多边形刚体 支持刚体间约束条件 内置睡眠与静止身体 物理模拟时间加快变慢 移动兼容(触摸事件和PC鼠标事件响应) 物理性质(质量、面积、密度、动量守恒、摩擦阻力、重力、弹性或非碰撞检测以及恢复等) 开始结合 Cax 和 Matter-js 引入 js 先在 HTML 引入 matter-js 和 cax, 你可以通过 npm 或 cdn 获取 js: unpkg.com/matter-js unpkg.com/cax 准备工作 页面添加 Canvas <canvas id="myCanvas" width="800" height="600"></canvas> 复制代码 提前声明好变量: var Engine = Matter.Engine, Render = Matter.Render, World = Matter.World, Bodies = Matter.Bodies, Composites = Matter.Composites, Body = Matter.Body, Constraint = Matter.Constraint, MouseConstraint = Matter.MouseConstraint, Common = Matter.Common, Events = Matter.Events, Composite = Matter.Composite 复制代码 创建刚体 Bodies.rectangle(100, 49, 800, 44, { isStatic: true }) 复制代码 前四个参数分别代表 x y width height。需要注意的是 x 和 y 是矩形中心的坐标 isStatic 为 true 的话代表是静止刚体,不传或者传 false 为可运动刚体。 创建四面墙并添加到世界 // 创建引擎 var engine = Engine.create(); // 创建四面墙壁墙壁并添加到世界 var offset = 10; World.add(engine.world, [ Bodies.rectangle(400, 600 - offset, 800, offset * 2, { isStatic: true }), Bodies.rectangle(400, offset, 800, offset * 2, { isStatic: true }), Bodies.rectangle(offset, 300, offset * 2, 600, { isStatic: true }), Bodies.rectangle(800 - offset, 300, offset * 2, 600, { isStatic: true }), ]); 复制代码 创建物体并添加到世界 var stack = Composites.stack(20, 20, 6, 4, 0, 0, function (x, y) { if (Common.random() > 0.5) { return Bodies.rectangle(x, y, 64, 64, { bitmap: new cax.Bitmap("img/box.jpg") }); } else { return Bodies.circle(x, y, 46, { desity: 0.0005, frictionAir: 0.06, friction: 0.01, bitmap: new cax.Bitmap("img/basketball.png"), }); } }); World.add(engine.world, stack); 复制代码 通过Composites.stack(xx, yy, columns, rows, columnGap, rowGap, callback)可以用来创建物体堆。 参数xx,yy分别为物体堆中第一个物体的x和y坐标,columns和 rows分别为所要创建的物体堆的列数和行数,columnGap和rowGap分别为物体与物体之间的列间隙和行间隙,最后,由var body = callback(x, y, column, row, lastBody, i); 可以看出callback为生成的具体物体的方法。 看以看到,创建的时候挂在 bitmap 上去用户后续的渲染。 发动引擎 Engine.run(engine) 复制代码 初始化渲染墙壁和物体 var bodies = Composite.allBodies(engine.world); for (var i = 0; i < bodies.length; i += 1) { var obj = bodies[i] if (obj.bitmap) { obj.bitmap.x = obj.position.x obj.bitmap.y = obj.position.y if (obj.label === 'Circle Body') { obj.bitmap.scaleX = obj.bitmap.scaleY = 92 / 128 obj.bitmap.originX = 64 obj.bitmap.originY = 64 obj.bitmap.rotation = obj.angle * 180 / Math.PI } else { obj.bitmap.scaleX = obj.bitmap.scaleY = 64 / 200 obj.bitmap.originX = 100 obj.bitmap.originY = 100 obj.bitmap.rotation = obj.angle * 180 / Math.PI } stage.add(obj.bitmap) } } //墙壁 var topRect = new cax.Rect(800, 20, { fillStyle: '#2CB044' }) stage.add(topRect) var bottomRect = new cax.Rect(800, 20, { fillStyle: '#2CB044' }) bottomRect.y = 600 - 20 stage.add(bottomRect) var leftTop = new cax.Rect(20, 600, { fillStyle: '#2CB044' }) stage.add(leftTop) var rightRect = new cax.Rect(20, 600, { fillStyle: '#2CB044' }) rightRect.x = 800 - 20 stage.add(rightRect) 复制代码 通过 Composite.allBodies 可以拿到所以刚体 通过设置 bitmap 的 scaleX 和 scaleY 可以使 刚体大小和纹理大小对应起来 更新渲染舞台 cax.setInterval(function () { var bodies = Composite.allBodies(engine.world); for (var i = 0; i < bodies.length; i += 1) { var obj = bodies[i] if (obj.bitmap) { obj.bitmap.x = obj.position.x obj.bitmap.y = obj.position.y obj.bitmap.rotation = obj.angle * 180 / Math.PI } } stage.update() }, 16) 复制代码 添加 Matter-js 内置 Debug Canvas var render = Render.create({ element: document.body, engine: engine, options: { wireframes: false } }); var renderOptions = render.options; renderOptions.wireframes = true; Render.run(render); 复制代码 最终效果: 原文发布时间为:2018年06月26日 原文作者:当耐特 本文来源掘金如需转载请联系原作者
0.引言 在我们编写CSS的时候,经常会用到百分比赋值(%)实现自适应。像我们最常使用的流式布局设计模式,基本所有的column的宽度都是通过%来取值的。或者比如经常会遇到的元素水平垂直居中问题,我们常常会使用下面这样的CSS代码加以实现(absolute+transform思路): .wrap { position:absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); } 复制代码 大家因为经常使用,肯定都知道前面两个50%指的是wrap的定位参照物的宽、高的50%,而translate()里的50%指的是wrap自身,这应该不会有什么疑问,但在这简单的三行代码中,就出现了两类不同的%值,一种是相对于参照物盒子的,一种是相对自身的。不过你以为CSS世界里就只有这两类百分比值吗?一切可没这么简单,下面我会列举出不同的情况下%值的参照对象,且听我娓娓道来。 1.第一类——定位类 熟悉的小伙伴都知道CSS中的定位分为四种,默认值static,相对定位relative,绝对定位absolute还有固定定位fixed。虽然说每一类定位的%值的参照物都各不相同,但因为都具有定位的特殊性质,所以我把它们归为一类,现在对四种不同的定位分类讨论: static:这个就不用说了吧,position的默认值,并没有对元素起到定位的作用,所以left、right等位置属性并不能被有效赋值,所以不存在在定位功能上的%值。 absolute:作为一个最为常用的定位属性,absolute不知道给多少前端小白挖了数不清的坑,相信大家早年在这上面学习的过程都是艰辛的。不扯远了,给一个元素absolute定位后就可以赋予left等位置值,参照物就是祖先元素中存在定位的元素,那么自然而然,位置值如果取得是%,那么这个%相对的元素便是这个参照物。left、right是相对于width,top和bottom是相对于height,这我就不必多说了吧。 relative:小伙伴们肯定都听说过子绝父相,而且肯定经常用,那么relative它是相对与自身定位的,那么位置值自然就是相对于自身的宽高喽。 fixed:这是一个很特殊的定位值,因为我们知道它是相对于视窗定位的,那么自然%的参照物便是视窗了。 2.第二类——盒子模型 在一个盒子模型内有很多特别常见的属性值,大家天天用也天天看,就是这些:width,height,margin,border,padding,width和height就不用说了,是相对于父盒子的,重点讲下margin和padding margin&padding:这两个小伙子很特别,如果设置了%值,那么他们参照的是父元素的宽度!!父元素的宽度!!!父元素!!!宽度!!!重要的事情说三遍,不信的话我们可以亲手试试。的确很奇葩,不过你还真得记住,别开发的时候糗了你还以为是BUG。我们可以使用padding的这一特殊性质实现16:9或4:3等各比例响应式图片、视频盒子的构建。 border:border的话我一般是没见过有人用%的值,如果你在开发的时候用的是%,请收下我的膝盖。这边要讲的实际上是border-width,因为border实际上是个简写属性。其实是骗你们的啦,border-width目前还不允许输入%值,未来会不会允许并且参照的是谁都还是未知,如果你写了%的值浏览器是不会渲染的哦,所以border不存在%值。 border-radius:既然说到了border,就顺带提一下border-radius,圆角。平时我们用这个属性的时候基本都是给他赋4个参数,代表四个角,分别是左上、右上、右下、左下,以顺时针的顺序排序。但实际上,border-radius最多可以取八个值,前四个值和后四个值用 / 隔开,斜杠前表示各角水平方向上的圆角半径,斜杠后表示各角竖直方向上的圆角半径。范例如下: border-radius:top-left|top-right|bottom-right|border-left / top-left|top-right|bottom-right|border-left 复制代码 3.第三类——背景值 background-size:设置背景时常用的属性,虽然我们平时常用contain或者cover代替,但是当我们想要让背景充满整个盒子的时候,也会这样子写: background-size:100% 100%; 复制代码 因此,background-size的参照物和border-radius一样,都是盒子自身的宽高。 background-position:这个属性和relative类似,起到的也是定位的效果,因此它的参照对象就是原盒子。但是这个属性比较特殊,他不是参照原盒子的宽高值,而是原盒子的宽高值减去背景图片的宽高值所得到的剩余值,更为形象的说,下面这两个属性值是等价的:"center center"和"50% 50%",如果你设置了后者,背景图片会自动居中,不用像定位那样还需要transform偏移了。这应该是优秀的前人在设计这个属性的时候就考虑到它将来的应用了吧。 4.第四类——transform translate():在第一个模块中,我们讲到了这样一个属性:translate(),在CSS3中还有还有translate3d(),这个属性的含义想必大家都知道,就是在指定方向上进行2d偏移,它的参照物是自身的宽高。而transform3d()的第三个属性,指的是在z轴上的偏移,因为z-index的默认值是auto,所以%值并不能起作用,也就是说对translateZ()赋予百分比的值是无意义的。 transform-origin:这个属性是改变元素变形的原点,它和width还有height的特点一模一样,这里就不作过多详述了。 scale():控制元素的缩放比例,传入的参数是一般是浮点数,指的是相对于元素本身放大或缩小的比例。 zoom:zoom并不是transform的属性值,它是一个独立的CSS属性,之所以把他放在transform这一个模块讨论,是因为恰好它与scale()有共同的特征,它的取值既可以是浮点数,也可以是%,包括参照物,都与scale()等价。 5.第五类——字体 font-size:这个属性和我们的height一样,是参照父盒子的字体大小的。 line-height:我们所说的行高也是很特别的一个属性,如果给它赋予不同类型的值,会有不同的特性。如果它的属性值是一个无单位的数字,那么最后的结果便是这个数字与该元素字体大小的乘积。这是我们设置line-height的首选方法,因为字体大小font-size是继承自祖代元素的,通过这个方法设置的值基本不会出现异常情况。但如果我们的值是%,最后的结果是给定的百分比值乘以元素最后计算出的字体大小。 text-indent:这个属性是用来设置首行缩进的,我们最长用的是2em,首行缩进两个字符,这边的2em指的就是两倍的font-size,按道理来说如果它取%应该也是要相对于本身的font-size的,但是偏偏就那么特别,和padding和margin一样,如果设置的是%,则参照的是父元素的width。这应该算是一个特例吧。 6.结语 大家可能大概看一遍下来还是一脸懵逼,为了给大家加强记忆,我就以参照物的不同类别为主线做个总结: 相对于父盒子: 最常见的应该就算是参照父盒子(containing box)的属性,但是还有一些特例参照的是父盒子的width,只有这个类别还需要分两类讨论: 相对于盒子自身: 以盒子自身为参照的属性就比较多了,参照的属性一般也是与自身有关联的属性,属于这一类的属性值有:定位中的relative;盒子模型中的border-radius;背景中的background-size;背景中的background-position比较特殊,还记得吗,它需要减去你的背景图片的宽高,你可以联想到flex布局中的flex属性值;在transform变换中,translate()、transform-origin、scale()还有我们拓展的与transform相似的zoom属性,他们都是参照自身的;line-height行高与它的字体大小有关,所以参照的就是自身的font-size。 相对于定位元素: 因为定位的性质比较特殊,所以将他单独分出一类,定位元素参照的是他的定位对象,因为relative是相对于自身定位,所以我把他归为相对盒子自身一类中去了,其他的属性值我们都可以看作是参照他们的定位元素。 文章列出的所有属性具体的一些属性值的特性可以参考MDN官网,其实像上文列出的属性,我们并不需要全部去记忆,也很难做到把所有的都记下来,很多时候,我们只需要自己在浏览器中测试一下就知道这些CSS是参照谁的啦。 最后留下一个小问题,如果不用px,只用%,如何实现一个宽高相等的正方形div? 成文不易,希望大家能多多支持,如果您有补充,欢迎在评论区里提出,谢谢。 原文发布时间为:2018年05月28日 原文作者:腾讯课堂NEXT学位 本文来源掘金如需转载请联系原作者
我们都学过javascript的面向对象,在我学习的过程中,一度有个问题困扰着我,那就是在构造函数中,如果使用了this,那么这个this指向的是谁?如果在定义的原型方法中使用了this,那么这个this又指向谁了?是构造函数、原型、还是实例?到底是谁在决定? function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function() { return this.name; } var p1 = new Person('pan', 18); p1.getName();复制代码 构造函数其实就是普通的函数,而this是在函数运行时才确定的。那么是什么导致构造函数变得如此特别了? 与new 关键字有关 如果我们自定义一个New方法,来模拟关键字new的能力,那么会有如下实现(在此之前请先回忆一下new 一个函数 会发生什么.,如果您没有想起来,那就记住new一个函数,生成一个实例对象)。 //将构造函数以参数形式传入 function New(func) { //声明一个中间对象,该对象为最终返回的实例 var res = {}; if(func.prototype !== null) { //将实例的原型指向构造函数的原型 res.__proto__ = func.prototype; } //ret为构造函数执行的结果,这里通过apply, //将构造函数内部的this指向修改为指向res,即为实例对象 var ret = func.apply(res, Array.prototype.slice.call(arguments,1)) //当在构造函数中明确指定了返回对象时,那么new的执行结果就是该返回对象 if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) { return ret; } //如果没有明确指定返回对象,则默认返回res,这个res就是实例对象 return res; }复制代码 为了方便大家理解,例子中做了一些注解。通过New 方法的实现可以看出,执行时,利用apply设定了传入的构造函数的this指向,因此当使用New方法创建实例时,构造函数中的this就指向了被创建的实例。 如果把当前函数看成基础函数,那么高阶函数,就是让当前函数获得额外能力的函数。如果把构造函数看成基础函数,那么New方法,就是构造函数的高阶函数。构造函数本就和普通函数一样,没有什么区别。但是因为New的存在,它获得了额外的能力。New方法每次执行都会创建一个新的中间对象,并将中间对象的原型指向构造函数的原型,将构造函数的this指向该中间对象。这样统一逻辑的封装,就是高阶函数的运用。 当然,如果简单粗暴一点来理解,则凡是接收一个函数作为参数的函数,就是高阶函数。但是如果这样理解,那么我们还是用不好高阶函数。因为正如阳波大神所说,高阶函数其实是一个高度封装的过程,理解它需要点想象力。那么在接下来的系列中,就借助几个例子,来理解高阶函数的封装。 原文发布时间为:2018年06月17日 原文作者:Panthon 本文来源掘金如需转载请联系原作者
我曾见过很多很多人盲目地使用(前端)框架,如 React,Angular 或 Vue等等。这些框架提供了许多有意思的东西,然而通常人们(自以为)使用框架是因为: 它们支持组件化; 它们有强大的社区支持; 它们有很多(基于框架的)第三方库来解决问题; 它们有很多(很好的)第三方组件; 它们有浏览器扩展工具来帮助调试; 它们适合做单页应用。 但这些都不是使用框架的根本原因。 最最本质的原因是: (UI 与状态同步非常困难) 是的,就是这原因,让我们来看看为什么 假设你正在设计这样一个 Web 应用:用户可以通过群发电子邮件来邀请其他人(参加某活动)。UX/UI 设计师设计如下:(在用户填写任何邮箱地址之前,)有一个空白状态,并为此添加一些帮助信息;(当用户填写邮箱之后,)展示邮箱的地址,每个地址的右侧均有一个按钮用于删除对应的地址。 这个表单的状态,可以被设计为一个数组,里面包含若干对象,对象由邮箱地址和唯一标识组成。开始的时候,数组为空。当(用户)输入邮箱地址并按下回车键之后,往数组中添加一项并更新 UI。当用户点击删除按钮时,删除(数组中对应的)邮箱地址并更新 UI。你感觉到了吗?每当你改变状态时,你都需要更新 UI。 (你可能会说:)那又怎样?好吧,让我们看看如何在不用框架的情况下实现它: 用原生(JS)实现相对复杂的 UI 以下代码很好地说明了使用原生 JavaScript 实现一个相对复杂的 UI 所需的工作量,使用像 jQuery 这样经典的库也需要差不多的工作量。 在这个例子中,HTML 负责创建静态页面,JavaScript 通过 document.createElement 动态改变(DOM 结构)。这引来了第一个问题:构建 UI 相关的 JavaScript 代码并不直观易读,我们将 UI 构建分为了两部分(译者注:应该是指 HTML与 JavaScript 两部分)。尽管我们使用了 innerHTML,可读性是增强了,但降低了(页面的)性能,同时可能存在 CSRF 漏洞。我们也可以使用模板引擎,但如果是大面积地修改 DOM,会面临两个问题:效率不高与需要重新绑定事件处理器。 但这也不是(不使用框架的)最大问题。最大的问题是每当状态发生改变时都要(手动)更新 UI。每次状态更新时,都需要很多代码来改变 UI。当添加电子邮件地址时,只需要两行代码来更新状态,但要十三行代码更新 UI。(此例中)我们已经让 UI(界面与逻辑)尽可能简单了!! 代码既难写又难理解,更麻烦的是它非常脆弱。假设我们需要(添加)同步服务器数据到邮件地址列表的功能,我们需要对比服务器返回结果与数组中数据的差异。这涉及对比所有数据的标识与内容,(当用户修改后,)可能需要在内存中保留一份标识相同但内容不同的数据。 为了高效地改变 DOM,我们需要编写大量点对点(译者注:指状态到 UI)的代码。但只要你犯下了很小的错误,UI 与状态将不再保持同步:(可能会出现)丢失或呈现错误的信息、不再响应用户的操作,更糟糕的是触发了错误的动作(如点了删除按钮后删除了非对应的一项)。 因此,保持 UI 与状态同步,需要编写大量乏味且非常脆弱的代码。 响应式 UI 拯救一切 所以,(之所以使用框架,)不是因为社区,不是因为工具,不是因为生态,不是因为第三方库...... 目前为止,框架最大的改进是(为我们)提供了应用内部状态与 UI 同步的可靠保证。 只要你清楚特定框架的某些(特定)规则(如不可变状态),就差不多(可以正常使用)了。 我们只需要定义一次 UI 界面,不再需要为每个操作编写特定的 UI 代码,同时,每个相同的状态均有相同的输出(译者注:指 UI 一致):当状态改变后,框架自动更新(对应的)视图。 框架是如何工作的呢? 基于两个基本的策略: 重新渲染整个组件,如React。当组件中的状态发生改变时,在内存中计算出(新的)DOM 结构后与已有的 DOM 结构进行对比。实际上,这是非常昂贵的。因而采取(将真实 DOM)映射为虚拟 DOM ,通过对比状态变化前后虚拟 DOM 的不同,计算出变化后再改变真实 DOM 结构。这个过程称为调和(reconciliation)。 通过(添加)观察者监测变化,如 Angular 和 Vue.js。应用中状态的属性会被监测,当它们发生变化时,只有依赖了(发生变化)属性的 DOM 元素会被重新渲染。 那 Web components 呢? 很多时候,人们会把 React、 Angular 和 Vue.js (等框架)与 Web components 进行对比。这显然体现了人们并不理解这些框架所提供的最大好处:保持 UI 与状态同步。Web components 并不提供这种同步机制。它仅仅提供了一个<template>标签,但它不提供任何(状态与 UI 之间的)协调机制。如果你在应用中使用 Web components 时,想保持 UI 与内部状态同步,则需要(开发者)手工完成,或者使用如 Stencil.js (内部和 React一样,使用虚拟 DOM)之类的库。 让我们明确一点:框架表现出的巨大潜力并不体现在组件化上,保持 UI 与状态同步才是具体的体现。Web components 并未提供相关的功能,你必须手工或使用第三方库去解决(同步的)问题。使用原生 JavaScript 去编写复杂、高效且易于维护的 UI 界面基本上是不可能的。这就是你需要使用现代 JavaScript 框架的根本原因。 自己动手,丰衣足食 如果热衷于了解底层原理,想知道虚拟 DOM 的具体实现。那,为何不试着在不使用框架的情况下,仅使用虚拟 DOM 来重写原生 UI呢? 这里是框架的核心,所有组件的基础类。 这里是重写后的 AddressList 组件(借助 babel 来支持 JSX 的转换)。 现在 UI 是声明式的,我们并未使用任何框架。我们能任意添加新逻辑来改变状态的同时,不需要编写额外的代码来保持 UI 同步。问题解决了! 现在,除了事件处理之外,这看起来就像个 React 应用对吧?我们有haverender()、componentDidMount()、setState()等等。一旦解决了保持应用内 UI 与状态的同步问题,所有东西就会很自然地叠加起来(形成组件)。 可以在这个 Github 仓库中找到完整的源代码。 原文发布时间为:2018年06月02日 原文作者:sea_ljf 本文来源掘金如需转载请联系原作者
首先在使用 vue create my-project 创建项目的时候要选择使用 css 预处理器。 安装 vue-cli 首先使用 npm 安装 vue-cli v3.0。 npm install -g @vue/cli 复制代码 安装完成后使用 vue -V 查看版本号,如果显示版本号说明安装完成。 创建项目 vue-cli v3.0 创建项目的命令与 2.0 有所不同。3.0 创建项目的命令为: vue create test-project 复制代码 创建过程中首先选择创建的模式,是采用默认配置,还是自定义配置: 通过上下箭头进行选择。window 默认 cmd 可能不支持箭头上下选择,建议下载其他 shell 工具。 建议采用 Mannual select features 自定义模式。这样可以自主选择需要的插件。 因为我之前创建过一次,所以创建了一个命名为 walle 的模板,下次创建的时候可以直接按照上次的模板进行创建。 选择自定义模式后可以自由选择想要在项目中使用的插件,用空格键选中。 如果选择了 CSS Pre-processors (CSS预处理器), 则接下来会让你选择预处理器的类型。 我选择了相对比较熟悉的 SCSS/SASS 预处理器。这样就可以在项目中使用 SCSS 语法和 SASS 语法了。关于如何在项目中使用 SCSS/SASS 请看我的另一篇博客。 接下来会让你选择 lint 的模式,也就是检测代码的规则。 选择每次保存时进行代码规则校验。 选择配置文件的集成方式,是配置在独立文件中,还是全都配置在 package.json 文件中。因为在独立文件中比较容易看,所以建议选择使用独立文件。 最后就是询问你是否将此次的配置生成一个模板,下次直接之后模板配置直接生成项目了。 确定后就开始了漫长的项目生成之旅了。(第一次使用 vue-cli 进行项目生成可能会卡主,一直不动,这时候按一下 enter 键项目就能继续生成了) 作者:沈鑫Real原文发布时间为:2018年06月15日 原文作者:沈鑫Real 本文来源掘金如需转载请联系原作者
作者:百度外卖 耿彩丽 李宗原 转载请标明出处复制代码 引言 最近笔者和小伙伴在研究Vue SSR,但是市面上充斥了太多的从0到1的文章,对大家理解这其中的原理帮助并不是很大,因此,本文将从Vue SSR的构建流程、运行流程、SSR的特点和利弊这几方面对Vue SSR有一个较为详细的介绍。最后还将附上一个笔者实现的去除Vue全家桶的Demo案例。 剖析构建流程 首先我们镇上一张官网给出的构建图: Vue SSR构建流程 app.js入口文件 app.js是我们的通用entry,它的作用就是构建一个Vue的实例以供服务端和客户端使用,注意一下,在纯客户端的程序中我们的app.js将会挂载实例到dom中,而在ssr中这一部分的功能放到了Client entry中去做了。 两个entry 接下里我们来看Client entry和Server entry,这两者分别是客户端的入口和服务端的入口。Client entry的功能很简单,就是挂载我们的Vue实例到指定的dom元素上;Server entry是一个使用export导出的函数。主要负责调用组件内定义的获取数据的方法,获取到SSR渲染所需数据,并存储到上下文环境中。这个函数会在每一次的渲染中重复的调用。 webpack打包构建 然后我们的服务端代码和客户端代码通过webpack分别打包,生成Server Bundle和Client Bundle,前者会运行在服务器上通过node生成预渲染的HTML字符串,发送到我们的客户端以便完成初始化渲染;而客户端bundle就自由了,初始化渲染完全不依赖它了。客户端拿到服务端返回的HTML字符串后,会去“激活”这些静态HTML,是其变成由Vue动态管理的DOM,以便响应后续数据的变化。 剖析运行流程 到这里我们该谈谈ssr的程序是怎么跑起来的了。首先我们得去构建一个vue的实例,也就是我们前面构建流程中说到的app.js做的事情,但是这里不同于传统的客户端渲染的程序,我们需要用一个工厂函数去封装它,以便每一个用户的请求都能够返回一个新的实例,也就是官网说到的避免交叉污染了。 然后我们可以暂时移步到服务端的entry中了,这里要做的就是拿到当前路由匹配的组件,调用组件里定义的一个方法(官网取名叫asyncData)拿到初始化渲染的数据,而这个方法要做的也很简单,就是去调用我们vuex store中的方法去异步获取数据。 接下来node服务器如期启动了,跑的是我们刚写好的服务端entry里的函数。在这里还要做的就是将我们刚刚构建好的Vue实例渲染成HTML字符串,然后将拿到的数据混入我们的HTML字符串中,最后发送到我们客户端。 打开浏览器的network,我们看到了初始化渲染的HTML,并且是我们想要初始化的结构,且完全不依赖于客户端的js文件了。再仔细研究研究,里面有初始化的dom结构,有css,还有一个script标签。script标签里把我们在服务端entry拿到的数据挂载了window上。原来只是一个纯静态的HTML页面啊,没有任何的交互逻辑,所以啊,现在知道为啥子需要服务端跑一个vue客户端再跑一个vue了,服务端的vue只是混入了个数据渲染了个静态页面,客户端的vue才是去实现交互的! chrome network 顺着前面的思路,我们该看客户端的entry了。在这里客户端拿到存在window中的数据混入我们客户端的vuex中,然后分析数据去执行我们熟悉的其余客户端操作了。 SSR独特之处 在SSR中,创建Vue实例、创建store和创建router都是套了一层工厂函数的,目的就是避免数据的交叉污染。 在服务端只能执行生命周期中的created和beforeCreate,原因是在服务端是无法操纵dom的,所以可想而知其他的周期也就是不能执行的了。 服务端渲染和客户端渲染不同,需要创建两个entry分别跑在服务端和客户端,并且需要webpack对其分别打包; SSR服务端请求不带cookie,需要手动拿到浏览器的cookie传给服务端的请求。实现方式戳这里。 SSR要求dom结构规范,因为浏览器会自动给HTML添加一些结构比如tbody,但是客户端进行混淆服务端放回的HTML时,不会添加这些标签,导致混淆后的HTML和浏览器渲染的HTML不匹配。 性能问题需要多加关注。 vue.mixin、axios拦截请求使用不当,会内存泄漏。原因戳这里 lru-cache向内存中缓存数据,需要合理缓存改动不频繁的资源。 可能是把双刃剑 SSR的优点 更利于SEO。 不同爬虫工作原理类似,只会爬取源码,不会执行网站的任何脚本(Google除外,据说Googlebot可以运行javaScript)。使用了Vue或者其它MVVM框架之后,页面大多数DOM元素都是在客户端根据js动态生成,可供爬虫抓取分析的内容大大减少。另外,浏览器爬虫不会等待我们的数据完成之后再去抓取我们的页面数据。服务端渲染返回给客户端的是已经获取了异步数据并执行JavaScript脚本的最终HTML,网络爬中就可以抓取到完整页面的信息。 更利于首屏渲染 首屏的渲染是node发送过来的html字符串,并不依赖于js文件了,这就会使用户更快的看到页面的内容。尤其是针对大型单页应用,打包后文件体积比较大,普通客户端渲染加载所有所需文件时间较长,首页就会有一个很长的白屏等待时间。 SSR的局限 服务端压力较大 本来是通过客户端完成渲染,现在统一到服务端node服务去做。尤其是高并发访问的情况,会大量占用服务端CPU资源; 开发条件受限 在服务端渲染中,created和beforeCreate之外的生命周期钩子不可用,因此项目引用的第三方的库也不可用其它生命周期钩子,这对引用库的选择产生了很大的限制; 学习成本相对较高 除了对webpack、Vue要熟悉,还需要掌握node、Express相关技术。相对于客户端渲染,项目构建、部署过程更加复杂。 去除VUEX的SSR实践 先附上demo地址,戳这里! 说在前面: vue-router不是必须的,不用router其实做个vue的preRender就可以了,完全没必要做ssr; vuex不是必须的,vuex是实现我们客户端和服务端的状态共享的关键,我们可以不使用vuex,但是我们得去实现一套数据预取的逻辑; 官网的demo大而全,集成了vue-router和vuex,想想我们的项目如果没有使用到这两者,光引入就又需要改造成本,这并不是我们想搞的“丝滑般”过渡,接下来笔者将带领大家一步一步的做个“啥都没有的”demo。 在此笔者的思路是:构造一个Vue的实例,那么我们可以用这个实例的data来存储我们的预取数据,而用methods中的方法去做数据的异步获取,这样我们只在需要预取数据的组件中去调用这个方法就可以了。 首先我们需要让我们的组件“共享”这个EventBus,为此笔者简单的封装了一个plugin: export default { install (Vue) { const EventBus = new Vue({ data () { return { list: [], nav: [] } }, methods: { getList () { // get list }, getNav () { // get nav } } }) Vue.prototype.$events = EventBus Vue.$events = EventBus } } 复制代码 然后我们需要在main.js中export出我们的EventBus以便两个entry使用。这样我们的main.js就像下面这样: import Vue from 'vue' import App from './App' import EventBus from './event' Vue.use(EventBus) Vue.config.devtools = true export function createApp () { const app = new Vue({ // 注入 router 到根 Vue 实例 router, render: h => h(App) }) return { app, router, eventBus: app.$events } } 复制代码 接下来是我们的两个entry了。server用来匹配我们的组件并调用组件的asyncData方法去获取数据,client用来将预渲染的数据存储到我们eventBus中的data中。 // server import { createApp } from './main' export default context => { return new Promise((resolve, reject) => { const { app, eventBus, App } = createApp() // 这里笔者的demo比较简单,仅app组件需要预取数据,复杂业务可以递归遍历哈; const matchedComponents = [App] Promise.all(matchedComponents.map(({ asyncData }) => asyncData && asyncData({ eventBus }))).then(() => { context.state = eventBus._data resolve(app) }).catch(reject) }) } // client import Vue from 'vue' import { createApp } from './main' const { app, eventBus } = createApp() if (window.__INITIAL_STATE__) { eventBus._data = window.__INITIAL_STATE__ } app.$mount('#app') 复制代码 然后我们需要改造我们的组件了,只需要定义一个async方法去调用EventBus中的方法获取,考虑到服务端只会执行beforeCreate和created两个生命周期而beforeCreate不能拿到data,所以我们需要在created中去做数据的获取。 // 服务端渲染数据预取; asyncData ({ store, eventBus }) { return eventBus.getNav() } // 将服务端拿到的数据混入vue组件中; created () { this.nav = this.$events.nav } 复制代码 然后是webpack的改造了,webpack的配置其实和纯客户端应用类似,为了区分客户端和服务端两个环境我们将配置分为base、client和server三部分,base就是我们的通用基础配置,而client和server分别用来打包我们的客户端和服务端代码。 首先是webpack.server.conf.js,用于生成server bundle来传递给createBundleRenderer函数在node服务器上调用,入口文件是我们的entry-server: const webpack = require('webpack') const merge = require('webpack-merge') const nodeExternals = require('webpack-node-externals') const baseConfig = require('./webpack.base.conf.js') const VueSSRServerPlugin = require('vue-server-renderer/server-plugin') // 去除打包css的配置 baseConfig.module.rules[1].options = '' module.exports = merge(baseConfig, { entry: './src/entry-server.js', // 以 Node 适用方式导入 target: 'node', // 对 bundle renderer 提供 source map 支持 devtool: '#source-map', output: { filename: 'server-bundle.js', libraryTarget: 'commonjs2' }, externals: nodeExternals({ whitelist: /\.css$/ }), plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), 'process.env.VUE_ENV': '"server"' }), // 这是将服务器的整个输出 // 构建为单个 JSON 文件的插件。 // 默认文件名为 `vue-ssr-server-bundle.json` new VueSSRServerPlugin() ] }) 复制代码 其次是webpack.client.conf.js,这里我们可以根据官方的配置生成clientManifest,自动推断和注入资源预加载,以及 css 链接 / script 标签到所渲染的 HTML。入口是我们的client-server: const webpack = require('webpack') const merge = require('webpack-merge') const base = require('./webpack.base.conf') const VueSSRClientPlugin = require('vue-server-renderer/client-plugin') const config = merge(base, { entry: { app: './src/entry-client.js' }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), 'process.env.VUE_ENV': '"client"' }), new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function (module) { return ( /node_modules/.test(module.context) && !/\.css$/.test(module.request) ) } }), // 这将 webpack 运行时分离到一个引导 chunk 中, // 以便可以在之后正确注入异步 chunk。 // 这也为你的 应用程序/vendor 代码提供了更好的缓存。 new webpack.optimize.CommonsChunkPlugin({ name: 'manifest' }), new VueSSRClientPlugin() ] }) 复制代码 从localhost中我们看到ssr预取的数据已经成功出来了,大功告成! 结语 本文介绍了Vue的SSR的构建和运行流程,也分析了SSR的特点和利弊,希望对大家了解SSR有一定的帮助。最后针对不使用vuex的SSR实现方案进行了介绍,如果感兴趣或者有疑问,欢迎大家留言交流。 原文发布时间为:2018年05月24日 原文作者:百度外卖 耿彩丽 李宗原 本文来源掘金如需转载请联系原作者
DOM0 html标签中的写法 <image id="element" src="hello.png" onclick="alert('Hi')"/> 复制代码 在JS中的绑定方法: var element = document.getElementById("element"); element.onclick = function(e) {} 复制代码 dom0是节点元素的私有属性。同一个事件只能绑定一个,绑定多个,只有最后一个有效。直接写在html节点上的也会被覆盖。如下面的代码,最后点击触发的时候只会打印3。 var element = document.getElementById("element"); element.onclick = function(e) {console.log(1)}; element.onclick = function(e) {console.log(2)}; element.onclick = function(e) {console.log(3)}; 复制代码 所以,在使用如window.onload之类的事件的时候就需要注意了。 DOM1 有标准,不涉及实践。 DOM2 addEventListener方法在节点对象的原型链上。绑定实名函数更好,因为可以移除。第三个参数用于选择在什么阶段触发,默认false表示在冒泡阶段触发。 element.addEventListener('change',function(){},false) 复制代码 与DOM0的相比,DOM2事件可以绑定多个,如下,1和2都会被打印: element.addEventListener('change', function() {console.log(1)}, false); element.addEventListener('change', function() {console.log(2)}, false); 复制代码 可是,在绑定实名函数的时候,如果事件、函数名和触发阶段完全相同的话,最终也是只有最后一个有效,如下,最终事件触发的时候只会打印出一个1: function fn() {console.log(1)}; element.addEventListener('change', fn, false); element.addEventListener('change', fn, false); 复制代码 此外,addEventListener还可以绑定DOM0中没有的事件,如DOMContentLoaded。 DOM3 与DOM2的区别在于事件的种类,其他的一样。如keyup、keydown、keypress都是DOM3的事件,click也是DOM3级事件,具体到MDN中搜索DOM L3。 事件流 简要的说就是事件的三个阶段:捕获阶段--目标阶段--冒泡阶段。详细说就是如下图。 当用户点击浏览器窗口,事件发生,捕获阶段开始:window--document--html--body--父节点--目标节点(目标阶段),然后开始冒泡阶段:目标节点--父节点--body--html--document--window。 几个需要注意的api: preventDefault的作用是阻止浏览器默认行为,什么是默认行为?除了你自己绑定的操作之外的行为都是浏览器的默认行为,如a标签的跳转,表单的提交,鼠标右键呼出菜单等等。 此外event.returnValue = false;、return false;也可以达到跟proventDefault同样的效果。如果是a标签,阻止跳转,可以href="javascript:;"或href=javascript:void 0; stopPropagation的作用是阻止事件的传播。阻止的是其他节点上的事件。 stopImmediatePropagation的作用也是阻止事件的传播。它不但能阻止其他节点上的事件,当前节点上的其他未触发的事件也会一并阻止。如下代码,只打印1: element.addEventListener('click', function(event) { event.stopImmdiatePropagation(); console.log(1); }, false); element.addEventListener('click', function() {console.log(2)}, false); 复制代码 currentTarget,当前会执行的回调函数绑定的那个节点。 elementFirst.addEventListener('click', function(event) { console.log(event.currentTarget); // elementFirst }, false); elementSecond.addEventListener('click', function(event) { console.log(event.currentTarget); // elementSecond }, false); 复制代码 target,就是事件流中的目标阶段的那个节点,也就是目标节点。需要注意的是,事件是否发生与是否绑定的操作没有关系,即便没有在一个节点上绑定事件的操作,事件依然会发生。target可以在事件委托中使用。 自定义事件 var myEvent = new Event('theEvent'); theTarget.addEventlistener('theEvent', function() {doSomething()}) theTarget.dispatchEvent(myEvent); // theTarget是一个节点,或者说是一个可以调用addEventListener方法的对象。 复制代码 此外customEvent做到跟Event同样的效果,他们的区别在于,customEvent可以加一些自己需要的数据进去,不过兼容性没有Event好。 用Event创建了实例之后,也可以用myEvent.data = {}的方式给数据,效果是一样的。 这有什么用?可以用来做全局范围内的广播,使模块间解耦。在vue中有一个用于组件间通讯的EventBus,自定义事件就可以用来实现这一功能。 事件委托和代理 事件委托就是把本来应该由你来做的事情,让别人帮忙做一下。 在实际编程中,可能会出现这样的场景,一个节点下有多个子节点,每个子节点都要有相应的事件绑定,这个时候我们就可以利用事件的冒泡,把事件绑定在父节点上,然后用event.target来区分到底是哪个子节点触发的事件。当这些子节点需要动态增减的时候,使用事件委托就显得尤为方便了,无论是写代码的效率还是程序运行的效率都会更高。 局限性:focus、blur这样的事件没有在冒泡机制,无法委托。另外一些消耗较高的事件如mousemove和mouseout也不适合委托。如下图 如果我们把B区域的mousemove事件委托到A区域,当事件在A区域发生的时候,对应的操作也会执行,如果是消耗较低的事件,就不会有太大的影响,可如果是消耗较高的事件,就会显得有点浪费了。 观察者模式与发布订阅模式 这两种设计模式与事件非常的类似。与事件的区别在于,事件是异步的,而我们自己实现的这两种模式,虽然使用了回调函数,但大都是同步的。而这两种设计模式之间的区别在于,发布订阅模式的事件池是统一的,观察者模式的事件池分散在各个发布者上面。 原文发布时间为:2018年06月23日 原文作者:砖用冰西瓜 本文来源掘金如需转载请联系原作者
Java 8 发布三年多之后,即将快到2017年7月下一个版本发布的日期了。 你可能已经听说过 Java 9 的模块系统,但是这个新版本还有许多其它的更新。 这里有九个令人兴奋的新功能将与 Java 9 一起发布。 Java 平台级模块系统 Java 9 的定义功能是一套全新的模块系统。当代码库越来越大,创建复杂,盘根错节的“意大利面条式代码”的几率呈指数级的增长。这时候就得面对两个基础的问题: 很难真正地对代码进行封装, 而系统并没有对不同部分(也就是 JAR 文件)之间的依赖关系有个明确的概念。每一个公共类都可以被类路径之下任何其它的公共类所访问到, 这样就会导致无意中使用了并不想被公开访问的 API。此外,类路径本身也存在问题: 你怎么知晓所有需要的 JAR 都已经有了, 或者是不是会有重复的项呢? 模块系统把这俩个问题都给解决了。 模块化的 JAR 文件都包含一个额外的模块描述器。在这个模块描述器中, 对其它模块的依赖是通过 “ requires” 来表示的。另外, “ exports” 语句控制着哪些包是可以被其它模块访问到的。所有不被导出的包默认都封装在模块的里面。如下是一个模块描述器的示例,存在于 “module-info.java” 文件中: module blog {我们可以如下展示模块: 32130002475b31336ae7 请注意,两个模块都包含封装的包,因为它们没有被导出(使用橙色盾牌可视化)。 没有人会偶然地使用来自这些包中的类。Java 平台本身也使用自己的模块系统进行了模块化。通过封装 JDK 的内部类,平台更安全,持续改进也更容易。 当启动一个模块化应用时, JVM 会验证是否所有的模块都能使用,这基于 requires 语句——比脆弱的类路径迈进了一大步。模块允许你更好地强制结构化封装你的应用并明确依赖。你可以在这个 课程 中学习更多关于 Java 9 中模块工作的信息 。 如果你想学习Java可以来这个群,首先是二二零,中间是一四二,最后是九零六,里面可以学习和交流,也有资料可以下载。 Linking 当你使用具有显式依赖关系的模块和模块化的 JDK 时,新的可能性出现了。你的应用程序模块现在将声明其对其他应用程序模块的依赖以及对其所使用的 JDK 模块的依赖。为什么不使用这些信息创建一个最小的运行时环境,其中只包含运行应用程序所需的那些模块呢? 这可以通过 Java 9 中的新的 jlink 工具实现。你可以创建针对应用程序进行优化的最小运行时映像而不需要使用完全加载 JDK 安装版本。 JShell: 交互式 Java REPL 许多语言已经具有交互式编程环境,Java 现在加入了这个俱乐部。您可以从控制台启动 jshell ,并直接启动输入和执行 Java 代码。 jshell 的即时反馈使它成为探索 API 和尝试语言特性的好工具。 322d0003e3f6c42e3137 测试一个 Java 正则表达式是一个很好的说明 jshell 如何使您的生活更轻松的例子。 交互式 shell 还可以提供良好的教学环境以及提高生产力,您可以 在此 了解更多信息。在教人们如何编写 Java 的过程中,不再需要解释 “public static void main(String [] args)” 这句废话。 改进的 Javadoc 有时一些小事情可以带来很大的不同。你是否就像我一样在一直使用 Google 来查找正确的 Javadoc 页面呢? 这不再需要了。Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。此外,你会注意到,每个 Javadoc 页面都包含有关 JDK 模块类或接口来源的信息。 321000048ba2cfe25db6 集合工厂方法 通常,您希望在代码中创建一个集合(例如,List 或 Set ),并直接用一些元素填充它。 实例化集合,几个 “add” 调用,使得代码重复。 Java 9,添加了几种集合工厂方法: Set ints = Set.of(1, 2, 3);除了更短和更好阅读之外,这些方法也可以避免您选择特定的集合实现。 事实上,从工厂方法返回已放入数个元素的集合实现是高度优化的。这是可能的,因为它们是不可变的:在创建后,继续添加元素到这些集合会导致 “UnsupportedOperationException” 。 改进的 Stream API 长期以来,Stream API 都是 Java 标准库最好的改进之一。通过这套 API 可以在集合上建立用于转换的申明管道。在 Java 9 中它会变得更好。Stream 接口中添加了 4 个新的方法: dropWhile, takeWhile, ofNullable 。还有个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什么时候结束迭代: IntStream.iterate(1, i -> i < 100, i -> i + 1).forEach(System.out::println);第二个参数是一个 Lambda,它会在当前 IntStream 中的元素到达 100 的时候返回 true。因此这个简单的示例是向控制台打印 1 到 99。 除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。现在可以通过 Optional 的新方法 stram 将一个 Optional 对象转换为一个(可能是空的) Stream 对象: Stream s = Optional.of(1).stream();在组合复杂的 Stream 管道时,将 Optional 转换为 Stream 非常有用。 私有接口方法 Java 8 为我们带来了接口的默认方法。 接口现在也可以包含行为,而不仅仅是方法签名。 但是,如果在接口上有几个默认方法,代码几乎相同,会发生什么情况? 通常,您将重构这些方法,调用一个可复用的私有方法。 但默认方法不能是私有的。 将复用代码创建为一个默认方法不是一个解决方案,因为该辅助方法会成为公共API的一部分。 使用 Java 9,您可以向接口添加私有辅助方法来解决此问题: public interface MyInterface { void normalInterfaceMethod(); default void interfaceMethodWithDefault() { init(); } default void anotherDefaultMethod() { init(); } // This method is not part of the public API exposed by MyInterface如果您使用默认方法开发 API ,那么私有接口方法可能有助于构建其实现。 HTTP/2 Java 9 中有新的方式来处理 HTTP 调用。这个迟到的特性用于代替老旧的 HttpURLConnection API,并提供对 WebSocket 和 HTTP/2 的支持。注意:新的 HttpClient API 在 Java 9 中以所谓的孵化器模块 交付。也就是说,这套 API 不能保证 100% 完成。不过你可以在 Java 9 中开始使用这套 API: HttpClient client = HttpClient.newHttpClient();除了这个简单的请求/响应模型之外,HttpClient 还提供了新的 API 来处理 HTTP/2 的特性,比如流和服务端推送。
世界上有两个伟大的编辑器:一个是emacs,一个是vi。它们从诞生以来,一直在Unix/Linux世界得到最广泛的支持。尽管过了几十年,在Windows平台上和跨平台上有层出不穷的后起之秀不断挑战它们的地位,比如编辑器界的Sublime Text,Ultra Editor,Notepad++,pspad,Atom,Visual Studio Code,IDE界的Eclipse, IntellJ IDEA, NetBeans等等,但是它们的地位从未动摇过。写C#的最好IDE一定是Visual Studio,写Java还是IntellJ IDEA和Eclipse更方便。但是,对于其它语言和其它任务,比起层出不穷的后来者,一定是emacs和vim的支持是最广泛的。针对一个特定的任务,可能Sublime Text和Atom只有区区几种插件选择甚至是没有,但是在vim和emacs上可以找到好多页。 这两种编辑器的学习曲线确实是相对比较陡的,但是,一旦修炼成功,这样的付出是绝对值得的。造成学习困难的主要原因,其实是功能太多太强大。这个修炼需要花不少的精力和时间,想修成上仙甚至上神是不容易的,但是,只要坚持下去,最终一定可以做到。好了,废话不多说了,我们开始修炼之旅。 Vim技能修炼教程(1) - 使用vundle管理插件Vim技能修炼教程(2) - 语法高亮速成Vim技能修炼教程(3) - 语法高亮进阶Vim技能修炼教程(4) - 基本功Vim技能修炼教程(5) - 操作符实务Vim技能修炼教程(6) - 行编辑器Vim技能修炼教程(7) - 可视模式Vim技能修炼教程(8) - 多窗口Vim技能修炼教程(9) - 缓冲区和标签页Vim技能修炼教程(10) - 代码跳转Vim技能修炼教程(11) - 代码折叠Vim技能修炼教程(12) - Vim的脚本语言支持Vim技能修炼教程(13) - 变量Vim技能修炼教程(14) - 写个ex命令吧Vim技能修炼教程(15) - 时间和日期相关函数Vim技能修炼教程(16) - 浮点数计算函数Vim技能修炼教程(17) - 编译自己的Vim ps:文章内容版权归云栖社区专家“lusing”所有,未经内容作者同意,请勿转载。
◆ ◆ ◆ 费尔德曼的百吉饼,和一场经济学实验 费尔德曼曾是个有着鸿鹄之志的人,20多年里一直在华盛顿从事分析工作。他职位很高,收入颇丰,但他受到认可却不一定是因为其兢兢业业的工作。在办公室的圣诞派对上,同事在向妻子介绍他时,对他的称呼不是“公共研究组组长”(这确实是他当时的职位),而是“带百吉饼来的人”。 送百吉饼最初只是偶一为之的奖励措施:员工拉到研究合同就会得到老板的犒赏。接着,这成了他的习惯,每周五他都会带百吉饼、一把锯齿刀和奶油乳酪到单位。上下楼的同事听说了百吉饼的事后,也纷纷表示想要。到最后,他每周要带上15打百吉饼,为收回成本,他摆了一个投币篮,贴了一张价签。结果,其成本回收率约为95%,他认为,没给钱的人是因为一时疏忽,而非有意占他便宜。 1984年,他就职的研究机构经历了管理层更迭,费尔德曼对未来做了一番斟酌之后,觉得前景堪忧,他决定辞职卖百吉饼。他的经济学家朋友觉得他丧失了理智,但他的妻子却支持他。毕竟,他们最年幼的三个孩子即将大学毕业,而且房贷也供完了。 他开车挨个绕遍环绕华盛顿的办公园区,用极其简单的推销手段拉拢客户:每天一早,他会将百吉饼和一个投币篮放在各家公司的餐室,然后中午再回来收走钱和剩余的百吉饼。这是一种全凭自觉的生意方式,而且确实行得通,仅仅几年间,费尔德曼的周送货量就达到了8400块百吉饼,业务遍及140家公司,收入恢复到了他做研究分析员时的水平。他摆脱了方寸隔间的拘束生活,可以活得逍遥自在了。 他同时还—在无意之中—设计了一场巧妙的经济学实验,费尔德曼从一开始就在一丝不苟地记录百吉饼生意的数据。因此,通过对比回收所得与百吉饼缺失数量,他发现他可以衡量客户的诚信度,且精确到分。他们是否占了他的便宜?如果存在此种行为,好占便宜的公司相比不占便宜的公司有何特点?什么情况会助长人们小偷小摸的行为?什么又会减少此类行为? 因为缺乏有效数据。白领犯罪的关键一点是,白领犯罪者何其多,我们所听说的骗局被拆穿的案例只是沧海一粟。多数侵占公款之徒不为人知,理论上仍然过着逍遥自在的生活,因为盗用公司财产的员工很少被发现。 与之相反,街头犯罪却非如此,因为无论罪犯是否归案,行凶抢劫、入室盗窃、谋杀通常都会被记录在案,且街头犯罪有着明确的受害者,而受害者通常会向警方报案,数据随即生成,进而又会有犯罪学家、社会学家和经济学家据此发表不计其数的学术论文。但白领犯罪并无明显的受害者,既然不知道犯罪对象、案发率或损失程度,罪行又如何定量呢? 然而,保罗·费尔德曼的百吉饼生意则不同,因为整件事确有一名受害者,就是他自己保罗·费尔德曼。 大量的心理学及经济学研究表明,对同一种商品,若出售者不同,人们愿意支付的价格也有所差异。经济学家理查德·塞勒在其1985年的研究《沙滩上的啤酒》中证明,同样一瓶啤酒,若是在度假酒店内出售,口渴的日光浴游客愿意支付2.65美元,而若是在一家破破烂烂的杂货店出售,他们只愿意支付1.50美元。 面对现实情况,费尔德曼逐渐总结出,付款率只要超过90%就算是“诚实守信”的公司了:80%~90%的付款率“可气但还过得去”;如果一家公司的付款率长期低于80%,费尔德曼则会张贴一张警告标语,如: 今年以来,百吉饼成本大幅上涨。遗憾的是,也有越来越多的百吉饼无故消失却无人付款。切勿继续此种行为,我猜想,你不会教自己的孩子行偷窃之事,那为何自己却明知故犯呢? ◆ ◆ ◆ 百吉饼的数据究竟说明了什么? 1.公众的同情心影响诚信度 近几年,总体付款率经历了两次值得注意的变化。其一是1992年起出现的长期而缓慢的下降。至2001年夏,总体付款率已经下滑到了87%左右。但当年的“9·11”事件发生之后,付款率立即上涨了整整2%,且此后再未出现明显回落。(假如付款率上涨2%听起来不算多,那换个角度想:未付率从13%下降到了11%,即盗窃数量下滑了15%。)由于费尔德曼的不少客户均在国安部门工作,这种“9·11”效应或许有些许爱国主义色彩,这也有可能表明公众的同情心有了普遍的提高。 2.小办公室比大办公室更守信用 数据还显示,只有几十名员工的办公室付款率要比几百人的办公室高出3%~5%,这似乎有违常识。在大办公室,百吉饼桌旁理应常有许多人在场,众目睽睽之下,你不得不投币进钱箱。但大小办公室的对比说明,百吉饼盗窃与街头犯罪类似。农村地区的人均街头犯罪率远低于城市,主要原因是农村地区的罪犯被发现(进而被抓获)的概率更高。此外,在规模较小的社群,预防犯罪的社会因素更加强大,其中一大因素就是羞耻心。 3.个人情绪对守信程度的影响 例如,天气就是一大影响因素:反常的好天气能提高人们的付款率;而与之相对,遇到反常的寒冷天气,则会出现大量未付款的现象。暴雨或强风天气也有同样的影响,影响最恶劣的是节假日:在圣诞周,付款率会下降2%,即盗窃数量上升15%,这与“9·11”造成的影响程度相同,但效果相反;感恩节半斤八两;情人节当周也非常糟糕;4月15日所在周也不外乎如是。但也有好的节日:7月4日、劳动节和哥伦布纪念日所在周。两种节日差别何在?欺诈率较低的节日仅仅是放假一天而已,别无他意,而欺诈率较高的节日则充满了各种各样的烦心事和来自亲人的种种期许。 4.关于守信,费尔德曼有他自己的看法,这些看法多是从生活经验总结而来 他逐渐相信,工作士气是一大因素—如员工爱戴自己的老板、热爱本职工作,这样的办公室更加守信。他同时还相信,在公司内地位较高的员工欺诈率要高于底层员工。他多年来一直在为一家办公室占用了三层楼的公司送百吉饼,从中得出了这一观点—该公司顶层为主管办公室,较低的两层为销售、服务和行政员工的办公室。费尔德曼猜测,这些主管有欺诈行为是因为特权思想膨胀。他所没有考虑的因素是,欺诈或许原本就是他们坐上主管之位的手段。 ◆ ◆ ◆ 如明知自己的所作所为无人目睹 会有人能抵制住诱惑,不去作恶吗? 如果说道德代表着在人类心目中,这个世界应该如何运转,而经济学代表着其实际的运转方式,那么费尔德曼的百吉饼生意则恰好处于二者相交的范畴。没错,很多人占他的便宜,但绝大多数人,即便是无人在场的情况下,也没有越界。这一结果或许出乎某些人的意料,包括费尔德曼的经济学家朋友,他们在20年前劝阻他,说他这种全凭自觉的生意方式完全行不通,但这却没有出乎亚当·斯密的意料。实际上,亚当·斯密第一部著作《道德情操论》的主旨就是人类生性诚实。 “无论人类被描写得有多么自私,”亚当·斯密写道,“其本性之中显然有某些原则,令其关注他人的命运,让他人的幸福成为对其来说不可缺少的东西,尽管除了眼见此种情景所获得的满足之外,他从中一无所得。” 费尔德曼有时会向自己的经济学家朋友讲述《裘格斯戒指》的故事,故事出自柏拉图的《理想国》: 在苏格拉底的一堂课上,一位名叫格劳孔的学生讲述了这个故事。苏格拉底同亚当·斯密一样,认为即使没有外力强制,人类一般而言也是生性善良的。格劳孔则同费尔德曼的经济学家朋友一样,不以为然,他讲述道,一位名叫裘格斯的牧羊人偶然间在一处隐蔽的山洞里发现了一具尸体,尸体上带着一枚戒指,裘格斯将戒指戴在自己手上后,发现戒指令他隐身了。在无人监控其所作所为的情况下,裘格斯干尽了坏事—引诱王后、弑杀国王,等等。 格劳孔的故事提出了一个道德问题:如明知自己的所作所为无人目睹,会有人能抵制住诱惑,不去作恶吗?格劳孔似乎认为答案是否定的,但保罗·费尔德曼则和苏格拉底及亚当·斯密同属一个阵营,因为他知道,在至少87%的情况下,答案是肯定的。 原文发布时间为:2016-09-03 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
如何优雅地测量一只猫的体积,而不使其感到惊恐或受到伤害? ◆ ◆ ◆ 前情提要 Monte Carlo 测猫法: 把猫装进已知体积为V_box的盒子,在盒子内均匀取N个随机点,其中M个在猫体内,猫体积近似为V_box*M/N。 推理及讨论见supplemental materials. 要实现这一测猫法,需要一种瞬时确定某点是猫还是非猫的方法,否则在猫运动的情况下,会测得猫扫过的体积而不是猫体积。 我决定用下图所示的方法。。。 盒子壁上装尽量多的激光灯,盒子壁用感光材料。若要确定某点是猫还是非猫,则让所有激光灯射向目标点。若目标点是猫,则激光会被猫挡住因此盒子壁上任何一点都不会检测到激光。因此我们用以下原则判断目标点是猫非猫: 若有盒子壁上任何一点检测到激光,说明目标点非猫。 否则认为该点是猫。 测量可以在很短的时间内完成,足以快到忽略猫的运动。 ============================ 当然这种方法是有缺陷的,猫身上一些凹陷部位可能会成为激光无法穿过的死角,因此被算入猫体积。 一个充分不必要的解决方法是让猫变成凸猫(convex cat), 即任取两点属于猫,两点之间的线段上的点都属于猫,满足这一条件的猫叫做凸猫,如下图所示。 下图是一个现实生活中凸猫的例子。。(图片来自网络) 对于凸猫,该方法测得的猫体积即为真猫体积,证明见supplemental materials中的夹逼测猫法。 但是这种方法是不猫道的,因为猫咪宣言中有这样的话: We hold these truths to be self-evident, that all cats are created equal (大雾), and they are endowed by their Creator with certain unalienable rights, that among these are the rights to stand up, lie down, turn around, groom themselves and stretch their limbs ... Five freedoms[ARCHIVED CONTENT] Farm Animal Welfare Council 而凸猫显然(至少)剥夺了猫咪 stretch their limbs 的自由。。。 好在对于非凸猫,该方法也不是那么糟糕。 下面我将展示给大家,即使对于非凸猫,用该方法测出来的猫体积 首先本身就是一种很合理的猫体积定义 其次实际操作中与一般意义上的猫体积差别不大 ============================ 要测量猫体积,首先要定义猫体积。 然而“猫有毛兮毛有枝,本喵在哪你不知。” 猫的体积定义并非显而易见的,主要有两个困难: 猫的表面是凹凸不平的,那些凹陷和缝隙怎么算?客观标准是什么呢? 喵是测不准的。理论上来讲喵的电子云可以想你时你在天边,想你时你在眼前,哪里算边界? 嗯。。化学家出场了。。。 化学家测猫大法: 把一个直径一定的毛线球用一定力量按在喵体表滚一遍,把毛线球与喵接触的内表面轨迹包括的空间的体积视为猫的体积,并称之为Van de Waals cat volume .(好吧。。。我知道这不叫Van de Waals体积。。但是这个体积的实际名字土掉渣了。。哪有Van de Waals高大上。。。) 如下图。 这一体积定义包含两个要素。毛线球的直径和按在猫身上的力量,前者决定了凹陷和缝隙算与不算的体积和形状标准——毛线球放得进就算,否则不算;后者决定了猫边界的标准——和毛线球之间的作用力达到某一值为准,啥啥电子云都不好使,就看力的大小。通过改变毛线球和力量的大小,可以控制猫体积的精细程度。究竟多精细不重要,重要的是可以定义一个体积的客观标准。 ============================= 仿照这一定义,我将我测得的猫体积定义为 Van de Bars cat volume。。。如下图。。。 准确来说,是一个直径相当于激光束粗度,无限长的bar在猫表面滚过定义的猫体积。。。你看。。。我测的体积也是有一个很有道理的定义的嘛。。。。 同时我想强调,相对于其他回答,该方法对猫毛可以有很严格的处理,详见supplemental materials中对猫毛的讨论。 =============================== 我认为实际测量中Van de Bars 猫体积和我们一般认为的猫体积差异并不大。 比如看下图 E为克莱因猫,虚线部分在猫体内。。 对于碗状猫(bowl cat),Van de Bars 猫体积确实会把猫肚子下面那块空间误算做猫体积的一部分。但是对弓状猫(bow cat)、椅状猫(chair cat)的测量都是准确的,因为光线可以从图上箭头的角度穿过。甚至小昭猫(shaw zhao cat)这个我本来觉得挺奇葩的形状下其实并没有任何问题。这样一来,Van de Bars 猫体积在多数情况下和我们一般认为的猫体积的区别也就仅限于耳廓内的空间、个别身体缝隙之类的光穿不过的死角。。。我觉得还是能接受的。。。 为了尽量避免碗状猫对测量的影响,我们要大力鼓励猫咪充分 stretch their limbs. 这也提示我们,爱护猫咪对我们蓝星人也是有益的。。。所以爱护猫咪,人人有责,no cats should be convex!!!============================= 综上,我设计了一种测量Van de Bars 猫体积的Monte Carlo测猫法。我觉得这是目前回答里最猫道最优雅的。。。因为它保障了猫咪伸展身体、弄干身体、不受恐吓、自由站起、躺下、翻身的权利。。。而且对猫体积有严谨而实用的定义。。。 =============================Supplemental materials: Monte carlo 测猫法的推理: 把猫装进体积为V的盒子,在盒子内 uniform randomly 取N个 independent and identically distributed (i.i.d.) 的点组成样本,记为 SAMPLE = {(xi, yi, zi) | i in range(0, N)}。 定义如下 function: I(x, y, z) = 1 if (x, y, z) in CAT else 0 (即确定一个点是猫还是非猫) 假设猫体积(V_cat)不变,且猫的运动与取点不相关(即猫既不接飞镖也不躲飞镖,见评论区知友讨论),则I(x, y, z)具有如下分布: I(x, y, z) = 0 with a probability of 1-V_cat/V_box I(x, y, z) = 1 with a probability of V_cat/V_box 与猫运动与否不相关。 根据这一分布I(x, y, z)的期望值是V_cat/V_box. {I(xi, yi, zi) | (xi, yi, zi) in SAMPLE} 是一个服从上述分布的 i.i.d. 的sample。 根据大数定理(law of large numbers), sample mean almost surely converges to expected value. 所以可以用 sample mean 估计期望值,即: V_cat/V_box ~= sum(I(xi, yi, zi))/N 记M为在猫体内的样本点数量,则 V_cat/V_box ~= sum(I(xi, yi, zi))/N = M/N 所以V_cat ~= V_box * M/N 关于猫毛的讨论 上述方法等价于把猫边界定义为猫体表透光率显著不同于空气以至于足以使得sensor检测到差异的位置。可以想象这应该包括了猫毛,而且是不受压迫不变形的猫毛。 我认为这也是该方法的一大优势——这是真正的无损测真猫,而不是测 a rat-like creature that lives inside a cat (见 @苍原雪在本问题下的回答)。。。其他方法,包括彩虹糖,都是有压迫的。实际上彩虹糖法测的是彩虹糖的形状和大小、彩虹糖与猫接触处的压强定义的Van de Waals cat volume. 因为这一压强,长毛猫的测量可能和我们预想的含猫毛体积有较大区别。 Van de Bars 猫体积和其他猫体积的对比 (不适用于克莱因猫) VS 真 猫体积 这里真猫体积指刨除一切空隙的猫体积。显然,Van de Bars 猫体积 >= 真猫体积。所以Van de Bars 猫体积是真猫体积的一个upper bound. 可惜的是它们之间的差是没有任何保证的,比如口袋猫。 VS Van de 毛线球 猫体积 我觉得Van de Bars 猫体积应该是与bar同样直径的毛线球定义出的Van de 毛线球猫体积的upper bound,但是我没仔细证。。。因为比如bowl cat这样的存在,它们的差同样是没upper limit的。。。 VS Convex Hull (附夹逼测猫法) 一个set的convex hull 是包含这个set且convex的最小的set。如图3和下图。 易知Convex hull 猫体积 >= Van de Bars 猫体积 >= Van de 毛线球猫体积 >= 真猫体积。对于convex猫,因为猫本身就是convex的,所以猫和猫的convex hull是同一集合,所以Convex hull猫体积 = 真猫体积,所以convex cat 的真体积 = Van de 毛线球体积 = Van de Bars体积 = Convex hull 体积。。。。。。夹逼测猫法。。。。convex 猫真好测。。。各种体积都一样。。。all cats should be convex。。。 关于克莱因猫 准确讲克莱因猫应该是克莱因猫皮(Klein Cat Skin),因为这是一个曲面而不是实体,而且这个曲面不能把空间分为内、外互不连通的两部分,所以也无法把克莱因猫体积定义为克莱因猫皮围成的空间的体积。仔细看Fig. 6 E 的话,克莱因猫“体内”的空间可以通过尾巴-食道-口和外界相通。所以严格讲,克莱因猫无体积。 但是这并不妨碍我们继续强测克莱因猫的 Van de 毛线球体积和 Van de Bars 体积,只是不同于之前可以把这作为真猫体积的近似,现在我们必须将其作为一种独立的体积定义使用。 在克莱因猫上 Van de Bars 猫体积比 Van de 毛线球猫体积鲁棒。因为当毛线球小到克莱因猫可以吞下去的时候,毛线球会沿着口-食道-尾巴通路把喵“体内”滚个遍,然后 Van de 毛线球体积为零。。。而 Van de Bars 体积因为使用的是无限长的bar, 所以即使bar直径再小也无法access喵“体内”的空间。这允许我们用较细的bar来提高测量准确度而不必担心体积忽然降为0. =========下面是原答案=============== 物理学家测猫法:取一只半径为r的真空中的球形猫,体积等于4/3*πr^3数学家测猫法:把猫装进已知体积为V的盒子,在盒子内均匀取N个随机点,其中M个在猫体内,猫体积近似为VM/N。生物学家测猫法:把control猫装盒子,塞了10次都塞进去了,把实验猫装同一个盒子,塞了10次只进去两次,所以,猫多大我不知道,反正显著大于control猫。 原文发布时间为:2016-09-04 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 导读 有关数据和数据分析的高谈阔论比比皆是。不断有人告诫各大公司要规划恰当战略来收集分析大数据,并警告不这么做可能带来的不良后果。像《华尔街日报》近日就提到公司享有客户数据这样一个大宝藏,却大都不知道该如何利用。本文将探讨其中缘由。有公司尝试从巨大的数据中获取实际可用的信息,通过与他们合作,我们归纳了管理者在数据应用上的四个常规错误。 ◆ ◆ ◆ 错误一:没有理解融合的概念 阻碍大数据发挥价值的第一大挑战就是兼容性和融合性。大数据的一个主要特点是其来源多样。然而,如果数据形式不相同,或难以整合,则其来源的多样性将使公司难以削减开支,也无法为客户创造价值。例如,在我们和一个合作项目中,该公司拥有丰富的数据,记录客户的交易量和忠诚度,以及专门的在线浏览行为数据,但是鲜少交叉检索这两类数据来判断某种浏览行为即为交易达成的前兆。面对这种挑战,公司创建了“数据湖”来容纳大量非结构性数据。但是,这些公司能够加以利用的数据目前都显得杂乱无章,只不过是一些以文本,也就是说,当这些数据只是普通的二进制数字时,要将它们井然有序地存储起来非常困难。要将来源不同的它们整合起来更是难上加难。 ◆ ◆ ◆ 错误二:没有认识到非结构化数据的局限性 阻碍大数据发挥价值的第二大挑战是其非结构化的特性。对文本数据的挖掘已经有了特别的进展,其语境和技术所带来的认识与结构化数据类似,只是其它形式的数据如视频仍不易于分析。举个例子,虽然拥有最先进的人脸识别软件,有关当局仍然无法从大量视频中识别出波士顿马拉松爆炸案中的两名嫌疑人,因为该软件尚在处理从不同角度拍摄的嫌疑人的照片。 虽然从非结构性数据获取信息面临挑战,但是各公司在利用这些数据初步提升分析已有数据的速度和精确度上取得了显著成绩。比如,在石油和天然气勘探中,人们就用大数据来优化正在进行的操作,以及针对地震钻井的数据分析。尽管他们所使用的数据在速度、种类和体积上都有可能增加,最终这些数据还是用于同一个目的。总之,一开始就希望通过利用非结构性数据形成新的研究假设是站不住脚的,除非各公司通过“实践”有了这种专业能力,能利用非结构性数据优化某个问题答案。 ◆ ◆ ◆ 错误三:以为关联分析意义重大 第三大挑战——我们认为是阻碍大数据价值的最重要的影响因素——是观测数据的大量重叠使其因果关系难以明确。大规模数据集往往包含众多相似或完全一致的信息,直接导致错误的关联分析,误导管理者的决策。近日《经济学人》指出“在大数据时代,相互关系往往是自己浮现出来的”,《斯隆管理评论》在博客中强调虽然很多公司都能接触到大数据,但是这些数据并不“客观”,因为问题在于要从中提炼出值得采取行动的信息。同样,典型的用于分析数据的机器学习算法所进行的关联分析并不一定会提供原因分析,因而不会给出可执行的管理意见。也就是说,让大数据有利可图的技巧在于能够从仅仅观测到相互关系转变为正确鉴别何种关联为因果形式,可以作为战略举措的基础。要做到这一点就必须超越大数据。 谷歌趋势是大数据的经典范例,它利用谷歌搜索词条整合记录。然而,它也说明了仅仅用于关联分析的数据是毫无意义的。起初,研究人员称数据可以用于反映流感的传播。然而后来,研究人员发现因为数据体现的是过去,使用这些数据只能在现状与过去模式相关的情况下,稍微改善应对行为。 举个更具体的例子,假设一个鞋业销售商向曾浏览其网站的消费者投放广告。原始数据分析认为消费者看到这些广告会更愿意购买鞋子。可是,这些消费者在看到广告之前就已经对该销售商表现出了兴趣,因而比普通人更愿意进行交易。这个广告有效吗?很难说。实际上,这里的大数据并没有考虑营销传播有效性的因果推论。要知道该广告是否有效,销售商需要进行随机检测或试验,选取一部分消费者不接触这个广告。通过比较看了广告和没看广告的消费者之间的购买率,公司才能确定是否看到广告能让消费者更愿意消费。这个案例中,价值主要不是通过数据创造的,而是通过设计、执行以及阐释重要的试验来创造的。 这是个试验,不是分析观测到的大数据集来帮助公司了解一段联系到底是仅仅相关还是因为反应潜在的因果关系而变得可以赖以作出判断。虽然对于管理者来说,哪怕仅利用记录消费者行为一拍字节的数据来提升效益都很困难,但是比较参与了营销活动的客户和没有参与的客户——根据试验结果——能够让营销人员推论这个活动是否有利可图。 开展实地试验,得出正确的结论,采取恰当的应对措施,都不是轻而易举的事。但是成功的公司已经有能力来设计、开展重要的实地试验,并对其结果评估,采取针对性措施。正是这种“试验加学习”的环境,以及对其能否加以推广的理解和认识之上采取行动的能力,才让大数据有价值。 只是,由于越来越多的数据样本收益递减,这样的试验并不一定需要大数据。比如:谷歌透露说其往往用有效数据的0.1%中的随机样本来进行数据分析。确实,近日刊登的一篇文章显示大数据的大实际上是不利的,因为“数据库越大,就越容易支持你提出的假设。”换句话说,因为大数据提供重叠的信息,公司能从整个数据集,也能从其千分之一的数据集中获取同样的信息。 ◆ ◆ ◆ 错误四:低估了劳动力技术需求 开展试验不是公司从大数据推测有价值信息的唯一途径。另一个可行的方法是公司可以培养算法技能,来更好的处理数据。推荐系统便是此类算法的一个范例。推荐系统通过针对关联数据的算法向客户推荐最相关的产品。只是,它不是依靠背后规模庞大的数据,而是依赖识别关键信息碎片来预测客户偏好的能力。的确,往往不是数据的规模,而是计算机学习的算法来确定结果的质量。尽管预测能力可能增加可用数据的规模,但是在大多数情况中,预测的提升说明规模收益随着数据集增加而递减不过,要建立好的算法就需要好的数据分析师。一些公司以为不同聘请员工来分析数据中的因果联系就能将大量的数据转化为信息,他们可能要失望了。 数据本身是没有价值的。只有与管理、构建和分析技能结合来,明确对其进行试验和算法,才能对公司有用。当你把价格信息看做是对价格信息处理的技能时就清楚了。很多情况下,相对于数据成本,留住数据处理人才成本更高。这说明对于一个公司而言,数据处理能力比数据本身更重要。 原文发布时间为:2016-09-06 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 导读 现在说机器学习和深度学习的应用只受限于人们的想象力并不夸张。不仅全世界的数据科学家们为之着迷,甚至在日本的农场,一位小哥为了减轻妈妈的工作负担,也开始尝试采用深度学习和Tensor Flow种黄瓜。 大约一年前,曾为日本汽车业内一名嵌入式系统设计师的MakotoKoike开始在父母的黄瓜种植园帮工。根据大小形状颜色和其他属性来分选黄瓜这件事所需的工作量令他吃惊。 Makoto Koike那一生致力于提供鲜脆黄瓜的父亲就很为他那些仍带有细刺的扎手黄瓜感到自豪。颜色鲜艳又直又粗并且有许多刺的黄瓜被认为是高档的,可在市场上要价更高。 但是MakotoKoike很快就了解到分选黄瓜就如把它们种出来一样难。“每只黄瓜的颜色、形状、质量、新鲜度都不同”,Makato说。 零售店里和Makoto Koike家农场的黄瓜 在日本,每家农场都有自己的分类方法,并且没有行业标准。MakotoKoike家农场把黄瓜分为9个不同的等级,由他妈妈亲自分选所有黄瓜,——这在收获的峰季是最高每天8小时的工作量。 “分选工作不是一项简单易学的任务。你不只要看它的大小粗细,还要看颜色质地,有没有小的划痕,是不是奇形怪状,有没有刺。这些需要好几个月才能学会,所以在最忙的时节雇临时工行不通。我自己也是最近才学得能把这些黄瓜分选好”,Makoto说到。 歪歪扭扭的黄瓜被评为次品 市面上也有(黄瓜)自动分选机,但在性能和费用方面都有局限,所以小型农场不大会用它们。 Makoto认为分选黄瓜不是瓜农的一项重要任务。“瓜农希望把注意力和功夫花在培养可口蔬菜上。我想在接手父母的农场生意之前把分选工作自动化。” Makoto Koike(中间)和他的父母在自家黄瓜农场 ◆ ◆ ◆ 深度学习的众多用途 Makoto试用机器学习来分选黄瓜的创意最初来自一个完全不同的应用实例:谷歌阿尔法狗与世界顶尖职业围棋手对弈。 “当我看到谷歌的阿尔法狗,我意识到这里确实在发生一些很严肃的事情,”Makoto说,“这触发我开始开发带有深度学习技术的黄瓜分选机。” 深度学习用于图像识别,允许电脑从训练数据集中学习到什么是图像的重要“特征”。使用大量的人工神经元分层,深度学习可以高精度地自动分类图像。因此神经网络可以从图像中识别出不同种类的猫,或是不同型号的汽车和飞机。神经网络有时会在特定应用中超过人眼的表现。(如需更多信息,请看我过去的博客文章Understanding neuralnetworks with TensorFlow Playground.) ◆ ◆ ◆ TensorFlow将深度学习的权力民主化 但是计算机是否真能学会妈妈的黄瓜分选技艺?Makoto开始着手使用谷歌的开源机器学习库TensorFlow来看看自己能不能用深度学习技术来进行分选。 “谷歌刚刚开源了TensorFlow,所以我就开始把它试用于我的黄瓜图像上,”Makoto说。“这是我第一次尝试机器学习或是深度学习技术,马上就得到高过预期的准确度。那给了我信心:它能解决我的问题。” 有了TensorFlow,你不需要知道施用深度神经网络所需的高阶数学模型和优化算法。只要下载示例代码并阅读教程,你可以马上就可以开始用它。TensorFlow显著降低了机器学习的门槛,自从谷歌于去年11月开源了这个程序库,许多“非机器学习”的工程师已经开始通过他们自有的数据和应用来摆弄这项技术。 ◆ ◆ ◆ 黄瓜分选系统的设计 下图是Makoto设计的黄瓜分选机的系统图解。该系统以Raspberry Pi 3为主控制器用一架相机为每根黄瓜拍照。在最初阶段,系统在TensorFlow上运行小规模的神经网络来检测这是否是黄瓜的照片。系统接下来将这张照片转发至Linux服务器上的一个更大的TensorFlow神经网络执行更加精细的分类。 黄瓜分选机的系统图解 Makoto 采用了名为DeepMNIST for Experts的TensorFlow示例代码,经过一些对卷积层,池化层和最后一层的微调后,改变网络设计以适应黄瓜图像的像素格式和黄瓜分选的等级数。 下图是Makoto的黄瓜分选机,已于七月投入使用。 下图是分选臂以及相机接口的特写镜头。 ◆ ◆ ◆ 挑战深度学习的极限 深度学习目前面临的挑战之一是它需要大量的训练数据。为了训练模型,Makoto花了大约三个月时间,拍摄了7000张他母亲所分选的黄瓜的照片,但这恐怕还是不够。 “当我用测试图像进行验证时,识别准确度超过95%。但如果在实际操作中运用这个系统,准确度就会下降到70%左右。我怀疑神经网络模型由于训练图像的数量不够,存在“过度拟合”的问题(神经网络中的现象:模型被训练得只适于少量的训练数据)。” 深度学习的第二个挑战是它消耗大量的运算容量。现在这架分选机用一台普通的Windows台式电脑来训练神经网络模型。尽管它将黄瓜的照片转成80*80像素的低分辨率图像,但对基于7000张照片的模型,它仍需2-3天时间来完成训练。 “即使处理这样低像素的图像,这个系统也只能根据黄瓜的形状、长度和弯度来将其分类。它不能识别色泽、纹理、划痕和刺”,Makoto解释道。提高像素来放大黄瓜的图像可以提高准确度,但训练所需时间也将大大增加。 为了改进深度学习,一些大公司已经开始进行大规模分布式训练,但那些服务器往往需要巨额成本。谷歌推出了云机器学习(CloudML)这个用于训练和预测的低成本云平台,它可以投入数以百计的云服务器来使用TensorFlow训练神经网络。在Could ML平台上,谷歌会来搭建用于分布式训练的大规模集群,而你只需购买你要用到的,这让开发者们可以更容易地试用深度学习而无需大量资本投资。 这些专用服务器曾被用于阿尔法狗的比赛 Makoto对CloudML充满期待。“我可以在Cloud ML上使用更高分辨率的图像和更多的训练数据来训练模型。我还可以试着改变神经网络的各种设置、参数和算法来看看这些如何提高准确度。我已经迫不及待地想试用了。” 原文发布时间为:2016-09-06 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
前不久,坐拥Littlewoods和Very两家在线商店的在线零售商Shop Direct,和IBM研发的世界领先的AI计算机Watson开展了合作,启用了一种能实现自主思考的机器人,它可以通过Whatsapp回答顾客的问题,甚至还可以向消费者们推荐他们可能心仪的产品。 目前,这家公司在研发一种能让顾客与网页Very.co.uk实现对话的技术,这项技术可以让顾客像在WhatApp上与朋友聊天那样自如对话;同时,顾客可以收到各种定制化的信息,从而将他们的在线购物化繁为简。 网络世界中的购物机器人技术发展得如火如荼,那么在实体商店中,消费者们是不是也可以通过使用购物机器人,提升购物体验呢? ◆ ◆ ◆ ATR公司的超市购物辅助机器人RobovieⅡ 早在2009年,来自日本的ATR公司就开始研发超市购物辅助机器人RobovieⅡ了。RobovieⅡ可以在体弱多病的老年人购物的过程中一路随行,并提出一些建议。比如,当你在水果区附近晃悠时,它会自动推荐一些新上市的水果,同时还会推送一些果蔬沙拉的搭配方法。这不仅解放了老年人的双手,还促使他们更好地享受购物带来的乐趣。 2009年的12月底,ATR公司在日本某地对这款机器人进行了简短的测试,参与测试的老年人都表示很满意。当时,ATR公司对外界宣称,这款机器人将于次年三月效力于京都的某超市,但是小编发现自从2009年底后,这款机器人就消失在了公众视野中,所以它很可能并未如期投入使用。 ◆ ◆ ◆ 全自动购物车wi-GO 作为一款全自动购物车,wi-GO可以跟随消费者穿梭在超市中,来去自如。它的屏幕上安置了三个摄像头,其生成3D的景象可以且只可以识别一个人。wi-GO的轮子和底座上装有距离传感器,可以躲避障碍物。使用这种机器人不需要在消费者安装任何识别传感器在身上,所以很适合在公共场合使用。 该产品由某个学术项目团队研发,他们声称,除了超市以外,这个技术还能在医院中广泛运用,例如,将这个系统安装在病人的点滴架中,这样病人在行走的时候就不用自己扶着点滴架;另外,它还可以运送药物或者病号餐。当然,这类技术也可以运用在机场行李上——将系统安装在行李车上,操纵行李车,so easy! ◆ ◆ ◆ 日立的人性购物机器人EMIEW3 同样是一家日企,日立从 2005 年就开始致力于购物机器人的研发。今年,日立推出了一款名为 EMIEW3 的人形购物机器人。它的内部搭载了一个远程智能处理系统,因此它能够通过摄像头跟踪顾客的当前位置,并且在他们需要帮助的时候自动提供服务。顾客还可以与它进行沟通交流,以获取自己需要的信息。另外,EMIEW3还应用了强大的智能语音处理技术,这使得它能够根据水平及垂直方向的声音分析确认声音的来源,即使在嘈杂的环境中也能进行有效识别。 更值得一提的是,EMIEW3使用了最新的机器人交互技术,所以在为顾客答疑解惑的同时,它还能跟与他的机器人进行信息交流;在顾客决定购买时,将商品的价格和信息发送给收银台的机器人,方便结算。 日立表示,EMIEW3 预计将于 2018 年正式上市,并有望冲出日本,走向世界。 ◆ ◆ ◆ Fellow Robots和Lowe’s联合打造OSHbot客户服务机器人 OSHbot客户服务机器人是由零售行业机器人公司Fellow Robots和零售巨头公司Lowe’s联合研发的。这些机器人知道商品的位置,所以当消费者走进Lowe’s实体店后,OSHbot就可以通过与消费者对话进行导购。目前,OSHbot系统中设置了二十五种语言,所以Lowe’s旗下的OrchardSupply Hardware零售店内的机器人能用英语和西班牙语与消费者对话。 当消费者走进店内,对OSHbot说:“我想买钉子和油漆”后,机器人就会告诉他们,它听懂了,然后消费者可以通过OSHbot自带的触摸屏直接在屏幕上导航定位商品、查看商品图片,然后点击选择他们最想要的那款商品。选择了之后,OSHbot会告诉顾客商品库存量以及它在店内的具体位置(比如15号过道)。确认完成之后,顾客可以点击机器人身上的一个按键,然后OSHbot机器人就会带领消费者来到商品摆放点。 机器人帮助消费者完成的整个商品导购过程是全自动的,顾客只需跟着OSHbot即可(它的背面还有一个引导屏幕)。把顾客带到商品货架位置后,OSHbot会出具一些额外选项。比如当顾客购买油漆时,他们通常还需要一把刷子。所以,OSHbot会提供相关商品信息,再把顾客带到刷子所在的货架。当然,如果顾客不想跟着机器人,OSHbot会给他们在地图上显示商品货架的具体位置,让他们自己决定是否自己走过去。 去年11月,OSHbot机器人首次发布时,消费者们都觉得很惊艳,因为对他们而言,这样的购物体验既新鲜又有趣。 ◆ ◆ ◆ 沃尔玛与Five Elements的合作结晶:私人购物机器人Budgee 一提起逛超市,小编脑海中浮现的第一件事就是:找辆方向轮利索些的购物车!是的,即便是方向轮轻微损坏的购物车,都会极大地影响购物体验。作为全世界最大的零售商,沃尔玛果断抓住了消费者的痛点——他们打算用私人购物机器人来取代购物车的存在。 在今年六月的彭博技术大会上,机器人公司Five Elements的首席执行官Wendy Roberts宣布,他们正在和沃尔玛合作升级超市的购物车。尽管两家公司都没有透露太多具体合作细节,但是从Five Elements现有的产品来看,这次的合作意义重大。 Five Elements主要专注于一个叫Budgee的私人购物机器人的研发。它的储存空间巨大,同时可以四处跟随消费者,帮助他们携带物品。实际上,同样的技术也可以被应用到购物车上,这么一来,消费者不仅不用推购物车,购物车还会自动跟着消费者走,实在太美好了。 这款私人购物机器人Budgee还能充当导购员的角色,消费者们只需要把购物清单出示给Budgee,它就会对清单上的商品进行自动定位,省时又快捷。 清点了这么多款购物机器人,小编最心仪的就是小跟班Budgee了!能拎包包,能定位商品,还能一路相随,这样忠诚的智能购物伴侣简直是广大女性的福音。 原文发布时间为:2016-09-08 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
黑暗中,一只苍蝇的腿被悬吊在开放空间的高处。它被挂在一个空箱子的顶上,一个电磁铁吸住它背部粘着的别针。当电磁铁关闭时,苍蝇就开始自由落体。 然后呢,它会振翅飞行。毕竟飞行是苍蝇的老本行。生物学家Stéphane Viollet是这么想的。 通过观察食蚜蝇翻筋斗,他试图了解苍蝇如何旋转自己的身体和它们是否有内部的重力感官。对于在空气中对抗重力歪歪扭扭飞行的昆虫们来说,认清哪边是上时很重要的。问题在于,它们是怎么认清的呢? 现在,根据他们的最新实验,Viollet及其同事可能已经发现了食蚜蝇的答案:主要依赖视觉。 这与人类及大多数其他脊椎动物在内耳中有感受重力的内部加速度传感器不同。例如,人类耳朵中有三个充满液体的小腔室,一旦感受到加速度就会移动。腔室中的纤毛检测到晃动并向大脑发出信号,使你能维持方向。 但飞行昆虫的奥秘尚未被完全认识。“对许多昆虫来说这依然是个问题,因为昆虫没有内耳,”Viollet说道。 有研究表明蟑螂能用背部的微型器官当作钟摆来旋转自己。但Viollet说,昆虫能否在飞行中感受重力仍不清楚。如果苍蝇能追踪重力,它应该能检测到突然下坠并迅速起飞。 出人意料的是,在黑暗环境中,苍蝇无法旋转自己,持续下落了超过一英尺直到撞在箱子底部。(别担心,苍蝇身轻如燕,没那么容易受伤。) “真的是万万没想到,”Viollet说道。70%的实验时间里苍蝇都重复了上述的坠地。 开灯后,在白色箱子里,仅有30%的苍蝇坠地。在有条纹的箱子里,只有10%的苍蝇坠地。并且苍蝇相比于黑暗箱子里更快开始振翅。似乎视觉不仅对旋转必不可少,而且也决定了做出反应的时间。 Journal of Experimental Biology于8月发表了这一研究,Viollet认为该发现可能也适用于其他飞行昆虫。 原文发布时间为:2016-09-10 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
人工智能、基因技术、大数据、区块链,新一轮产业革命席卷而来! 美国人如何定义和重塑未来? 如何开启新型产业模式,布局全球产业市场? 这一场前所未有的科技革命如何改变我们的世界? 对话嘉宾简介: 亚力克•罗斯(Alec Ross),美国前国务卿希拉里的创新事务资深顾问、希拉里2016年总统竞选团队科技政策制定小组负责人、美国科技战略专家、美国创新产业领军人物。他曾在美国总统竞选历史上由奥巴马竞选团队首次掀起的网络政治战中起了关键作用。由于在希拉里任国务卿期间创新事务中的杰出表现,他曾获得美国国务院特殊荣誉奖、牛津大学网络与社会奖,荣列《外交政策杂志》评选的“一百位全球顶尖思想家”和《赫芬顿邮报》评选的“十大开创新局的政治人物”。亚力克•罗斯也是美国哥伦比亚大学国际和公共事务资深研究员、约翰•霍普金斯大学客座教授。 黄征宇,首位来自中国大陆的美国白宫学者、前国际开发署署长特别助理、金融科技服务及跨国投资专家、宇沃资本美国董事长。进入白宫前,他曾是英特尔最年轻的华裔董事总经理,领导团队研发出迅驰等划时代新产品,帮助英特尔在全球市场成为领导者,更积极推动了英特尔与中国政府在通讯领域的知识产权合作。黄征宇在斯坦福大学获得经济学学士学位、工业工程学士学位和计算机科学硕士学位,还在哈佛商学院获得工商管理硕士学位。 黄征宇和亚力克•罗斯曾在白宫有过共事的经历。当时,作为2009-2010届白宫学者之一的黄征宇在美国国务院担任国际开发署署长特别助理,亚力克•罗斯则是前国务卿希拉里的创新事务顾问。两人在工作有过不少交集,更重要的是他们在科技创新领域的观点和想法有很多共鸣。 日前,黄征宇和亚力克•罗斯做了一番深入的交流和探讨。特别值得一提的是,如果希拉里最后入主白宫,亚力克•罗斯很可能继续为美国首位女总统操盘决策美国科技创新大计。所以,他对美国科技创新的思考将具有决定性意义,他与黄征宇这一场关于科技未来最前沿的深刻对话到底有哪些精彩内容? ◆ ◆ ◆ 人工智能 黄征宇:我们从人工智能开始谈起吧。可以预见,机器人在未来社会将扮演一个非常重要的角色,其中最有可能实现的就是机器人将会大量地取代人力。众所周知,中国是世界上劳动力资源最丰富的国家之一,机器人技术的高速发展和逐渐普及将会对未来中国产生哪些影响呢? 亚力克•罗斯:人工智能为人类生活带来的影响是好是坏,评价非常多元化,可谓是褒贬不一。同样,人工智能对未来的中国也将是一把双刃剑。不可否认,科技对中国经济的高速发展做出了贡献,使得中国已经位列世界五大科技强国(美国、德国、日本、韩国和中国)。 中国目前正在快速地推进城镇化,在这一过程中,机器人技术发展所带来的下一波革新浪潮的势头将非常迅猛,毋庸置疑将在越来越多领域逐渐取代人力。最明显的例子将发生在农业和工业,尤其那些大型工厂、重型工厂,机器人将帮助人类承担那些沉重的、繁琐的、极其体力化的工作。 黄征宇:所以,人工智能的发展将会对未来的社会结构造成很大的冲击。在这样的情况下,中国的产业会发生什么变化?另外,我很好奇,人类生活究竟会被机器人改变多少,以及机器人最终真的会超越人类吗? 亚力克•罗斯:冲击是毫无疑问的。在不久的将来,中国将会成为机器人领域发展最为先进的国家。相比美国、德国和日本研发的尖端智能机器人技术,中国正在研发应用于大规模制造的机器人,中国将会成为一个机器人硬件和系统的输出大国,让其它国家也使用上中国生产的机器人。 这里,我们需要探究的问题不是奇点是否会出现,而是人类是否能削弱机器在学习过程中产生的负面影响。在这方面,我不得不提到一批像艾隆·马斯克(Elon Musk)这样身家上亿的硅谷创业者,他们为了人类的美好未来,已经在人工智能的非盈利机构Open AI 上投入了超过10亿美元。 黄征宇:我知道艾隆·马斯克他们很担心,未来的人工智能发展到某一天,可能会对人类不利,这也是他们做Open AI的原因之一。简单打个比喻,他们在研究能不能植入一个off switch(关闭开关),一旦人工智能出现他们担心的负面问题,可以随时随地把机器人关掉。 亚力克•罗斯:你说的没错,这是非常值得关注的点。 ◆ ◆ ◆ 基因技术 黄征宇:在生命科学领域有一场革命正在酝酿,那就是对人类基因进行改良,使人类变得更聪明、更强壮和更长寿。所以,很多人都说生命科学的巨大进步将延长人们的寿命,并且带来前所未有的健康生活方式——至少对那些能负担得起费用的人来说是这样的。我迫不及待地希望知道最前沿的生命科学将如何影响我们未来工作和生活的方式? 亚力克•罗斯:目前,世界顶级的富豪阶层已经开始接触到这个领域。我们预计,这项技术将会在2020年应用于大众市场。当然,实现这一目标的前提是需要经济和科技的双重支持。 目前,人类基因组的研发成本被降低到了1100美元,而在五年前,它的成本则是100000美元。在未来四年内,它的成本还会大幅度下降,或许只需要几百美元。 当今社会,人类的平均寿命正以不可思议的速度增长,但单纯的更长寿并不意味着人类的生命会变得更有创造力。我的祖母活到99岁才去世,但老年人在后期能获得的生活质量和安全保障是不够的。假如人生最后的那几年是无所作为而又不快乐的,那长寿是否具有实质意义就很值得怀疑。 ◆ ◆ ◆ 加密数字货币 黄征宇:近年来,加密数字货币作为一种新的货币品种,不断被人提及。它的出现挑战了人们对传统货币的认知,一系列让我们脱离实体货币的技术层出不穷。 从目前来看,加密数字货币暂时还不能成为一种全球性的货币,因为他具有无法被追踪的匿名特征,政府层面无法进行掌控,你觉得未来加密数字货币的发展趋势会是怎样? 亚力克•罗斯:是的,加密数字货币没有成为全球货币有你说的这个原因,就是它的隐匿性暂时还不符合国家层面的货币调控要求。政府仍将牢牢地掌控着货币,对其施加影响力。我觉得会有一种加密货币在未来出现,但它必须要具备真实世界的属性,而且这种货币不会威胁到国家层面的调控。 当然,支付与货币截然不同,支付将会甚至已经变得前所未有的高效。很多技术应用已经出现在大众面前,给最普通的老百姓提供了收取、持有、消费和转账的便利。 加密数字货币中的核心技术之一——区块链技术最初并不受关注,但现在越来越多的人开始讨论这项技术和未来前景,它可能会迫使人们重新改写政府、企业和人之间的关系。既然这是一个跨越国界的全球货币技术,我认为中国与美国的金融机构要共同投资,共同研发,这对全球最大的两个经济体有着深远的意义。 ◆ ◆ ◆ 数据 黄征宇:在信息时代,数据已经渗透到全球各个行业,影响着政府的决策、企业的发展、人们的生活。不夸张地说,谁掌握数据,谁就掌握了信息时代。正因如此,全球各个国家对数据方面的规则制定尤为重视,但中美在这方面似乎存在着很大的差异。 我知道你曾经是希拉里任国务卿时期的创新事务顾问,你觉得美国政府会怎么看待这个事情? 亚力克•罗斯:针对这一问题,中美之间的确存在着很大的差异,中国的数据及隐私保护规范和美国有着非常大的差别。在这个信息时代,中美两国的科技公司现正处在一个竞争非常激烈的阶段。 我们面临的最大的问题之一就是市场准入。中国政府要向在中国经营的美国公司索要数据控制权和归属权,而美国也会针锋相对,捍卫自己认可的规则。目前,美国还没有就中国公司进入美国市场提出数据方面的限制政策。然而,下一任总统就很可能会采取更加强硬的手段,比如,基于机会公平的原则来决定市场准入。 无论是下一任总统是希拉里还是特朗普,我相信他们在这方面的态度都会比奥巴马总统强硬得多。比如,脸书(Facebook)在中国经营,中国政府要求把数据存储在中国。在美国,阿里巴巴可以在美国做生意,却把数据存放在中国。那么,美国公司会觉得公平吗?他们会作何感想? ◆ ◆ ◆ 网络战争 黄征宇:无论是化学武器还是核武器,世界各国都有公认的游戏规则。但像黑客方式的网络攻击,到目前为止还没有一个全球化的准则来进行约束。一般情况下,大家都不愿意承认这种攻击,只是我知道你在做,你也知道我在做。网络战争,未来如果没有行之有效的约束的话,恐怕会造成非常危险的结果? 亚力克•罗斯:用代码来武装自己,是自人类将核裂变材料用到武器上以来最至关重要的变化。 的确,现在的问题就是你所提到的——在这个领域里,很少有条约和协议能产生约束作用。网络攻击已经成为所有国家和大型企业最需要警惕的危险之一,人类已经为化学武器和核武器制定了不少条约进行约束,但代码这种武器是21世纪独有的,而且发展速度远快于规则制定速度,至今为止还没有一套被广泛承认的全球性规范,所以就会导致混乱。 美国和中国,在一定程度上是竞争对手;但这种竞争目前主要体现在经济上。而俄罗斯人却正在打一场虚拟世界的战争——网络战争。可以预见,美国与俄罗斯在这方面的对抗会不断升级,俄罗斯甚至正在干涉美国的总统选举,这对于美国来说是决不允许的,美国未来要给俄罗斯一个教训,以此来制约他们。 ◆ ◆ ◆ 非洲 黄征宇:中国在对外援助方面走的是有别于西方国家的一条路,这在中国援助非洲上体现得更为典型,它大多是采取政府加企业的模式,政府提供了充足的援助资金,企业获得介入的机会,使得中国在当地推进项目既快速又有效。这个模式很近似于PPP模式(Public-Private Partnership,即政府和社会资本合作)。 我在美国国际开发署工作的时候,很多同事对中国在非洲当地的援助成果相当赞赏。你觉得在非洲这片充满机遇的大地上,未来会有一场什么样的改变浪潮? 亚力克•罗斯:进入非洲是中国很高明的一步棋。虽然部分美国人因为中国在非洲的大量投资而感到不安,但基本来说,中国在非洲投资基础设施的初衷是好的。 未来十到二十年,非洲也许会经历中国和印度十几年前同样的变化。无论当前谁在非洲投资,假如坚持十年,那将会大大地受益。当然这也有风险和例外,那就是非洲政治上的不稳定因素,从治理不当的政府那里只会收获失败的交易。 我更希望看到美国、中国和非洲,能在一项共同事业上形成三方合作的成功案例,这或许会发生在医疗健康服务领域,也可能在矿产资源开采领域。 ◆ ◆ ◆ 中国如何成为创新领域的领导者 黄征宇:未来决定一个国家能否跻身世界一流国家的标准之一是看这个国家是否有持续的创新能力。美国目前最大的竞争力还是他的创新力,而中国政府近几年也不断强调,要将创新摆在国家发展的核心位置。 显然,中美两国都意识到,创新对于国家未来发展的重要性。创新能不断让一些老的企业倒闭或衰退,让新的企业甚至是行业成长起来,并富有活力。你认为,中国未来如何能成为创新领域的领导者? 亚力克•罗斯:答案只有一个,就是继续实行开放政策。 每个时代都有其独有的矛盾和对抗,例如左派与右派、开放与闭塞。毫无疑问,在信息时代,最开放的国家将是最具创新性的。21世纪对于控制狂而言是非常不利的一个时代,因为他们不能适应想象和创新;而对于热衷创新的年轻人来说,这是一个天赐的时代。 黄征宇:那么问题来了,中国可以为年轻人和他们的创新提供合适的环境和资本吗? 亚力克•罗斯:中国有着近乎无限的尖端创新人才。打破陈规和突破性的创新往往就来自那些不拘泥于条条框框的人,他们并不在乎别人怎样看待他们和他们的想法。这些人适合活在一个更开放的社会里,而且活得如鱼得水。 他们中的大多数人在年轻的时候就已经表现得与众不同,这些年轻人别出心裁的想法会带来很多的创新。中国应该注意培养和选拔这样的人才,给他们更好的土壤,帮助他们成长。 另一方面来说,从全球视角来切入也很重要。最有发展潜力的企业往往是为了走向全球而建立起来的。比如阿里巴巴、华大基因,他们天生就是全球化的。 ◆ ◆ ◆ 政府该如何制定创新规则 黄征宇:我们都知道打破成规和毫无章法不能划上等号,政府应该如何制定规则,但又不会过度限制创新发展? 亚力克•罗斯:一般来说,规则的制定需要由四个不同的利益相关方共同参与,他们包括政府,企业,学术界和民间社会。人们最好要倾听这四类群体的声音,其中唯有政府可以在聆听其他三方面呼声的同时,还能发挥出制定规则的长处。 我们都知道,如果政府不再能通过调控手段来刺激经济和就业增长,那就必须依靠创新。大家都想知道为什么欧洲进入了一个长期的慢增长通道。首当其冲的问题就是规则设定太多,创新激励太少。我在欧洲看到的政策制定人士都是那些60岁的、西装革履的、离创新前沿比较远的,这样的人在给20、30岁的年轻人制定创新规则,会发生什么可想而知。 ◆ ◆ ◆ 写书的初衷 黄征宇:据我所知,你的这本新书《新一轮产业革命》已经登上亚马逊经济类图书排行榜的冠军位置。回忆一下,你写这本书的初衷是什么呢? 亚力克•罗斯:我来自西弗吉尼亚的煤矿工业地区,是普通家庭出身,所以,我付出了比常人多几倍的努力才得到现在的工作,过上现在的生活,我还很荣幸能与希拉里和奥巴马一起并肩工作。 所有人都对成功非常热衷,但要知道,机会面前并非人人平等,在抓住机会之前你得知道什么是机会。所以我写这本书的初衷,是试图让普通的中产阶级人群能看到全球超级精英们都在讨论些什么,那是一些坐在超音速飞机上的人才会谈论的话题。 ◆ ◆ ◆ 想对中国读者说些什么 黄征宇: 我一直穿梭于中美之间,我知道你这本新书的中文版前不久已经在中国出版了。对中国的读者,你有什么想说的吗? 亚力克•罗斯:我希望中国读者能领会三件事。 如果中国保持开放政策,那中国经济一定会持续增长。 赋予年轻人力量很重要,只有那些为年轻企业家创造最多有利条件的国家和社会,才能创建出像苹果和阿里巴巴这样的公司。 在创新领域里,我们要尽量减少全球范围内的竞争,要抱着相互合作的态度。关于未来,我们要更多地考虑合作。 我每次来过中国之后,对中国看法都会更加乐观。我觉得,中国未来即使很难再保持经济的高速增长,但从劳动力密集型的制造业向知识经济的过渡是令人非常乐观的。在我看来,广东的25岁年轻人和在纽约或伦敦的年轻人同样令人印象深刻。 黄征宇:这么说你还挺喜欢中国的? 亚力克•罗斯:是的,我有三个孩子,我鼓励我的孩子们学习中文,他们自己也很喜欢中文。我13岁的大儿子Colton在霍普金斯大学的中文老师那里学习,他学得很好。而我11岁的女儿,今年11月会开始上中文课。等我9岁的小儿子再大点,他也会开始上中文课。 学会英语的中国商界领袖们在全球的商业环境里会更有优势,对我们也一样。如果中国的经济实力持续上升,那努力学习中文、研究中国和中国文化的美国人也会占据有利的地位。美国惯常的想法和标准是去到世界各地的时候,都可以用英语交流,但我希望我的孩子们能够不一样。 原文发布时间为:2016-09-10 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
快播涉传播淫秽物品案昨日在海淀法院开庭审理。快播公司、王欣、张克东、牛文举均表示认罪悔罪。吴铭表示快播公司犯罪成立。 庭前法院委托鉴定机关,对涉案的四台缓存服务器的硬盘数据是否受到改写污染问题进行了鉴定。鉴定结论是:未发现硬盘中的视频文件在2013年11月18日被行政机关扣押后,有从外部拷入和修改的痕迹。 再次开庭,王欣的态度和半年前截然不同。在2016年1月的庭审中,王欣则是否认快播传播淫秽视频,王欣称,涉案四台服务器是加速服务器。服务器留存的文件是缓存文件,快播无法轻易辨别。 在整场快播案庭审的剧目中,王欣那句“技术无罪”,博得了无数网友的同情和支持。大数据文摘今日也只从技术角度探讨,从数据规模、基础设施等方面说明,成人网站对技术的要求到底有多高。 ◆ ◆ ◆ 成人网站对技术的要求到底有多高 上网之人,多少都会接触过成人网站。这是一个举世公认的事实。 不过这是一个难以洞察的领域,因为相关数据少之又少。我们知道成人网站都是那些在互联网上有着超高流量的网站。根据 Google DoubleClick 的 Ad Planner 服务(通过cookie跟踪网民)显示,全球 Top 500 网站中,就有数十个成人网站。全球最大的色情网站 Xvideos 每月网页浏览量(Page Views,PV)高达 44 亿,是 CNN 或 ESPN 新闻网站的 3 倍,是 Reddit 的 2 倍。LiveJasmin 也不小。除了 Google 和 Facebook 等大站,其他网站在YouPorn、Tube8 和 PornHub 面前都是小巫见大巫。 虽然网页浏览量是一个很好的起始点,但它们仅告诉我们某些色情网站比某些非色情网站要受欢迎。40亿的PV,听起来很多,但当我们把那些X站用户实际在做的事考虑进来,成人网站的大小和规模就有点明朗了。 ◆ ◆ ◆ 规模 色情网站和非色情网站的主页区别是访客的平均停留时间。诸如 Engadget 等新闻网站的平均停留时间是 3 – 6 分钟,大约是是阅读 1 – 2 篇文章。然而色情网站的停留时间,大约是在 15 – 20 分钟。 大部分网站的内容主要是文本和图像,而成人大站则是视频。EXT首页完全加载大约是几兆数据,打开一篇文章,大约是500kb数据。访问色情网站,假设是打开一个 480×200 低分辨率的视频,每秒传输 100 kb 数据。15 分钟的话,那就大约是 90 MB 数据了。 XVDO 每月有 3.5 亿访问次数,乘以 90 MB,那就每月传输大约 29 PB 数据,也就是每秒传送数据约 50 GB。做个对比,你家网络连接可能每秒传送两兆(2 MB),XVDO是你家的 25,000 倍。 简而言之,色情网站是在处理天文数字级别的数据。在原始带宽(Raw Bandwidth)方面,能与之匹敌的网站,也就只有 YouTube 或 Hulu,而 YouPorn 却又是 Hulu 的 6 倍。 ◆ ◆ ◆ 基础设施 就支持视频所需的资源,数据存储器、CPU 周期、I/O 和带宽,远超过文本和图像所需要的资源。 当然了,虽然每个网站的情况又不一样了,但大部分成人站点都有 50 至 200 TB 的成人资料。对一个网站来说,这是个大数目(Google、Facebook、Blogger 和 Youtube 之流存储的数据比这还要多),好在现在 2 TB 的硬盘便宜。 CPU 周期和 I/O 会影响视频流和 PV 数量。首先,色情网站要提供动态、可搜索的海量视频数据库,然后点播视频时,从硬盘读取文件,再网络上传输。如果你有过在局域网传送大量大文件的经历,你就会知道网络系统的压力有多大了。 硬件设备情况,实际上我们几乎无法知晓,因为色情网站也没公布过。虽然如此,但我们讨论的大型色情网站会有四核服务器、千兆交换机、负载均衡器。在软件方面,大部分大型色情网站都会使用超高吞吐量的数据库(比如 Redis )来存储和提供视频,还有轻量级的 HTTP 服务器(比如 Nginx )。 最后说带宽。还是以 Xvideos 为例(基于 Ad Planner 的数据估测),大型色情网站必须有足够的连通性(connectivity)来支撑每秒 50 GB(400Gbps )。这还只是平均传输速率。在高峰期间,Xvideos 或许要 1,000Gbps (1Tbps) ,或更高 。在伦敦和纽约直接的连通性也才 15Tbps。 有很多方法来处理高流量:自己搞个数据中心,或者去大数据中心租赁几排架的服务器,或者使用诸如 Amazon AWS 和 Microsoft Azure 之类的云服务。 ◆ ◆ ◆ 真实案例 YPN是全球第二大的色情网站,足够提供研究数据。另外要说一下,DoubleClick 的 Ad Planner 中的估测数据比实际数据要低很多的。 YPN有“超过 100 TB 的干货”,每天网页浏览量超过 1 亿。总而言,这相当于每天传送 950 TB 数据(大部分都是视频流),每月大约传送 29 PB。Xvideos 肯定不止 28 PB 这个估测值了,它可能是每月 35 – 40 TB。 在高峰期,YPN每秒得响应 4000 个网页,相当于有每秒 100 GB 或(800 Gbps )的突发流量。这相当月每秒传送 10+ 张双层 DVD。 在软件方面,YPN的主数据库是 Redis,用 MySQL 作为管理工具,用于管理和向 Redis 簇中添加数据。后端是 Perl 和 MySQL,不过在 2011 年改成了 PHP + Redis。HTTP 服务器是 Nginx,同时用 HAProxy 和 Varnish 做负载均衡。Redis 服务器可以每秒处理 30 万请求,每小时记录下 8 – 15 GB数据,包括访客日志、行为数据等。据说 Redis 可以抗住 2 亿的日 PV。 (译注:2012年2月份,YPN的技术人员 Eric Pickup 在 Google 群组宣告他们网站改用 Redis DB 后。扛住了每天1亿PV浏览量,每秒30万请求,已经坚持 2 周。Eric 还将去加拿大一个技术大会分享经验。) 令人悲伤的是,YPN拒绝透露硬件设备信息。从 YPN的 CDN 的 IP 地址来看,它应该没有使用云服务,应该托管在某地的大型数据中心。 互联网每天大约处理 1/2 EB 数据,相当于每秒处理 50Tb, YPN的 800Gbps 这个数字,几乎就占了互联网中每秒流量的 2%。而全球有几十个和 YouPorn 规模相当的色情网站。互联网流量中色情内容占据了 30%,这个说法也就不是不现实的哦。 原文发布时间为:2016-09-10 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 导读 我总是在关注和寻找可以改进我如何解决数据分析项目的好想法。尤其喜欢可以转化为我可以重复使用的工具的那些方法。大部分时候,我都是通过自己反复尝试或者咨询其他从业人员来发现这些工具。我与学术界和学术研究也有着密切联系,我经常发一些推文推荐我偶然看到并为之入迷、深感兴趣的学术论文。通常情况下,学术研究的结果不会马上转化为我所能用的,但是我最近偶然从几个研究中发现一些想法,值得与大家分享。 我在这篇文章中阐述的想法解决了一些经常出现的问题。在我看来,这些想法也强化了数据科学中包含的数据管道的概念,而不仅仅是机器学习算法。这些想法也应该能给试图构建人工智能应用的工程师们带来启示。 ◆ ◆ ◆ 使用可重用的保留数据法来避免在交互式数据分析中出现过拟合 过拟合在统计和机器学习领域是一个众所周知的问题。像保留部分数据做验证法、自助法以及交叉验证法等技术被用来在静态数据分析中避免过拟合。被广泛应用的保留部分数据做验证法将整个数据集划分成两个独立集合。但是从业人员(包括我自己)经常在应用经典的保持法的时候忘记重要的一点:理论上相应的保留数据集只能被使用一次(如图一所示): 图一:静态数据分析,由本·骆易家提供 而事实上,目前大部分数据科学项目本身都是交互式的。数据科学家反复迭代多次并且基于之前的结果修正他们的方法或者算法。很多情况下同一个保留数据集被频繁多次地使用,这将会导致过拟合(如图二所示): 图二 交互式数据分析,由本·骆易家提供 为了解决这一问题,有一个研究团队通过借鉴差分隐私的思想设计出了可重用的保留数据做验证方法。通过解决过拟合问题,他们的方法可以增加数据产品的可靠性,特别是在有更多的智能的应用被部署的关键场合里。好消息是他们得出的解决方案对于数据科学家来说是开放的,而且并不要求对差分隐私这一概念的理解。在圣何塞铁杆数据科学会议上的一次演讲中,谷歌的莫里兹·哈特(其中一名研究人员)描述了他们提出的阈值保留数据法,下面是其对应的Python代码: from numpy import * def Thresholdout(sample, holdout, q): # function q is what you’re “testing” – e.g., model loss sample_mean = mean([q(x) for x in sample]) holdout_mean = mean([q(x) for x in holdout]) sigma = 1.0 / sqrt(len(sample)) threshold = 3.0*sigma if (abs(sample_mean – holdout_mean) < random.normal(threshold, sigma) ): # q does not overfit: your “training estimate” is good return sample_mean else: # q overfits (you may have overfit using your training data) return holdout_mean + random.normal(0, sigma) 他们的阈值保留数据法和其他方法的细节可以在这篇论文和哈特的博客文章中找到。我也推荐最近的一篇关于盲样分析的论文——一个相关的数据摄动法在物理学中的应用,可能很快会在其他学科也得到应用。 ◆ ◆ ◆ 使用随机搜索进行黑盒参数调优 大部分数据科学项目涉及到数据管道,其中包含了一些需要恰当调整的“旋钮”(超参数),通常需要反复试验来完成调优。这些超参数通常伴随着特定的机器学习方法(网络深度和架构、窗口大小等),但是它们也涉及到影响数据准备及其他数据管道中的步骤的多个方面。 随着机器学习管道相关应用日渐增多,超参数调优成为许多研究论文(甚至是商业产品)的主题。许多结果是基于贝叶斯优化和其相关技术。 在职的数据科学家不需要急着去学习贝叶斯优化。最近加州大学伯克利分校的本·雷希特的博客中强调:研究表明当进行黑盒参数调优时,简单的随机搜索实际上与更高级的方法相比是十分有竞争力的。并且他们正在努力提高某些特定工作里的随机搜索的速度。 ◆ ◆ ◆ 通过局部近似来解释你的黑盒模型 在某些领域(包括健康、消费金融以及安全),模型解释是常见的需求。而目前黑盒模型风靡全球——包括深度学习以及其他算法甚至是模型组合定义。随着人工智能受到关注,指出黑盒技术仅可以被部署到某些应用领域是十分重要的,这些领域必须已经开发出可以使得模型更加具有解释性的工具。 最近,来自马尔·科图略·里贝罗和其同事们的一篇论文提出了一种可以使得这种模型更加容易解释的方法。在这篇论文中提出的想法是使用一系列可解释的局部可信近似值:这是一些可解释的局部模型,可以近似原始模型在将被预测的实例附近是如何行为的。研究人员观察到,尽管一个模型可能过于复杂以至于不能够全局的解释,但是提供一个局部可信的解释通常来说已经足够。 最近的一个演讲描述了研究人员提供的该方法的实用工具。论文的一位共同作者卡洛斯·贾斯特林演示了一个相关方法的实现,帮助调试一个计算机视觉应用中的深度神经网络。 卡洛斯·贾斯特林将在2016年9月26日至29日在纽约举办的Strata + Hadoop世界大会上做一个名为“为什么我该相信你?解释机器学习模型的预测结果”的演讲。 原文发布时间为:2016-09-11 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 导读 大脑是人身上最惊人的器官。上百万的细胞以某种方式聚集到一起,就产生了思维、感觉和行动——而人之为人,也源于此。 所以,人们对于这个3磅(大约2.4kg)的“大肉块”的工作方式有如此多误解实在不足为奇。以下是关于大脑的五个最大的谣言。 ◆ ◆ ◆ 谣言一 听莫扎特能让你更聪明 古典音乐——尤其是莫扎特——能够让人更聪明的谣言在过去的20年甚嚣尘上。1998年,佐治亚州州长甚至想要设立基金,给该州每一名新生儿一份免费的古典音乐磁带或 CD。但事实是,只有非常罕见的数据显示听莫扎特能够让你变聪明。 “莫扎特效应”首次进入公众视野是在 1993 年,著名杂志《自然》刊发了一篇论文。该研究由 Frances Rauscher(现在任职于威斯康辛大学)主持,研究发现听10分钟莫扎特奏鸣曲(编号448)的大学生比听放松指令,或什么都不听的学生在空间智力测试中得到了更高的分数(8分)。 但即使在该研究中,效果也非常短暂——10到15分钟后就逐渐消失。而且听莫扎特也仅对折纸或用铅笔解决迷宫问题之类的空间智力测试中有效。(随后的研究发现给子宫中的小鼠听莫扎特也有类似的、让空间智力提高的效果。) 但是整体来说,某一方面的智力提高并不意味着其他方面也能如此。所以,没有理由认为这能提高人的数学或文字推理能力。 从那时起,人们开展了数十个研究验证古典音乐的效果。一些能够重复最初《自然》杂志所刊登研究的微小效应,但也有些失败了。 一些科学家认为相比于莫扎特的空间结构天赋,实验的结果与乐趣和情绪更相关。并且实验显示其他音乐也有类似的效应。在2006年一项对10岁和11岁的儿童进行的实验中,Blur 的摇滚音乐比莫扎特的效果更好。 即便如此,对特定莫扎特奏鸣曲的研究现在依然在继续,持续至今。最近有些研究提示莫扎特对癫痫病人脑电波模式能产生一些积极影响。 ◆ ◆ ◆ 谣言二 右脑负责创造思维,左脑负责逻辑思维 右脑半球和左脑半球 (Shutterstock) 大脑分为左右两个半球,由称为胼胝体的结构连接。这种结构导致很多人推测两个半球之间存在很大差异。但是其中很多猜测并不正确。 一个健康的大脑总是通过胼胝体连接左右半球、共同工作。现代脑成像技术例如 fMRI 明确证实大脑协同合作。即使是只涉及到语言、数学和创造的简单任务也跨越了半球,由整个大脑共同完成。 大脑的左右半球只有一个主要区别:右半球控制身体左侧,左半球控制身体右侧。 然而,即使这一点也不是完全固定的。如果一个人受到大脑损伤,健康的部分有时可接管受损部分的功能——甚至是大脑另外半球的区域。 例如,外科医生有时会为了阻止反复剧烈发作的癫痫,切除儿童的半个大脑。一些孩子可能会失去对侧身体的运动能力,但是很多依然能够正常行走和说话——性格也没有什么变化。 (然而,对于为何最初大脑会一分为二也有一些很好的解释——获得更好的整体功能。关于这个,全国公共广播电台(NPR)的 Tania Lombrozo 有一个有趣的采访。) ◆ ◆ ◆ 谣言三 你只使用了大脑的10% 睡着大脑正在清空思维(Shutterstock) 这个错误说法来源不明、传播范围极广。它的持久传播可能是源于人们内心的渴望——每个人都有未解锁的惊人潜力的世界该是多么美好啊。 现在利用 fMRI 和其他成像技术,研究人员能够观察大脑的实际使用情况。他们发现即使在执行非常简单的任务时,也可以清晰地观察到整个大脑都在活动。梅约诊所(Mayo Clinic)的神经专家 John Henley 在《科学美国人》中解释道:“证据显示你的大脑全天都在100%运转。” 考虑大脑的能耗能给你更直观的认识。大脑是一个饥饿的器官,占人类消耗冷凉的20%。人类进化出如此大型、高能耗的大脑却没有整个投入使用的话,就太低效了——可能性几乎没有。这绝对会是对资源的极大浪费。 ◆ ◆ ◆ 谣言四 成年人无法产生新的脑细胞 神经信号对一个脑细胞向另一个脑细胞传递了一个信号的艺术性表现(Shutterstock) 公平地说,这不仅是一个流行的谣言——在很长一段时间,多数科学家坚定地认为人一旦成年,就不再产生新的脑细胞。他们对这个观点深信不疑,当 1960 年代麻省理工学院(MIT)研究者 Joseph Altman 发现成年小鼠能够产生新的脑细胞时,其他研究者置若罔闻。 但是随后这一现象在其他物种中也得到了证实。20世纪80年代,科学家发现了成年鸣禽产生新的脑细胞的证据。90年代,在小鼠和猴子中也发现了类似的证据。 最终在1998年,科学家发表了一项研究,证明成年人也能够产生新的脑细胞。他们通过向数名患有癌症的志愿者大脑中注射细胞标记物证实了这一点。在这些病人去世之后,研究者检查了他们的大脑,并在海马区域(负责记忆的关键区域)发现了新生细胞的切实证据。 科学家仍然在研究这些新生细胞的具体功能,以及他们对人类思维的影响。 ◆ ◆ ◆ 谣言五 你的记忆准确无误 记忆脑和U盘 记忆可能非常不可靠,甚至是当时看来非常鲜明的、高度情感化的记忆(这种记忆常称为“闪光灯记忆”)。我们的记忆常含有错误、空白、错误暗示和近似。记忆通常随时间衰退。大脑并不是完美的电脑似的数据存储设备,而是易错的肉质器官。 例如,在极其戏剧化的辛普森谋杀案审判【注释1】后开展的一项研究发现,人们关于如何听到审判裁决的记忆在15个月后只有一半正确。而在32个月后,正确率只有29%。 在 911 事件7周后进行的研究发现,73%的曼哈顿大学生认为自己在事件发生当日看到了第一架飞机撞击世贸中心的镜头。但这是不可能的。该组镜头直到9月12日才对公众公开。 根据 Greg Miller 在《史密森尼》(Smithsonian)杂志的描述,Karim Nade 等一些研究人员相信,当记忆被频繁唤起时,它们最容易变得扭曲。并且这可能意味着,回忆越重要,回忆的次数越多,就越可能出错。重要的回忆一直伴随着你,而它们一遍一遍在你脑中重演,却可能离事实越来越远了。 【1】辛普森案 (英语:O. J. Simpsonmurder case,又称加利福尼亚人民诉辛普森案,英语:People v.Simpson)是美国加利福尼亚州最高法院对前美式橄榄球明星、演员O·J·辛普森进行的刑事诉讼,在该案中,辛普森被指控于1994年犯下两宗谋杀罪,受害人为其前妻妮克尔·布朗·辛普森及其好友罗纳德·高曼。该案被称为是美国历史上最受公众关注的刑事审判案件。[在经历了创加州审判史纪录的长达九个月的马拉松式审判后,辛普森被判无罪。 原文发布时间为:2016-09-19 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 导 读 “应用机器学习像是把你当一个伟大的工程师,而非伟大的机器学习专家。” 这是我在一份谷歌内部文件中读到的如何应用机器学习的第一句话。的确如此。以我作为服务器工程师/数据分析师的有限经验,数据(以及如何存储/处理)一直都是所有问题的核心,在整体中举足轻重。去问问任何一位Kaggle的获胜者,他们都会说,最大的收获总是来源于聪明地表示数据,而不是使用某些复杂的算法。即使CRISP数据挖掘处理也使用了不是一个,而是两个阶段,专门用来理解和准备数据。 ◆ ◆ ◆ 特征工程 那么,什么是特征工程? 简而言之,就是用最好的方法来表示数据的艺术/科学。 为什么说是艺术/科学?因为好的特征工程是专业知识,直觉和基础的数学能力的优雅组合。呃,最有效的数据表示法基本不包含任何数学计算(下文我会解释)。“最好的”是什么意思?大体上,提供给算法的数据的方式,应该以最有效的方式表示潜在信息的相关结构/属性。当你进行特征工程时,你是在把你的数据属性转化为数据特征。 属性基本上是数据的所有维度,但是所有这些以原始形态存在的属性是否以最佳的表示方式表示了你想学习的潜在趋势?也许不是。所以特征工程是对数据进行预处理,在此基础上进行建模/建立学习算法,从而可以花最小的力气处理噪声数据。在此“噪音”的含义是,任何与学习/预测你的最终目标无关的信息。实际上,由于你已经自己完成了一部分“思考”的工作,使用好的特征甚至可以让你使用简单得多的模型。 但是就像任何机器学习中的技术一样,一定要通过验证确保你引入的新特征确实能够改进预测,而不是增加不必要的复杂性。如果机器学习是发型:模型—华丽的,装饰的,不易打理的,特征工程—接地气的,即兴的,直接的。 如同之前提到的,好的特征工程包含直觉,专业知识(个人经验)和基本的数学技巧。以下是几个非常简单的技巧,你可以应用在你的下一个数据科学解决方案中。 1.表示时间戳 时间戳属性经常是用EPOCH时间来定义,或者分离到多个维度里,比如(年,月,日,时,分,秒)。但是在很多场合下,很多信息是不必要的。比如,在一个监督学习系统里,预测一个城市关于地点+时间的交通流量,如果以秒来发现其趋势,很有可能得到错误的结论。以年为单位对这个模型来说没有太多价值;小时,天和月可能是你需要用到的维度。所以,当表示时间时,试着去确认一下你的模型是否需要你所提供的所有数字。 别忘了时区。如果你的数据源自不同的地域,务必记得在需要的时候用时区做标准化。 2.分解分类型属性 有的属性是种类而非数字。一个简单的例子是“颜色”属性,比如{红,绿,蓝}之一。最常见的表示方法是将种类转化为二元属性,从{0,1}中二取一。于是你得到了一系列增加的属性,数目与种类的个数相等,而且在每个数据点的这一系列属性中,只有一个的值是1(其余的都是0)。这是一种独热编码形式。 如果你第一次接触到这个概念,你可能会认为分解属性是平添了不必要的麻烦(本质上我们扩大了数据集的维度)。相反,你可能更愿意将种类属性转变为一个标量值,比如,颜色特征可能用{1,2,3}代表{红,绿,蓝}。这会带来两个问题。第一,对于一个数学模型,这个可能表示“红色”比“蓝色”更接近“绿色”(因为|1-3|>|1-2|)。除非你的种类的确包含自然顺序(natural ordering)(比如一条火车线路上的车站),否则的话这种表示法可能会误导你的模型。第二,它可能导致统计学参数(比如平均值)失去意义。甚者,造成误导。再次考虑颜色的例子,如果你的数据集包含同样多的红色和蓝色值,而没有绿色值,取平均值仍会得到“2”——代表着绿色! 将种类属性转化为标量值最安全的情况是当你只有两个种类时。这样你就有了{0,1}对应{种类1,种类2}。这种情况下,“次序”不是必要的,并且你可以将属性值解读为属于种类2抑或种类1的概率值。 3.数字分组 有时候,将数字属性表示成分类属性也是一种有效的分析方法。这种方法通过将数字分段划组,来减少噪声对机器学习算法的干扰。比如说,如果我们要预测一个人是否拥有某一件特定的衣服。显然年龄是一个影响因素。实际上年龄组可能更加恰当一些。所以我们可以给年龄分段,比如1-10岁,11-18岁,19-25岁,26-40岁等。对于这样的分类,我们便没有必要像第2点所说的那样再去做类别内的分解,直接用标量值划分组别就可以了,因为相近的年龄组确实是有相似之处的。 属性域能被清楚归类的数据,其同一区间的数字能够代表相同的特征,分组这种方法就比较适用于这样的数据。如果你不想让你的模型区分太相近的数值,这种方法可以减少一些应用中的过拟合问题。比如说,如果你的关注点是一整个城市,你就可以把该城市所有的纬度归到一起。分组这个方法通过将数值”化整”到离它最近的典型数值,来减少微小错误带来的影响。不过,如果分组数量与你的可能值数量相当,或者你要求很高的精度,那么数据分组就没有什么意义了。 4.特征交叉 特征交叉也许是这些方法中最为重要和有用的一种了。这种独特的方法可以将两个或两个以上的类别属性组合成一种。这个方法非常有用,尤其如果相对于单个属性本身,与其他属性的结合能更好地表示某些特性。从数学上讲,是把所有这些属性的可能值做了叉乘。 若某特征A的值域为{A1,A2},特征B的值域为{B1, B2}。A和B之间的交叉特征(我们称之为AB)则是以下这些值中的一个:{(A1, B1),(A1, B2), (A2, B1), (A2, B2)}。你可以自由命名这些“组合”,任何一个组合都代表了A或B特征中的某些信息的合成。 比如以下图表: 所有蓝点属于一类,而红点属于另一类。我们暂且不用知道这个模型的真实意义。首先,你需要把X的值域划分为{x < 0, x >= 0},把Y的值域划分为{y < 0, y >= 0},并把它们分别表示为{Xn, Xp} 和 {Yn, Yp}。显然,第一和第三象限属于红色,而第二和第四象限属于蓝色。如果我们把X和Y做特征交叉,并把结果归类为”象限”这个统一的特征,我们就有了{I, II, III, IV}四个值,分别等同于之前提到的{(Xp, Yp), (Xn, Yp), (Xn, Yn), (Xp, Yn)}。 另一个更加具体也更加相关的好例子是经纬度。一个常见的纬度值与世界上很多地方都有关联,经度也是这样。但是如果你将经纬度相结合,并划分到不同的“区块”,它们就可以代表地理上的“地区”,各个地区内部有着相似的特性。 有时候,多个数据属性可以通过简单的数学计算被“组合”成一个新的特征。在上一个例子中,假设你把特征重定义为和: 那么现在你可以定义一个全新的特征: 就这么简单,如果,则是红色,反之则是蓝色。 作为补充,我接下来将简单介绍几个数学上比较复杂的特征工程技巧,并附带了链接以便大家更好地理解。 5.特征选取 运用某些算法来自动选择原始数据特征中的一个子集,以建立最终模型。你不需要建立/修改现有的数据特征,而是对它们进行删减,来降低干扰,减少数据冗余。 6.特征缩放(数据标准化) 有时候,你可能会注意到有些属性的数量级比别的属性更大,比如一个人的收入,相对于他的年龄而言。在类似的情况下,有些模型(比如岭回归)就要求你把所有的属性都缩放到一个可比较的、同等的范围内。这可以防止某些属性被给予过多的权重。 7.特征提取 特征提取包含了许多算法,它们能够从原始数据属性中自动生成新的特征集合。数据降维是这类方法里的一种。 原文发布时间为:2016-09-12 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
随着探测技术的发达,越来越多“亲吻”我们地球的小行星被发现。 近日,中国国家天文台紫金山天文台的科研人员在盱眙观测站首次观测到小行星2009ES,这个小行星到底对我们的地球有没有威胁?我们应该采取哪些措施?地球会不会毁灭?让我们来一探究竟。 ◆ ◆ ◆ 1.对“地球哨兵”一探究竟 首先,我们来看一下这个有着“地球哨兵”之称的1.2米口径近地天体望远镜。该望远镜坐落于紫金山天文台盱眙天文观测站,地处铁山寺国家森林保护区,由于周围没有城市型生活区及大型工厂等,因此具有比较理想的夜天光条件,远离城市,远离灯光,也是发现2009ES的必要条件,根据当时选址时的测量结果,夜天光下V星等为20.78等,B星等为21.38等,视宁度(指望远镜显示图像的清晰度)小于1角秒。 该天文观测站是我国天体力学的实测基地,主要从事太阳系天体和人造天体动力学的实测研究。已经装备的望眼镜为改正镜口径为105cm、球面主镜口径为120cm的近地天体探测望远镜,以及其它一些小型专用望远镜。 近地天体探测望远镜的类型属于施密特望远镜,在国内同类型望远镜中首屈一指。该望远镜2006年底建成并投入使用,主要用于搜索发现可能威胁地球的近地小行星,保卫地球安全,同时开展其它太阳系天体的实测研究。 ◆ ◆ ◆ 2.为什么说“2009ES”是个“危险”的小行星 探究2009ES之前,我们先来了解一下它存在的位置。 小行星带是太阳系内介于火星和木星轨道之间的小行星密集区域,由已经被编号的120437颗小行星统计得到,这个小行星“生活”的温床是由50多万颗小行星组成的,如此多的数量我们称之为“主带”,很多人也习惯将其称作“小行星带”。 这么多小行星为什么能被凝聚在同一个地方,而不是四处乱窜呢?原因就是,这些小行星除了受到太阳这颗恒星的万有引力,还极大地受到木星的万有引力的影响。 而所谓的“近地小行星”,只看字面意思就非常好理解了,“近地”即指其轨道非常接近地球,它们是偏离主环带的较特殊群体。 2009ES作为近地小行星的一份子,它的轨道与火星轨道距离最近时仅有0.0012个天文单位(约合18万公里)!而地球到火星的距离最近约为5500万公里,一旦它受到火星的引力影响而变轨,那么紧挨着火星的行星——地球就会“有危险”了。当然,变轨的可能性也是有两种,或者远离,也或者是靠近。 那么,什么样的小行星才会成为“危险分子”呢? 据分析,大约是直径超过140米,与地球最小距离不足0.05天文单位(约740万公里)的小行星才会被列入危险小行星行列。 国际小行星联测网的信息显示,2009ES直径在150米-470米之间,距地球最近约为714.4万公里,这两个数据都在危险小行星的范畴。据了解,2009ES是美国亚利桑那州莱蒙山巡天计划于2009年发现的,此前,全球已有8个台站曾观测到它,而这次的发现则是我国第一次追踪到这颗“危险分子”。 ◆ ◆ ◆ 3.目前已经发现了1640颗“其他危险小行星” 根据国际小行星中心网站最新发布,通过全球联测,目前科研人员已发现1640颗“潜在威胁近地小行星”。 图片来源于NASA 早在6500万年前,称霸地球长达1.5亿年的大型动物——恐龙突然消失了。针对恐龙的灭绝,天文学家猜测有两种可能的原因:一是超新星的爆发,大约相当1024颗氢弹能量导致了恐龙的灭绝;二是小行星撞击。1978年,美国天文学家路易斯•阿尔瓦雷斯猜测有一颗小行星撞击冰岛,而这次的撞击相当于100万亿吨TNT炸药的能量,如此剧烈的撞击导致了恐龙的销声匿迹。 除此之外,1908年6月30日,一束巨大的闪光照亮了西伯利亚克拉斯诺亚尔斯克边疆区石泉通古斯卡河盆地的天空,随后发生了相当于1000枚原子弹的剧烈爆炸,一团蘑菇状的状滚滚浓烟直冲到12英里的高空,灼热的气浪此起彼伏地席卷着整个浩瀚的泰加森林,数百平方公里森林在爆炸中被毁灭,这个著名的爆炸就是通古斯大爆炸。 此外,据澳大利亚国立大学(ANU)的地球学家最新研究报告显示,在32亿年前至少有3颗直径在20-50公里的小行星与地球发生了碰撞,这些碰撞大大改变了地球表面的结构和元素构成。 近几年,科学家预计名为Apophis的小行星将在2029年与地球擦身而过,2036年撞击地球。如果击中地球,将产生相当于11万颗原子弹爆炸所产生的能量,等同于整个纽约市及其周围区域的地方都会瞬时毁灭,如果它撞击在海洋中,那么将引起毁灭性的海啸,比2004年印度洋大海啸更猛烈。 Apophis是天文学家已知的近800颗具有潜在威胁的小行星之一。 ◆ ◆ ◆ 4.预防撞击,保卫地球 为了应对这种可能发生的撞击,有人提出了用核武器击毁小行星的方案。但是,地球上所有积累起来的核武器只够用来炸毁一个直径9公里的小行星,而且得准确地击中中心才行,此外,在宇宙中进行核爆炸的后果也难以预料。 因此,人们也在考虑其它对付小行星的方案,例如使用激光或铅锭等。美国宇航局准备在“阿波菲斯”2029年飞临地球时,用“引力拖车”将其引开,在2029年小行星经过地球附近时,只需发射一枚约1吨重的“引力拖车”飞船,就可以改变这颗小行星的运行轨道。根据天文学家计算,“阿波菲斯”这次飞越地球,其运行轨道将因此发生微弱的变化,但当它2036年再度返回时,与地球相撞的可能性非常小,只有1/5000的可能。 虽然若干小行星都来“挑衅”我们的地球,但相信不久的将来随着科技的发展,解决小行星撞击地球的问题将不再困难。 原文发布时间为:2016-09-13 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
有效且透明的市场基石是自由获取信息。信息驱动金融行为。确保对信息的公正使用对市场良性运作至关重要。 但是在公共平台上发布一则金融新闻的简单方式真的能被人看到进而影响股价吗?根据我和其他人的研究结果是:未必。 2001年哥伦比亚大学的吉尔.休伯曼和托姆.雷格夫教授注意到一家生物技术公司EntreMed发布关于癌症研究突破的新闻所产生的特别的一系列市场反应。起初这则新闻是以科普文章刊登在《自然》杂志上,1997年11月在大众化报纸上报导,随之而来的是EntreMed的股价上涨了30%。时隔第一次发布五个月以后,1998年5月《纽约时报》又将这则内容完全一致的文章在头版登出,EntreMed的股价暴涨300%以上。不管在11月份第一次的反应是不够多,还是在5月份的暴涨不合理,有一件事是非常清楚的,那就是新闻的定位不仅仅是它的新奇,金融市场所包含的信息如何扮演着重要角色。 在我的研究中,我发现今天依然存在对金融新闻关注过多和过少的相似的例子。比如,我发现刊登在报纸的头版或者网站的顶部的新闻就能获得更多读者的关注。读者也更关注大公司或者知名度高的公司新闻、一周内较早发布的新闻和一些负面新闻。重新发布旧新闻会继续刺激市场反应。这种做法新闻记者或者新闻迷都不会感到惊讶,但是对仅仅以金融相关性为基本,需要公平吸收全部新闻的金融市场来说是个挑战。 ◆ ◆ ◆ 这些可预测的新闻消费陷阱的出现来自于人的心理状态 标题党文章所处的角色会起到干扰的作用:面对繁多的竞争线索,人们很难集中注意力去关注相关的信息。信息含量越复杂,对获取相关的信息越难。打个比方,加利福尼亚大学和德保罗大学的David Hirshleifer,Sonya Lim 和Siew Teoh教授表示在同一时间发布大量的信息时,市场在处理盈余公告上的效率就更低。在“市场何时能鉴定出那些过气的新闻?”这个问题上,我和James Hodson都认为旧新闻重新刊登,它同样被复杂性驱使着。当旧新闻不再是直接将先前的单一的重新刊发,而是以多重资源来描绘时,市场参与人员则更有可能因为新刊发的新闻而误解了旧的新闻。 但是虽然市场作为一个整体在处理金融新闻展示了各种偏差,没有用同样方式展示所有金融专业的消费新闻。在鉴定新颖性的新闻时,有的更快速,更活跃和更精炼。在“新闻消费:从信息到回馈“这个问题上,我比较了不同的专业金融新闻消费模式。平均来说经销商和对冲基金比银行、大型投资管理公司要更快捷地点击那些新闻。对冲基金也更有可能第一时间得到消息。对冲基金只有8%的金融专业人员会去看金融新闻,然而所有的新闻中27%都是由对冲基金的人在第一时间阅读的,也就是说发布的任何一则新闻,对冲基金的人极有可能比其他投资人最先看到。 对冲基金的那些读者有的来自家族理财室,有的来自私人股权公司,有的来自代理经销商,他们很少去看那些旧内容的新闻,他们比任何金融专业人员看更多的新闻。 ◆ ◆ ◆ 市场中越复杂的新闻消费越能产生更大的影响力吗?是的 通过像对冲基金投资者这类较活跃的新闻读者来增加注意力就更能预测股价的走势和交易量,比通过其他投资人包括大型投资经理和养老基金要好。对冲基金的关注点提高一个标准误差第二天就能产生30个偏差点的大回报和3-4%的高交易量。 这些市场冲力的产生是由于新闻消费在投资人对投资前景方面产生了不同意见。通常有两种主要的交易量来源:一种是偿债能力需要,投资者因为资金流动或者证券投资组合再平衡需要交易。另一种是意见不统一,持不同观点的贸易商互相打赌。由于新闻发布(比如盈余公告)不会和流动性的股票有组织地同时发生,围绕新闻所产生的交易增加量要归结于意见的不统一,但是为什么公共新闻会产生意见不统一呢? 在“新闻背后的意见不一致:是逐渐升级的信息扩散还是观点不同?”这个问题上,我发现对新闻理解不一致很大部分是他们在不同时间读到新闻所造成的。一个没有看到这则新闻的投资者会很乐意地和看过这则新闻的投资者做交易。市场活动的很大部分也是受那些花了很大时间去阅读和分析那些公共新闻的人所导致。事实上,由于阅读新闻人数广泛分布而产生广泛的信息流动会导致交易量暴增160%。 将信息引入公共平台是极其重要的,但是公共信息处理过程也很复杂,尤其是新闻环境不断改变。 路透集团新闻和金融信息部前CEO汤姆•罗瑟这样描述:“大量的时间和成就都是由管理着公共和私人潜在市场波动信息分水岭的上市公司贡献的。我能预想我们丢弃了像10-Qs和8-Ks这样的概念转而去支持持续不断的相关操作数据而形成的未来。这首先对上市公司的高官们将是非常痛心的,它每天都产生波动。然而从长远来看,投资者和管理人员会作出调整。 这样的未来是令人兴奋的,但是也可能会提高市场自身的挑战。当今新闻的扩散包括重新刊发和重新包装的旧新闻都会让处理信息的市场任务变得更加复杂。 发行商们利用判断力来决定该刊登哪些新闻又在什么地点刊登,投资者们则根据这些公共信息进行交易。双方对金融市场的稳定和效能都起到至关重要的作用,尤其是当每天的新闻发行量达到几百万时。 Anastassia Fedyk是哈弗商学院商业经济哲学博士候选人,他的研究主要关注金融和行为经济。 原文发布时间为:2016-09-13 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
微信的开机界面看腻了吗? 在中秋节这天,大数据文摘向您推荐NASA中文(nasawatch)近期发布的一组图片,这是@POCKN 根据微信登录界面制作的太阳系行星图,请自行选取你最心水的星球保存。 第一张乱入的【中秋节专用微信开机界面-月球图】来自大数据文摘团队,大数据文摘与您的相遇源于微信,我们日日在微信中相见、相熟,希望今日共赏此月,“千里共婵娟”。 一:水星 水星是太阳系的八大行星中最小和最靠近太阳的行星,有着八大行星中最大的离心率,中国称为辰星。 二:金星 金星是太阳系从内向外的第二颗行星,在中国古代称为太白,另外早晨出现在东方称启明,晚上出现在西方称长庚。 三:地球 这是我们人类的家园——地球。是太阳系从内向外的第三颗行星,是目前人类所知宇宙中唯一存在生命的天体。 四:火星 火星是太阳系从内向外的第四颗行星,无论是质量还是体积,在太阳系的八大行星中,火星比水星略大,为第二小的行星。另外NASA计划在2030年代中期登陆火星。 五:木星 木星是太阳系从内向外的第五颗行星,亦为太阳系中体积最大,自转最快的行星。它的质量为太阳的千分之一,但为太阳系中其他行星质量总和的2.5倍。最晚发现于17世纪,当时人们使用望远镜就可发现它的存在。就在本周内,我们将收到朱诺号探测器传回的木星北极区域高清图片。 六:土星 土星是太阳系从内向外的第六颗行星,体积则仅次于木星。上面这张照片为卡西尼飞船拍摄的木星。1610年,伽利略用望远镜看到了土星光环的存在。 七:天王星 天王星是太阳系从内向外的第七颗行星其体积在太阳系中排名第三。首次发现于1781年3月13日,由天文学家威廉·赫歇耳发现。 八:海王星 海王星是太阳系八大行星中距离太阳最远的,体积是太阳系第四大,但质量名是第三。1846年9月23日首次由天文学家埃班·勒维耶和约翰·伽雷发现。 九:冥王星 冥王星,是柯伊伯带中最大的天体。2006年,国际天文联合会(IAU)正式定义了行星概念,将冥王星排除在行星范围,不过在2015年7月14日,新视野号探测器近距离飞掠冥王星时,全世界都被这颗“萌王星”之心震撼到了! 原文发布时间为:2016-09-15 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
引言:消灭任何一类生物体都会对生态系统造成严重影响,但如果是蚊子的话,说不定还真不会。 科学家们,用数据展现了他们的研究成果。文末有互动投票,欢迎参与。 每天,吉塔娃蒂·墨菲(Jittawadee Murphy)都会打开一个炎热、上锁的房间,这间屋子位于马里兰州银泉的沃尔特·里德(Walter Reed)陆军研究所,里面关着一群携带疟疾的蚊子(史蒂芬斯氏按蚊)。她给数以百万计的蚊子提供碾碎的鱼食作为食物,并且让妊娠中的雌蚊从昏迷的小鼠肚子上吸血——它们一个月内吸干了24只这种啮齿动物!墨菲研究蚊子已经20年有余,一直致力于寻找限制其所携带的寄生虫的传播方法。但是,她说,她宁愿蚊子干脆就从地球上消失。 相信支持她的人一定有很多。每年全世界范围内会有2.47亿人感染疟疾,其中近百万人会因此死亡。蚊子还会传播黄热病、登革热、乙型脑炎、裂谷热、基孔肯雅病毒和西尼罗河病毒,造成更加巨大的医学与财政负担,最近肆虐美洲的寨卡病毒也是由蚊子所传染。然后是虫害的因素:它们的种群数量太过密集,甚至能让阿拉斯加的驯鹿窒息,而现在正是北半球的夏天,蚊子的数量更是达到一个季节性的高峰,整个北半球的人和动物都受到它们的叮咬和侵扰。 如果这个世界完全没有蚊子,将会怎么样呢?会不会有人(或者别的什么东西)会怀念它们?《自然》向研究蚊子生物学与生态学的科学家们抛出了问题,得到的答案是令人惊异的。 目前约有3500种以蚊子命名的生物,其中只有一两百种会叮咬或者袭扰人类。它们生存在几乎每一块大陆的各种栖息地上,在众多的生态系统中发挥重要作用。“蚊子已经在地球上存在了至少一亿年,”墨菲说道,“它们与相当多的其他物种一起进化。”消灭一种蚊子,可能就会让捕食者没有食物,或让某种植物失去传粉的媒介。而探索一个没有蚊子的世界已经不再只是想象中的实验:人们已经投入了相当多的努力,就是为了消除这个最有害、最能传染疾病的物种。 然而科学家发现,在很多情况下,由一种蚊子的消失引起的生态缺口很快就会被其他生物填满。生活将会跟以前一样,甚至还会更好。考虑到它们是主要的疾病传播媒介,“很难说消灭它们会有什么坏处,只是保不准有点附带损害。”伊利诺伊州立大学的昆虫生态学家史蒂文·朱利亚诺(Steven Juliano)说。没有蚊子的世界将会“对我们更安全”,来自巴西圣卡塔琳娜联邦大学的医学昆虫学者卡洛斯·布里索拉·马孔德斯(Carlos Brisola Marcondes)说,“蚊子的消失对于人类而言影响重大。” ◆ ◆ ◆ 影响最大的是北极 如果蚊子全部消失,受影响最大的区域可能是北极冻原,这里居住着撮毛伊蚊( Aedes impiger )和黑足伊蚊( Aedes nigripes )。虫卵将会在第二年积雪融化后孵出,发展到成熟阶段仅需3到4周。从加拿大北部到俄罗斯,每年都有很短的一段时间内它们数量极其庞大,在有些地区甚至会形成厚厚的蚊子云。“这在全球范围内都是一个非常罕见的情况,”昆虫学家丹尼尔·斯特里克曼(Daniel Strickman)说。他是美国农业部在马里兰州贝尔茨维尔地区的医疗和城市昆虫学项目的负责人,他还补充道,“世界上没有任何一个其他地方,生物的数量可以如此庞大。” 关于如果这个生物群消失了会发生些什么,科学家们持有不同的观点。北卡罗来纳州环境与自然资源部的昆虫学家布鲁斯·哈里森(Bruce Harrison)预计,若没有蚊子作为食物,在苔原筑巢的候鸟数量将会减少50%以上。但其他的研究人员并不这样认为。阿拉斯加费尔班克斯地区的美国渔业与野生动植物服务中心的一名野生生物学家,凯茜·库尔比(Cathy Curby)认为,北极蚊子并没有大量地出现在候鸟胃部的样品中,蠓(摇蚊)才是更重要的食物来源。“人类可能高估了北极冻原的蚊子数量,因为它们只是选择性地被我们所吸引。”她说。 蚊子平均每天从每只驯鹿上吸取高达300毫升的血液,因而我们曾经认为麋鹿群应该会选择迎风的路线来逃离蚊群。当驯鹿群在北极的山谷中迁移时,路线上的微小变化都会引发极大影响:它们践踏草地、啃食地衣、输送营养物质、还会被狼群吃掉,这些最终会改变沿途的生态环境。如果将这些都考虑进来,蚊子的消失在北极地区会有相当大的影响,但是在其他地方是否也是这样呢? ◆ ◆ ◆ 以蚊子为食的其他动物呢? “蚊子很容易捕捉,而且吃起来味道还不错。”密歇根州立大学的水生昆虫学家理查德·梅里特(Richard Merritt)说。如果没有了蚊子的幼虫,会有数百种鱼类不得不改变它们的食谱才能生存下去。“这听起来很简单,但饮食习惯这种特性已经深深烙印这些鱼的遗传基因中。”哈里森表示。比如说,食蚊鱼(Gambusia affinis)是一种专门的蚊子捕食者,很擅长杀死蚊子,因此被养殖于稻田和泳池里作为害虫防治的手段,没有了蚊子,它们说不定就会灭绝。而这种鱼或其他鱼类的消失会对整个食物链的上下游产生巨大影响。 此外还有很多种类的昆虫、蜘蛛、蝾螈、蜥蜴和青蛙也会失去这一重要的食物来源。在2010年发表的一项研究中,研究者在法国卡马格地区的公园内喷上微生物杀虫剂,并跟踪观察捕食昆虫的毛脚燕的生存状况。他们发现,在喷上微生物杀虫剂之后平均每只鸟巢会产2只幼鸟,而在其他对照地点则平均孵化出3只幼鸟。 大量的捕食蚊子的鸟类很可能转向其他昆虫,这些昆虫会在“后蚊子时代”大量繁殖来取代蚊子的生态位。其他的食虫动植物可能完全不会想起它们:蝙蝠主要捕食飞蛾,而且蚊子在其肠胃内还占不到2%。“如果你正在消耗能量,”美国疾病控制与预防中心的医学昆虫学家珍妮特·麦卡里斯特(Janet McAllister)反问道,“你会选择吃22盎司的蛾子牛排,还是6盎司的蚊子汉堡?” 菜单上的选择很多,似乎大多数昆虫捕食者在没有蚊子的世界也不会挨饿。看来蚊子对生态系统的影响还没有大到让人们暂时放弃把它们赶尽杀绝的想法。 ◆ ◆ ◆ 那么幼虫呢? 蚊子的幼虫在全球水生生态系统里的构成了可观的生物量,它们可以存在于一切水体中,从不管是雨后的水塘,还是树洞,或者老旧的轮胎内。在洪水泛滥的平原,幼虫的密度大到它们的蠕动都能在水面上引起涟漪。它们以腐烂的树叶、有机残渣和微生物为食。问题是,如果没有蚊子,其他的滤食性生物是否会来替代它们?“能够处理有机碎屑的生物有很多,蚊子并不唯一的一种,更不是最重要的一种,”朱利亚诺说,“如果你取出飞机机翼上的一个铆钉,飞机也不可能因此停止飞行。” 在全世界的水体内,蚊子都是生物群体中重要的组成部分。 图片来源:M. & P. FOGDEN/MINDEN PICTURES/FLPA 也许蚊子消失实际的效果取决于具体的水体。在北美东海岸的紫瓶子草(一种猪笼草)内有一个大约25到100毫升的微型水域,而蚊子的幼虫是这个小小的紧密团体中重要的成员。北美瓶草蚊(Wyeomyia smithii)和瓶草摇蚊(Metriocnemus knabi)是唯二居住在此的昆虫,一同住在这里的还有轮虫、细菌和原生动物。当其他生物掉到水里淹死后,摇蚊咀嚼其尸体,瓶草蚊的幼虫则以残渣为食,为植物提供比如氮一类的营养物质。在这个例子中,消除蚊子可能就会影响植物生长。 在1974年,生态学家约翰·阿迪科特(John Addicott,现就职于加拿大亚伯达省的卡里加尔大学)发表了关于猪笼草内的捕食者与猎物结构的发现,表明有蚊子幼虫存在时,原生动物多样性更加丰富。他认为,蚊子在进食时控制了原生动物中优势种类的数量,使得其他原生动物得以生存。而对于植物而言,更广泛的后果仍然不得而知。 如果蚊子提供了“生态系统服务”——即让人类从自然中获益,这可能会成为继续让蚊子存在的强有力的理由。美国罗格斯大学新布朗斯维克分校的进化生态学家迪娜·丰塞卡(Dina Fonseca)举出蠓科的摇蚊,有时候也被认为称为蠓科小虫(no-see-ums)这个物种来作为对比。“人们被蠓科小虫叮咬,或者因为它们而感染病毒、原生动物或者丝虫,就会很想消除它们,”她说,“但是因为一些蠓科蚊子是热带植物如可可树的传粉昆虫,消灭了它们将导致我们没有巧克力可吃。” 成年蚊子依靠花蜜来给自身提供能量(只有某些雌蚊需要吸食血液来得到蛋白质用于产卵),如果没有蚊子,数千种植物就将失去一种传粉媒介。但麦卡里斯特表示,对于人类依赖的作物而言,它们的传粉好像没啥用。“如果哪怕有一种让它们留在身边的益处,我们早就利用它们了,”她说,“我们不需要蚊子的任何东西,除了让它们走开。”(蚊子:你喜欢我哪一点?人类:我喜欢你离我远一点。) 最终,似乎没有蚊子可以做而其他生物不能做的事情,也许除了传播疾病——它们极其擅长于从一个动物上吸食血液,然后在扎入到另一个动物体内,这为病原微生物的传播提供了理想途径。 “消除有害蚊子的生态学效果是人口会增加,这就是结果。”斯特里科曼说。许多生命将会被挽救,更多的人将不再受疾病的折磨,许多国家也不再被疟疾所困扰。比如在撒哈拉以南的非洲地区,消灭蚊子可能会让国民生产总值增加1.3%(这是据世界卫生组织估计每年由于疾病所消耗的GDP),这些钱可以用来加速当地发展。“蚊子的消失可以减少卫生系统与医院的财政负担,将用于病媒传播疾病的公共医疗开支投入到其他需要优先解决的健康问题上,还能降低辍学率。”世界卫生组织驻马尼拉的疟疾科学家杰弗里·希(Jeffrey Hii)表示。 来自佛罗里达医学昆虫学实验室的生态学家菲尔·卢尼博斯(Phil Lounibos)认为“消除蚊子只会暂时缓解人类的痛苦”。他的研究表明,消除一类病原微生物携带物种的努力都会是徒劳的,因为这个生态位缺口很快会由别的生物补上。他的团队从佛罗里达州的垃圾场里收集了雌性黄热病蚊(埃及伊蚊),发现其中一些已经被亚洲虎蚊(白纹伊蚊)受精,而后者会携带多种人类疾病。这个受精过程会使雌性黄热病蚊失去生育能力,表明了一个物种是如何取代另一个的。 鉴于蚊子传播疾病而导致的严重的人道主义与经济后果,多数科学家会认为人类总体健康的改善会超过人口增长的代价。而在生态系统中会造成“附带损害”的观点,也不会为蚊子赢得到多少同情。“每一种生物在自然中都有重要作用”的浪漫观点同样不足以为蚊子的审判提供辩护。世界上还有蚊子,并不是人类有意留着它们肆虐,而是因为能力有限。 因此,虽然人类会不经意把有益物种(从金枪鱼到珊瑚)推到灭绝的边缘,但人类的万般努力都没能让蚊子的生存受到严重影响。“它们并没有在环境中占据牢不可击的位置,”美国蚊虫防控协会的昆虫学家乔·康伦(Joe Conlon)说,“如果我们明天就能让它们消失,那它们所活跃的生态系统估计也就打个嗝,然后淡定地继续运转,自然会有其他的物种来替代蚊子,而至于是好是坏就说不清了。” 原文发布时间为:2016-09-16 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
仔细看这幅图。里面到底有几个黑点呢? 实际上有12个黑点。立命馆大学心理学教授Akiyoshi Kitaoka近日在脸书上贴出了这张图,而大部分人都无法看出来。 这张图就是有名的赫曼方格,名字来源于德国科学家赫曼,他于1870年在期刊中发表这幅图。当你注视黑色方格之间的白色空间时,你会发现其他的白色空间都变灰了。赫曼方格是一个著名的“有力视错觉”,因为所有人都会看错,而且你无法适应。 1985年,JR Bergen发明了一个赫曼方格的变体,能够产生不同的效果。这里的方格变模糊了,当你看着它,上面会出现接二连三闪烁的黑色小点。 在2000年,研究者Jacques Ninio和Kent Stevens又创造一款赫曼方格,也有类似的闪现效果。他们发现,将拥有黑色轮廓线的白圈放进交汇处,然后将花纹歪斜,就会产生一种“湮灭效果”。 这两位在Perception期刊上发表了论文:“把有黑色轮廓线的白色圆点缩小放进网格中,它们就会消失。你一次只能看到一部分白点,它们会在三两成群在页面中无序移动。在没有白点的地方,灰色条纹似乎是延续不断的,而实际上条纹是被白点所截断的。” 他们说这种错觉反过来也有效(就是黑点在白色网格中)。 一种解释是人类视网膜的侧抑制现象。为了聚焦,视网膜里的神经节细胞会增强焦点处接收到的刺激,减弱这一点之外的刺激。但是看着方格时,会导致细胞误会所收到的刺激。一些科学家认为这种错觉会让那些视力没有聚焦到的白点隐身。 四个区域刺激减弱vs两个区域刺激减弱 如果这些白点更加明显,比如变得更大,你的眼睛就不会让周围白点消失了。对比下面两张图: 原图 白点被放大 你也可以让这个错觉消失。比如先看着屏幕,然后将屏幕前倾,再看着它。 这么做之所以有效是因为倾斜屏幕增加了对比,这让黑点变得更加明显,从而视网膜不再受到侧抑制的影响。 反过来也有用,如果将屏幕后仰。对比度减少则会让所有的黑点消失。 原文发布时间为:2016-09-17 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
根据最新发表在Physical Review Letters上的文章,时间晶体,这种听起来科幻感满满的东西可能真的存在。 诺贝尔奖得主Frank Wilczek在2012年首次提出这个概念。一开始这只是纯粹出于数学上的好奇,将结晶的概念从三维扩张到思维。现在Wilczek新研究说明了这种晶体存在的真实可能。 针对时间晶体的主要疑点就是,它们似乎可以通过周期性移动实现永恒运动,然后可以反复回归到原始状态。这就违反了物理学中一条基本的对称性,即“时间平移对称性”。 时间平移对称是一项基础的时空对称,即物理法则在任何地方任何时间都是一样的。Wilczek和他的同事们认为这一潜在的违反是说得通的,因为「显性对称性破缺」(explicit symmetry breaking)和「自发对称性破缺」(spontaneous symmetry breaking)之间有着明显区别。 “在显性破缺中,自然法则不再含有对称性;自发性破缺中,自然法则仍含有对称性,但是自然选择了另一种不具备对称的状态,”研究合著者Dominic Else解释说。 如果时间结晶仅仅打破了自发性对称,它们则不是自然中第一个吃螃蟹的。比如,在磁铁中对称性就被打破了,因为它可以自发“选择”哪一头是北极,哪一头是南极。然而这并没有打破物理法则本身的对称性,仅仅代表物理法则没有决定具体要发生的事情。 普通的晶体也会自发性打破对称,虽然这些对称都存在于自然中,并没有延伸到时间维度里。人类还从未观察过自发性打破时间平移对称的情况,但是如果真的观察到,时间晶体应该是最有可能发生的地方。 为了证明这一可能性,研究者们进行了一系列模拟,使得时间平移对称性发生自发性破缺可以在不打破任何基础物理法则的情况下发生,比如热力学定律。 所以时间晶体是有可能在自然中存在的,至少从数学角度上说不是不可能。所以下一步的任务就是试图造出一个时间晶体,这也是Wilczek团队开始筹划的事情。他们设想了一个被俘获的原子、离子或者超导量子比特的大型系统来制造时间晶体。 如果他们能够成功,这将是一个震惊世界的突破。 原文发布时间为:2016-09-18 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
最新的KDnuggets调查统计了数据科学家们实际工作中最常使用的算法,在大多数学术和产业界,都有惊人发现哦! 根据Gregory Piatetsky, KDnuggets,最新的调查问题是:在最近的12个月中,你在实际数据科学相关应用中用到了那些模型/算法? 于是就有了以下基于844份答卷的结果。 ◆ ◆ ◆ 排名前十的算法和它们在投票者中所占比例 图1:数据科学家最常用的10大算法,所有算法见文末表格 每个受访者平均用到了8.1种算法,这相比于 2011 的相似调查显示的结果有了巨大的增长。 相比2011年对数据分析算法的调查,我们注意到最常用的方法仍然是回归,聚类,决策树/规则以及可视化。比例增幅最大的是(增幅=%2016/%2011 -1): Boosting算法,提升了40%。由2011年的23.5%提升倒2016年的40% 文本挖掘(Text Mining),提升了30%。从27.7%提升到35.9% 可视化(Visualization),提升了27%。从38.3%提升到48.7% 时间序列/序列分析(Time series/Sequence analysis),提升了25%。从29.6%提升到37.0% 异常检测(Anomaly/Deviation detection),提升了19%,从16.4%提升到19.5% 组合方法(Ensemble methods),提升了19%,从28.3%提升到33.6% 支持向量机(SVM),提升了18%,从28.6%提升到33.6% 回归(Regression),提升了16%,从57.9%提升到67.1% ◆ ◆ ◆ 2016年新秀中最为流行的是 K-最近邻法(K-nearestneighbors), 46% 主成分分析(PCA), 43% 随机森林(Random Forests), 38% 优化(Optimization), 24% 神经网络-深度学习(Neural networks - Deep Learning), 19% 奇异值分解(Singular ValueDecomposition), 16% ◆ ◆ ◆ 降幅最大的是 关联规则(Associationrules),下降了47%,从28.6%降为15.3% Uplift modeling,下降了36%,从4.8% 降为3.1%(出人意料的低,因为有很多相关文献发表) 因子分析(Factor Analysis),下降了24%,从18.6%降为14.2% 存活分析(SurvivalAnalysis),下降了15%,从9.3%将为7.9% 下面的表格显示了不同的算法类型的使用场所:监督算法,无监督算法,元算法和其它算法。应用类型未知(NA,4.5%)或者其它职业类型(3%)的不包括在内。 表1:不同职业类型的算法使用 我们注意到,几乎所有的人都在使用监督学习算法。政府和产业界的数据科学家们使用的算法类型比学生和科学界要多。产业数据科学家们更倾向于使用元算法。 ◆ ◆ ◆ 不同职业类型最常用的10大算法+深度学习情况 接下来,我们分析了不同职业类型最常用的10大算法+深度学习情况 表2: 不同职业类型的10大算法+深度学习 为了更清楚地展示这些差异,我们用一个公式来计算不同职业类型的算法使用率偏倚: 偏倚=某种职业类型的算法使用率/所有职业类型的算法使用率-1 图2:不同场所的算法使用率偏倚 我们注意到,产业数据科学家们更倾向于用回归,可视化,统计,随机森林和时间序列。政府/非盈利组织则更倾向于使用可视化,主成分分析和时间序列。学术界的研究人员们更多的用到主成分分析和深度学习。学生们普遍使用的算法较少,但多用到文本挖掘和深度学习。 接下来,我们看看某一具体地域的参与度,表示整体的KDnuggets用户。 参与调查人员的地区分布: 美国/加拿大, 40% 欧洲, 32% 亚洲, 18% 拉丁美洲, 5.0% 非洲/中东, 3.4% 澳大利亚/新西兰, 2.2% 在2011年的调查中,我们把产业和政府两个行业的被调查者合为一组,把学术研究者和学生合为一组,然后计算行业政府组的算法使用亲切度: (行业政府组的算法使用率/学术学生组的算法使用率)/(行业政府组的人数/学术学生组的人数)-1 因此,亲切度为0的算法表示它在产业/政府组和学术学生组使用率相同。越高IG亲切度说明该算法越偏向于产业,结果越小则算法越偏向于学术。 最偏向于“产业算法”是: uplifting modelling, 2.01 异常检测, 1.61 存活分析, 1.39 因子分析, 0.83 时间序列/序列分析, 0.69 关联规则, 0.5 尽管uplift modeling再次成为最偏向于“行业算法”,令人吃惊的却是它使用率极低,只有3.1%,是整个调查中比例最低的。 最偏向于“学术算法”是: 神经网络, -0.35 朴素贝叶斯, -0.35 支持向量机, -0.24 深度学习, -0.19 最大期望, -0.17 下图显示了所有算法及其产业/学术亲切度。 图3:KDnuggets调研:数据科学家使用最多的算法:产业与学术领域对比 下表是所有算法调研结果的细节,分别是2016年受访人群使用比例,2011年使用比例,变化(2016年比例/2011年比例-1)以及上文提及的产业亲切度。 表3:KDnuggets2016调研:数据科学家使用的算法 下方的表格是所有算法的调研结果细节,不同列依次代表的是: 排名: 根据使用比例的排名 算法:算法名称 类型: S – 有监督, U – 无监督, M – 元(meta), Z – 其他方法, 在2016年调查中使用该算法的人数比例 在2016年调查中使用该算法的人数比例 变化:(%2016 / %2011 -1), 产业亲切度见上文的解释. 表4:KDnuggets 2016 调研:数据科学家使用的算法 原文发布时间为:2016-09-18 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 金融科技即为资产创新的一种 金融科技的出现和蓬勃发展,很大程度上是由时下的经济环境决定的。从信贷周期或流动性周期来看,金融的创新是有周期性的,创新最主要的动力就来自于资金的流动性过剩,资金的本质是追求高回报,因为近年来经济形势不好、以往资金获利的能力下降,所以解决资金回报问题的方法之一是资产创新。金融科技就是资产创新的一种。 在峰瑞资产创始合伙人李丰看来,创新资产的风险度通常较高,金融系统出于稳定性的需求,就需要分散风险,通过各种形式和衍生工具进行证券化。在近日朗迪金融科技峰会上,他说: “投资相应地也应该按照这个次序进行,这就是为什么我们先投资了一些做创新资产的公司,之后投了一些数据类的公司和做资产证券化的公司,这些公司用新的方法,解决了如何分散风险和定价这些创新资产的问题,接下来可能会有新的理财平台和理财模式出现。” 大势之下,金融科技已经深深改变我们的生活。 首先是针对中小企业的借贷,给他们提供发展业务的资金,优化了供应链,打造信用系统;各种新兴支付手段出现,科技加速了交易支付的迭代,创造新业务机会;财富管理不仅是针对有钱人的服务,智能投顾让普通人得到财富管理的建议;在保险业务方面,通过大数据有效降低保费,互联网保险让更多用户有机会参与其中。 比较中美市场来看,中国的金融创新有着独特的思路。在美国,由于银行信用卡的普及,P2P更多扮演着银行竞争者的角色,对于此前Lending Club的CEO被踢出局事件,一些业内人士认为是P2P平台“动了华尔街银行家的奶酪”的后果。 而在中国,我们从监管者的眼中看到,金融创新是建立在金融压抑的环境上的,领导层希望一切创新都是传统金融的互补行为,解决传统金融没有覆盖的需求。 随着金融市场化和利率市场化的进程,国内的金融压抑减轻之后,金融创新的高潮可能会有回落,这是必然的,未来市场会进入更加理性、平稳的发展阶段。 ◆ ◆ ◆ Fintech的下一步在哪里? 一,行业集中度提高 金融科技公司的“概念时代”已经过去了,现在国内有几千家P2P公司、大量的众筹平台,最近涌现出一系列智能投顾平台,市场也都有了免疫力。 随着监管的介入、市场竞争的加剧、用户教育的深入,行业集中度会有很大的提高。最终竞争会回归商业模式和资本的比拼。 目前国内估值较高的金融科技公司包括:蚂蚁金服,估值600亿美元;陆金所,估值185亿美元;众安保险,76.3亿美元;京东金融,71.8亿美元;微众银行,55亿美金;美国的Paypal是470亿美元的体量。可以看出中国的金融科技公司,在国际市场都是很大的规模。接下来,“跑得快”的金融科技公司会先后上市,行业内各家平台也会进行并购和整合。 二,智能投顾要接中国地气 人工智能在金融领域最直接的应用是智能投顾,目前嘉实基金和北大光华管理学院合作建立博士后工作站,主要研究方向为人工智能投资和大类资产配置;天弘基金也在力推在线投顾业务;大成基金和北京大数据研究院等机构联合成立大数据俱乐部,希望推动智能金融的发展。 可以看出,公募基金希望在此前基金单品的基础上,根据客户的投资目标做更多的产品服务创新,带动公司的投资管理和IT运营。未来智能投顾或许成为公募基金发展的新方向。 除了公募基金,从银行业、股票到网贷,未来都是需要智能投顾的用户渠道。不过在中国,这个行业还需要接地气,首先是中国投资者普遍不信任第三方来帮助自己理财,用户习惯的养成还需要时间。 其次是智能投顾平台能否整合足够的资产出来,把资产做很好地梳理,再提供给投资客户,同时还要对客户风险偏好和需求非常了解。 智能投顾在美国发展多年,有着良好的用户教育基础,美国智能投顾平台Betterment首席执行官Jon Stein介绍:我们在提供智能投顾的意见,是以目的为基础的建议,可能是一个财富管理的目标,有一些是退休的目标,有一些是保值的目标。 用户在美国其它机构开一个户,可能需要六七天的时间,而在Betterment只需要5分钟,此外平台还开发了很多安全措施,保证电子化、无纸化的操作,节省了用户时间,提供完整的服务,包括利率、汇率的情况,让客户更快了解到金融市场的变化。这些思路都值得国内智能投顾平台借鉴。 三,利率将会下降 纵观网贷平台,现在的利率水平非常高,一些平台对借款人的利率高达20%。中欧陆家嘴国际金融研究院执行副院长刘胜军说: “这样的利率,在当今中国经济现实下显然不可持续,这个利率为什么这么高?一部分是因为没有办法有效地识别借款人的风险,导致逆向选择,随着各家平台技术的提升,这个问题会得到缓解,利率水平一定会出现下降。” 借款利率过高,但是企业的利润中增长水平明显达不到利率水平,这意味很多借款本身就是欺诈行为,坏账风险高。 四,区块链最大的价值在于数字资产管理 区块链的峰会和论坛现在如雨后春笋一样非常多,但很多主题仍然还是在讲概念、讲思想,讲具体的技术和算法、真实应用的,还比较少,一位投资人高速钛媒体记者:讲概念和真实应用的,比例大概是一分实九分虚。 区块链还处于一个知识普及的阶段,目前优秀的区块链底层技术团队全世界也没有几支,VC对区块链创业团队的投资也比较谨慎,一些团队给自己估了很高的值,但是VC不认可。 “我们觉得区块链最大的价值在于数字资产的管理和交易,而不是简单地做一些结合场景的应用,但是资产管理对技术要求很高,目前我们在国内没有看到很优秀的团队。”这位投资人比较一番,认为区块链太早期,于是布局了多家与智能投顾相关的大数据以及数据分析创业团队。 一些区块链创业团队创造出“ICO”的概念,不同于IPO,“ICO”是Initial Coin Offering的简称,把所发行的标的物由证券变成了数字加密货币。ICO最直接的意义是:即便VC不看好,创业团队也可以在基于区块链的众筹平台上发行自己的代币,募集资金。 国外的The Dao就创造了众筹纪录,在15天内众筹超过1亿美金,后来遭到技术攻击,损失了约6000万美元。国内一家区块链创业团队去年通过发行代币众筹了400多万人民币,这些资金基本来自于早期比特币炒家,在2013年比特币价格上涨期间增加的财富。 就像股权众筹项目遭遇信用风险一样,这些ICO项目也有同样的问题:一是没法形成很好的信息披露方式,仅仅靠每年出一份白皮书,恐怕不能让投资者信服;二是风险定价是一个外包型定价,领头方对某一个资产做了定价,这意味着可以在外包基础上给外包方给予杠杆,难以避免利益冲突。 五,平台确定商业模式,进行转型 金融科技企业过去几年发展很快,在非理性狂热的推动下,大家过度关注规模,但这种速度是不可持续的,现在必须转型,平台的盈利能力、商业模式是不是可行,现在都面临了严峻考验。各个平台都在寻找自己的商业模式,一些平台的资金集中度逐渐扩大,朝全能型的方向发展。 从P2P起家的积木盒子,最近成立了母品牌品钛,将积木盒子、读秒、一点基金、企乐汇、智能投顾等子品牌归入旗下,如此一来,品钛的业务范围包括P2P、信贷决策引擎、基金销售、企业征信、智能投顾,估值和竞争力大大高过原来的P2P身份。 特立独行的P2P平台拍拍贷,今年以来实现盈利,为了把沉淀9年的大数据风控系统价值最大化,拍拍贷从去年下半年开始推出“拍分期”,专注线下资产的开发,进入东北、西北、上海周边地区的蓝领消费人群,针对3C产品推出分期信用贷款,对纯线上信用贷款的资产是个补充。 六,征信是第一步,大数据还有更多价值 大数据最直接的价值就是让金融服务的门槛变低。 业界普遍在思考:如何通过大数据的技术帮助Fintech平台提高风险识别和风险定价的能力?除了P2P行业,互联网的征信、互联网股权融资,股权众筹,大数据在这些领域有什么作用?上海市互联网金融协会副秘书长孟添说: “利用大数据进行征信,具有非常大的发展空间,中国和美国不同,美国的三大征信机构比较成熟,中国征信体系条块分割,现在要解决征信问题,除了央行征信体系,现在有越来越多利用互联网技术做征信的企业出现了,这个情况可能跟欧美以后发展很不一样。” 以往,征信由央行来做,因为央行可以汇聚所有银行类金融机构的数据。大数据时代,要把金融机构之外的更多数据汇聚的一起,难点在于:如何把数据放在一起?如何形成一系列指标?如何实时评价企业或个人获得金融服务的能力? 目前在国内,从大数据到商业价值实现之间,存在巨大的鸿沟。首先是技术门槛高,在美国,数据科学人才的供应尚且不满足市场需求,在中国,99%的中国企业没有组建数据科学团队的能力,但数据应用需求在快速增长。 其次是时间周期长,即使组建了数据科学团队,数据科学家基于市场提供的数据分析工具,仍需要花费大量时间进行数据清洗和数据处理等工作,平均数据挖掘项目周期在3-6个月之间。 同时,投入产出比低,数据存储成本高,数据如果不进行合理应用,只能增加成本,大量探索工作并不能保证商业效果。 七,网贷的未来热点在于:消费金融、供应链金融 银行以往贷款给基建项目会比较多,但是对消费者借贷,银行的力度不是很大,现在中国经济向消费转型之后,其实也提供了很多的机会给P2P公司,为更多的投资者带来信贷渠道。 网贷行业未来会更专业化,针对某一种类型的市场进行深耕,比如个人消费信贷,平台专门做这种类型的资产,越做越精。 其次是中国私人财富迅速增长的趋势,P2P网贷的功能会拓展到提供财富管理服务。然后是供应链金融。大型骨干型企业可以从银行贷款,或者直接融资,但是在供应链线上的很多小微企业,融资方式可能没有那么方便,P2P网贷是一个很好的方向。 八,打破刚性兑付 刚性兑付不是仅仅存在于互联网金融,更多是一种社会现象。 在刘胜军看来,中国有很多企业该破产却不破产,成为僵尸企业,甚至房地产,很多人买了房,如果销售商开发商把房价下降,老的房子会涨物业……这一系列的现象都是刚性兑付,处于社会稳定的角度,或者博弈的角度,大家都不愿意让违约发生。 因为中国经济增速放缓,企业风险事件越来越多,互联网金融领域的刚性兑付打破是不可避免的。但是靠一家公司是难以改变的,需要社会各界共同努力才能够解决,刘胜军认为从这几个方向推进: 1:、监管部门对行业进行适度的监管,随着时间的推移,竞争可能会越来越理性化; 2、投资者观念要转变,风险与收益是成正比,如果能拿到10%的回报率,承担和银行存款一样的风险,这是不可能的事情。 3、从互联网金融的企业要分散投资,如果说从技术上把很多投资分散化,不要把鸡蛋放在一个篮子里,无论在P2P平台分散,还是同一个平台内部不同客户借款人之间的分散,对于降低风险是非常有效的,有助于打破刚性兑付。 4、行业自律,金融科技是很新的事物,现在的监管规则相对滞后,行业领先企业需要通过行业自律,打破刚性兑付方面。 九,资本方估值逻辑已变,资产端决定存亡 资本方的估值逻辑已经改变,整个互联网环境都在从线上闭环到线下转变,互联网金融更加如此,李丰认为,资产端几乎决定了今后几年P2P平台的玩法和存亡。 金融科技创业公司的竞争对手无非2种,一是互联网公司,二是是金融机构,在两者之间,需要衡量:现在生意是偏虚拟闭环,还是偏线下的闭环?这将决定企业的生存空间有多少。他说: “以余额宝为首的几个巨大的互联网门户,是最大的理财平台,但最大的资产平台是哪家?可能大家一下回答不出来。原因在于金融当中偏理财和标准化产品这一端,基本上很靠近虚拟经济的闭环,而资产端非常靠近线下和实体经济本身,所以大公司没有办法垄断。” 为了寻求更好的资产,宜信成立了新金融产业投资基金,含30亿元人民币和5亿美元,主要投资于国内外金融产业与互联网、大数据、云计算、社交网络等领域相结合的Fintech领域,最近的动作是:跟投了国外区块链创业公司Circle的D轮融资。 这也是方法之一,可以更多的把间接融资变成直接融资,在这个过程当中,平台会涉及到更多面向一级和二级市场的途径。在李丰看来,这就是信贷周期中的投资顺序,继新型资产和金融技术服务类公司后,新型的财富管理方式将会陆续出现。 原文发布时间为:2016-09-19 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 什么是数据科学? 你已经下定决心要做一名数据科学家了,很好你已经开始了。但是现在你有了另外一种选择:你想做哪一种数据额科学家呢?因为(认识到这个很重要)虽然数据科学被承认是一种职业已经有很多年了,但是有关于它到底是什么还没有一个大家都认可的定义。 在现实生活,“数据科学家”这个词可以指代非常广泛的工种,因此它存在很多种形式,考虑到工业界以及商业界各种需求的不同,还有问题中目标与输出角色的不同。因此,在某些方面拥有技能的话比其他要更好一些,这就是为什么通向数据科学的路径是不相同的,可以通过多种领域如统计、计算机科学与其他科学学科来实现。 目的是决定数据科学形式类别的最大因素,这也与相应的A类以及B类相关联。广义上来说,分类可以总结如下: 面向人类的数据科学(A类),举例:分析支持以证据为基础的决策 面向软件的数据科学(B类),举例:智能推荐系统,如Netflix和Spotify 当这个领域越来越成熟之后,我们可以见到这些定义会愈加完善,在这里我们也要介绍我们第一个专家:Yanir Seroussi,Yanir目前是Car Next Door的首席数据科学家。 探讨职位头衔 在我们深入研究之前,值得花一点时间来反思“数据科学”中的“科学”,因为在某种意义上,所有的科学家都是数据科学家,因为他们都是与各种各样的数据进行打交道。但要考虑到通常被认为是数据科学的这个行业,究竟是什么使它成为一门科学?这个问题很好!答案应该是:“科学方法”。考虑到科学的多学科性,科学方法是把这些领域结合在一起。 然而,业界中职位名称貌似越来越宽松了,并不是所有的数据科学家都是真正的科学家。可以这样问你自己:你能证明自己是一个科学家即便你的工作并不包含真正的科学呢?个人来说,我不认为“分析师”不能作为一个选项 ,或者其他的最合适的也能作为选项。但是这可能只是我个人意见,也许我最好称自己为招聘科学家。 通过讨论的方式我们将继续探索,哪些领域的专业知识你还需要掌握(如果你还没有的话)。 解决问题 如果这个不是你清单中的首位的话,马上去修改。所有科学核心都是解决问题:一个伟大的数据科学家也是一个伟大的问题解决者;就是这么简单。需要更进一步的证明吗,基本我在这个项目中碰到的每一个人(不管其背景和目前工作环境如何)都提到数据科学中最重要的因素就是解决问题。 很明显,你需要有工具去解决问题,但是它们只是:工具。在这种情况下,即便是统计/机器学习技术也可以认为是你解决问题的工具。新的技术出现了,科技进步了。唯一不变的就是解决问题。 在某种程度上,你解决问题的能力是由天赋决定的,但是与此同时有且仅有一个方式来进行提高:那就是练习、练习、练习。在后面我们会回顾这部分内容,但是现在你只需要记住:你只能通过尝试来掌握某件事情。 统计/机器学习 看完上面的内容,似乎我轻视了统计和机器学习。不过在这里我们并不是讨论一个强力的工具;它们是非常复杂的(而且在某种程度上是非常深奥的领域),如果你没有专业的知识,你也不会很快地解决数据科学问题。 进一步对这些词进行解释说明,机器学习可以被认为是从人工智能/计算科学与统计学中发展起来的多学科领域。它通常被认为是人工智能的一个子领域,这是正确的,但是很重要的是要意识到没有统计学的话就没有机器学习(机器学习非常依赖统计算法来工作)。很长一段时间依赖统计学家都被机器学习所轻视,但是在这两个领域的合作才造就了最近的发展(参见统计学习理论),顺便提下高维统计学习只有在统计学家与机器学习结果合作时才会有良好的结果。 计算 1.编程 对于我们来说只需要简单的接触程序就行,因为它应该是很直观的:但是对数据科学家来说编程是必须要会的。设想下如果你不会编程的话,如何才能通过编写一段独特的算法来实现你的理论?又或者建立一个统计模型? 2.分布式计算 并不是所有事情都需要超级大的数据组,但是考虑到现代世界的情况,建议在工作中都加上大数据。简而言之:单一计算机中的主要内存并不能实现大数据处理,如果你想同时在数百台虚拟机中训练模型的话,你需要能够使用分布计算与并行算法。 3.软件工程 对于A类数据科学而言,让我明确一点:工程是一门独立的学科。因此如果这是你想成为的数据科学家类型,你其实不需要成为一个工程师。然而,如果你想把机器学习算法转化到应用中(即B类),那么你将需要一个强大的软件工程基础。 4.手动转换数据 数据清理/准备是数据科学的重要内在组成部分。这将耗费你大多数时间。倘若你没有成功地对数据集进行降噪(例如,错误赋值,非标准化分类等),将会对建模的准确性产生影响,最终导致产生错误的结论。因此,如果你尚未做好处理数据的准备,这将使你先前的知识积累显得无关重要。 有一点是非常重要的且值得注意的,即在商业化组织中数据质量一直以来成为饱受争议的话题,在数据储存方面,许多业务又涉及到复杂的基础事务需要处理。所以,如果你尚未准备好融入这个环境中,想要处理纯粹的数据集,商业数据科学可能不是最适合你的选择。 5.工具与技术 直至目前,你应当意识到,成为一名具备解决问题的能力的数据科学家相比于其他一切条件来讲是重中之重:因为技术将不断发生变化,能够在相对较短的时间内得到掌握。但是,我们不能对其他影响因素置之不理,因而,能够认清楚如今应用最广泛的工具对于成为一名数据科学家是有用的。 让我们先从编程语言谈起,R与Python是两种最常用的编程语言,因而,如果能够选择的话,希望你选用其中一种语言用于实验研究。 尤其是在A类数据科学工作领域,具备能够直观地观察数据的能力将会对与非技术型商业股东交流沟通产生重大影响。你可能具有最优的模型和最深刻的见解,但是如果不能有效地呈现/解释这些研究成果,那又将有什么用呢?事实上,你运用什么工具实现数据直观可视化并不重要,可以是通过使用R或Tableau(当时最为流行的编程语言),但是,说实话,工具是不太重要的。 最后,不论我们所讨论的是关系型数据库,还是运用大数据技术获得的SQL衍生数据库,由于SQL是当时产业界用于数据库中最为广泛的编程语言,大多数公司都非常看重SQL这种编程语言。SQL对于手动转换数据尤为重要,至少在处理更大规模的数据库时。总之,SQL真的值得你花费一定的时间来好好研究应用。 6.交流/商业头脑 在商业数据科学领域工作,具备交流沟通能力/商业头脑是不容忽视的。除非你将要从事非常具体的工作,可能是纯研究类型的工作(尽管我们要面对现实,在产业界并没有很多这种类型的工作),绝大多数数据科学领域的工作都涉及到业界交流互动,通常是与非学者类型的人打交道。 具备将商业化问题和催生这些问题的环境概念化是极为重要的。将统计学方面的观点转化为可以想普通大众推荐的行动或启发性观点也是重要的,特别是对于A类型数据科学领域的工作来讲。我曾与Yanir就该话题交谈过,他的观点如下: “我发现一种奇怪的现象,当一些技术型人才开始使用行话与人交流时,他们并不留意他们的交谈者——那些非技术型人才,的目光早已落到了别处。在交谈过程中,能够设身处地地为他人着想是重要的。” 摇滚明星 乍看这样一个标题,你可能会困惑不解:事实上,我用这一标题暗含讽刺意味。当然,数据科学家可不是摇滚明星,忍者,独角兽或其他任何一种神秘生物。如果你计划视自己为上述任何一种生物,那你可能该对着镜子好好大量自己一番。但是,讲到这里,我离题了。我想要表达的观点是,有一些数据科学家,他们具备顶尖的专业水平,也可能专业水平更为高端。在别人眼中,可谓稀有物种,尤为宝贵。如果你有此般天赋或愿望成为其中一员,那简直是太棒了。但是,如果你不具备这种才能或愿望,请记得:你可能在数据科学的某些领域做的术业有专攻,而且通常,好的团队是由精通于不同专业领域的数据科学家组成的。决定自己的研究重点在哪一领域,这个问题有回到我们之前讲的个人兴趣和能力这个话题上,我们将在下一章对该话题作继续讨论。 ◆ ◆ ◆ 自我剖析 现在我们正在取得进步!成功地消化了第一章的内容之后,你现在要做好准备开始制定个人目标。但是,我们首先要回顾一下——不妨来杯咖啡,寻一隅安静之所,深思下面的问题: 1.你为什么想要成为一名数据科学家? 2.对哪一类型的数据科学感兴趣? 3.你已经具备了哪些天赋或相关技能? 为什么认真思考这些问题是重要的?简而言之:数据科学是一个专业的研究领域,因而,除非你已经掌握了我们在第一章中提到的知识与技能,否则从事该领域的研究并不是一种轻松的选择。讲到这里,有一点对合理解决前两个问题尤为重要:你需要为从事数据科学领域的研究找到合理的理由,否则,当遇到困难时,很容易半途而废。 为了详细阐释上面的观点,我们来听听Dylan Hogg的见地。Dylan之前是一名软件工程师,现在是数据科学研究协会的领导者,数据科学研究会为运用机器学习(NLP)为雇主和相关候选人员建立联系搭建了一个平台。Dylan是如何从软件工程师成功地转型为数据科学家的(他仍然处于转型期),下面我们将讨论转型过程中应当具备的条件,他讲到: “不论学历高低,经历丰富与否,有一些内在的东西尤为重要,那就是一个人的求知欲、决心和毅力。你会遇到很多困难:也许是算法方面出错,也许是遇到技术瓶颈。不论遇到什么样的困难,你都能够找到最优的方法来研究机器学习算法或软件工程,但是,倘若你的信心不够坚定,你将会放弃或无法克服遇到的困难。” 这下你会懂了:在学习过程中,你不仅仅会遇到困难;在工作生活中,你会接二连三地遇到难题,因而,你最好能够保证有合理的理由来激励自己,而不仅仅因为你觉得拥有“科学家”这一头衔有多酷。 但是,我们应当如何应对第三个问题?为什么拥有相关技能是重要的?对,一个人的起点会对选择最适合自己的数据科学类型及你应当从自己感兴趣的领域学到的知识产生影响?为了能够恰当地回答这个问题,有必要探寻通往数据科学领域的典型途径,我们应当首先从更为广阔的科学领域开始。 注:在许多定量学科中有许多人具备向数据科学转型的素质。在这里我就不一一列举了,但是,需要强调的重点是:如果你花费时间来真正理解每种类型数据科学之间存在的细微差异,不论你的知识背景如何,你都将会意识到自己所具备的相关技能的重要性。 其他科学学科 这不是通往数据科学领域最平凡的道路;我们接下来将要讨论统计学与计算机科学在数据科学研究中的重要性。但是,许多领域的科学家都具有娴熟的相关技能(特别是物理学领域),许多人在这一方面已经跳过了。 为了对此进行解释,请允许我介绍Will Hanninger,澳洲联邦银行数据科学家。之前,Will是欧洲核子研究中心的粒子物理学家,发现了希格斯玻色子,下面是他的语录: “在物理学界,你能够自然而然地学习到所需要的数据科学领域的知识:编程、操作数据,获取原始数据并根据实用性对数据进行转换。你能够学习到统计学知识,重要的是:你将学到解决问题的能力。这些是作为一名数据科学家应当具备的基本技能。” 因此,技能组合具有高度可转换性,最重要的是获取解决问题的能力。工具与技术两者之间将会产生差异,例如,尽管机器学习是数据科学的同义词,但是,就更为宽泛的科学而言,这种同义关系是不常见的。在上述讨论中,我们一直谈及的是高智商人才,他们具有在短时间内学会使用工具与技术的能力。 下面我们以Sean Farrell的科研经历为例。Sean所学专业是天体物理学,之后进入澳大利亚商业数据科学研究领域,在研究过程,他就“为什么科学家在数据科学领域的损失反而是收获”这一题目写了一篇著名的博文。下面这段话尤为中肯: “至今为止,尚未发现一种能够培养出一位数据科学家的正式训练方法。多数数据科学家都来自统计学或计算机科学领域。然而,尽管其他研究领域也能够培养上述列举的技能,但是不能涵盖所有的相关技能。统计学家非常擅长数学和统计,通常在编程这一块儿的技能稍显欠缺。计算机科学家非常擅长编程,但是,在理解统计学知识方面存在难度。两个领域的科学家都具备高水平的(尽管不同的)数据分析技能,但是不擅长创新性地解决问题,这种技能也是难以教会的。” 为了避免误解,请记得我们今天讨论的上下文语境。Sean的一席话并不意味着来自统计学或计算机科学领域的所有数据科学家都缺乏创新性解决问题的能力;他的观点是:相比统计学和计算机科学,广泛意义上的科学对解决问题的技能要求很高。 统计学 谈及到科学,应当仔细研究统计学。近来,许多统计学中的分支学科被重新冠以数据科学之名,因此,在某种程度上,我们好像正在谈论语义学知识。但是,正如我先前谈到的,我认为科学方法应当被当作一门科学:难道提出假设,设计可行的实验方案等研究步骤不能称得上“方法论”吗?倘若不是的话,也许像“统计学家”或“模型分析师”这样的头衔更为贴切。 暂且将这一问题放一放,倘若你是产业界的一名统计员或者刚刚从统计学专业毕业,那么你可能已经拥有成为一名数据科学家应当具备的知识与素养。相关知识素养的形成主要依靠以下因素: 首先,你在机器学习技能方面有何经验?正如我们在第一章提到的,统计建模与机器学习是相互关联的,但是,在应用到大型数据集中,后者具有更多的优势。当机器学习在产业界的应用越来越受到关注,实际上,机器学习已经成为各种类型的数据科学。 其次,我们再重复一遍,你对数据科学的哪一领域感兴趣?很明显,拥有统计学背景更加有利于你胜任A类型职位,因而,如果你将目标设定为B类型职位,未来还需要学习很多知识。 最后,你是否拥有处理数据的实际经验?正如我们在第一章中提到的,手动转换数据是商业数据科学的重要组成部分,而来自统计学领域的科学家手动转换数据的能力相对薄弱。 计算机科学/软件工程 如果你在人工智能或计算机科学领域的学习已经达到前沿水平,你极有可能已经能够胜任B类型的数据科学研究工作。但是,我们这里将要考虑一条数据科学家常走的科研道路:一名经验丰富的软件工程师想要转型进入数据科学领域。 一名软件工程师在机器学习领域可能富有经验,也可能经验甚少。但是,B类型数据科学要求在软件工程原则方面拥有扎实的基础,因而,不论怎样,拥有软件工程方面的学术背景将使你更适合该领域的研究。我曾经与澳洲联邦银行高级数据科学家(先前是一名软件工程师)就此问题交流过,以下是他的观点: “大量数据科学工作其实都涉及到软件工程方面的知识,不仅仅包括设计健全的系统,而且包括简单地编写软件。你可以通过自动化完成众多任务,如果想要开展实验,你需要编写代码,如果你能够快速编码,将对实验进展产生重大影响。在攻读博士学位过程中,我每天要做成千上万项实验,如此浩大的工程是不可能通过人工完成的。拥有软件工程专业的学术背景意味着我能够快速完成设定的实验任务,然而,许多其他学术背景的学生需要费力处理基本的软件问题:他们真的非常擅长数学,但是要切实证明他们的观点还需要耗费大量时间。” Dylan对于该问题补充道: “如果你想要在生产环境中高效运用机器学习算法,良好的软件工程实践能力是非常宝贵的。这其中涉及到各种各样的软件工程知识——如可维护的代码,可供分享的代码库,以便于更多的人能够投入到数据科学领域的研究中,如在计算机中记录信息,排除生产过程中的故障,算法扩展,你应当认识到:一旦这些知识得到加强,你便能够通过这样的方式构建数据科学领域的知识框架。因此,如果你正在寻找一份能够有效利用所掌握的知识的工作,这将使得软件工程学术背景变得更为重要。” 我认为,上述两名数据科学家已经对如何成功实现转型这一问题做出了详细阐释,下面由我来总结如下:如果你是一名软件工程师,而且很喜欢数学,这将有助于你成为一名(B类型)数据科学家,前提是你已经做好准备在工作中掌握统计学/机器学习领域的知识。 数学 很容易得出这样一个结论:数学知识为数据科学的所有研究领域打下坚实的基础。因而,期望许多数学家从事数据科学家的研究工作是合理的。但是,相对来讲,少之又少的数学家成功转型成为数据科学家,这一现象引发了我浓厚的兴趣。 针对这一现象,有一种解释:与其他研究领域相比,数学(纯理论数学与应用数学)领域有相对较少的毕业生,但是,这种解释未免显得牵强。为了深究导致这种现象的原因,我曾经同Building IQ(一家新成立的运用先进的算法优化商业建筑中能源应用的公司)首席数据科学家Boris Sackovic交谈过。Boris拥有电气工程与应用数学双重学术背景,与当时许多数学家合作过,以下是他对该现象的见解: “许多数学家为理论层面的问题,美丽的方程着迷,能够洞察众多数学原理所蕴含的深层意义,当时商业数据科学研究讲求实证性,涉及到的多种多样的知识与能力。一些数学家喜欢这种实证性,而一些则表现出讨厌的态度。真实的情况更为复杂,你不能兼顾所有的情况,因而得具备能够灵活处理所遇到难题的能力。而这是商业数据科学的重点所在:找到更快更好、切实可行的挣钱方案。对于那些具有浓厚数学背景或理论背景的科学家而言,要理解商业数据科学领域的运行模式可能存在不少难题。我曾经遇到过很多数学专业的博士,他们在由学术界向商业数据科学领域过度期间可是吃了不少苦头。” 需要注意的是,Boris在这里谈及的是纯理论数学家,当然,他也补充说,在自己的职业生涯中也曾与许多优秀的应用数学家打过交道。这样一来上面的讨论便讲得通了,因为纯理论数学家可能会吸引那些热爱理论的人,而不会吸引那些热爱解决实际问题的人。理论研究工作并未涉及到太多数据处理问题,但是,我们都知道数据对于数据科学领域的研究极为重要。 就工作类型匹配度问题,多数数学家可能更适合学习A类型数据科学领域的工具和理论。但是,也有一些学习计算机科学的(实质上,理论计算机科学属于数学的一个分支)数学家,因此,具备这种学术背景的数学家可能更适合B类型数据科学领域的工作。 从上述讨论结果中可以得出一条非常重要的观点,即要理解商业数据科学真正要求数据科学家具备哪些知识和技能。倘若你能够真正清楚地认识到面临的挑战,所需要做的便是为了自己的目标努力前行。但是,倘若相比实际应用,你更热衷于理论研究,你可能要三思而后行。 一块空白的画布 如果你刚刚起步,也许你还是一名学生,喜欢数学、科学与计算,喜欢数据科学,这对你来讲不失为一则好消息:你可以不受先前学术背景的限制,选择属于自己的科研道路。现在有许多与数据科学相关的专业课程,涵盖计算机科学和数学/统计学等。当然你不可能一夜之间成为一名数据科学家,现阶段你需要树立不断学习的理念,利用各种数据科学领域的学习资源, 累积数据处理方面的实际经验,具备与人交流沟通的能力,积极迎接商业数据科学领域未来的挑战! 原文发布时间为:2016-09-19 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 电影魔术师 美国好莱坞影片《侏罗纪公园》上映后引起了极大的轰动。观众莫不被银幕上栩栩如生的巨大恐龙所震慑明知其假却大有乱真的感觉。不久后《阿甘正传》再次成为万众瞩目的大片虚拟的主人公阿甘居然可以与死去的肯尼迪总统握手交谈电影魔术真令人大开眼界而“魔术师”就是座落在斯坦福大学附近的硅图像SGI公司。 若干年前著名导演乔治·卢卡斯制作的大片《星球大战》虽然轰动一时但特技制作却让这位电影大师伤透了脑筋。另一导演卡梅伦比他幸运得多当制作影片《深渊》需要一只能哭会笑的水怪时他找到硅图像公司并发现了电脑三维图像的巨大魅力。从此SGI超级电脑制作的电影特技一发而不可收从斯皮尔伯格执导的《侏罗纪公园》直到斯瓦辛格主演的《终结者Ⅱ》无论是巨型恐龙还是会变形的液态金属机器人都尽情展示了电脑图像的迷人风彩把世界电影特技史带到了一个崭新的时代。硅图像公司的员工经常身着T恤骄傲地在硅谷行走T恤前面写着“我制造了恐龙”。 当然导演这一切的既不是卢卡斯、卡梅伦也不是斯皮尔伯格而是吉姆·克拉克J.Clark没有他天才设计出特殊电脑芯片和动画软件没有他把这些技术推进到一个新的高度好莱坞卖座的大片将黯然失色。克拉克不仅是硅图像的创始人和董事长而且是该公司最主要的技术大师。 吉姆·克拉克原是斯坦福大学的教授但他的传奇并非在大学象牙塔里书写而是在一次又一次的创业中完成。他出生于德州乡村小镇家境贫寒从小失去了母亲的呵护。中学辍学参军在海军艰苦的训练中发现了神奇的电子学靠自学获取了中学同等学力。服完兵役后克拉克考进犹他大学电脑科学系师从著名教授伊凡斯学习电脑制图。1978年他怀揣博士证书受聘于斯坦福大学四年后带着自己的研制的图形工作站电脑和三维绘图软件也带着一批最优秀的硕士生“下海”创办了硅图像公司。到克拉克离开公司二次创业之前硅图像公司已经快速成长为数十亿美元资产、有业界最负盛名的图形工作站的图形软件制造商。 另一家专业从事“电影魔术”的公司叫皮克萨Pixar说来也怪皮克萨公司的领导人就是苹果公司原来的董事长乔布斯。 1985年被迫离开自己亲手培育的苹果园后乔布斯郁郁寡欢无所事事地游荡在斯坦福大学校园偶尔也旁听几节物理课。偶然的机会在图书馆邂逅了保罗·伯格教授。伯格是诺贝尔奖获得者当时正在进行生物基因修补的研究。乔布斯与伯格谈得非常投机教授向他详细解释了他们如何做各种操作繁琐的实验每做一次都要在潮湿的实验室里工作两个星期才有结果。这次谈话使乔布斯获得了再次创业的灵感他要发明“下一个”伟大的计算机以支持科学实验工作。 毗邻着斯坦福大学乔布斯挂出了“下一个”NeXT公司的牌子。他心中的NeXT电脑实际是一种高档图形工作站具有强大的绘图和动画制作能力。40名员工夜以继日地苦干了三年直到1988年新产品才正式上市基本上实现了乔布斯要求的目标。NeXT工作站实现了硬件、软件和图形界面完美的组合。然而乔布斯全神贯注地埋头研究却忽略了一个可能使他的努力付诸东流的市场趋势——微软视窗已经全面走向成熟。NeXT的攻击对手原本指向“麦金塔’此刻却发现它根本不是视窗的对手顿时陷入了财务危机。 乔布斯发现自己犯了错误立刻幡然醒悟。他下令关闭全新的自动化工厂从制造电脑硬件转向全力开发电脑软件NeXT变成了一家软件公司。最让人感到惊异的是乔布斯还斥资5500万美元从《星球大战》制作人卢卡斯手中买下了从事专业动画片制作的皮克萨公司成功打进影视圈。1995年第一部全电脑制作的大型动画影片在皮克萨制作完成片名叫做ToyStory中文译为《玩具总动员》。 《玩具总动员》实际上是乔布斯和皮克萨公司百余名员工的一次总动员。他们在天才导演、38岁的拉赛特指挥下把硅谷高科技与好莱坞艺术创作联姻整整耗费了4年光阴紧张制作前期投入高达3000万美元。在这个效果空前的电脑动画片里有30个玩具人物出场由1500个全电脑制作的镜头构成播放时间长达77分钟使用了价格达数百万美元的高级电脑支持制作过程用了80万个电脑工作小时。无论是人物、街道、风景、楼房还是黄昏的落日、倾盆的暴雨三维动态的图像都显得那么逼真。《玩具总动员》也为乔布斯和皮克萨公司带来高达1亿7千万美元票房收入。当年11月挟电影轰动效应余威皮克萨股票上市一天之内牛市冲天乔布斯的身价即刻增加到11亿美元。 1996年岁末NeXT公司被苹果公司以4亿美元收购乔布斯终于回归了他亲自创建的“苹果”。1997年7月他再次执掌苹果公司大权以不断创新的技术继续推出下一个“伟大的产品” 原文发布时间为2016-09-20 本文来自云栖社区合作伙伴“大数据文摘”了解相关信息可以关注“BigDataDigest”微信公众号
◆ ◆ ◆ 引言 纳森尼尔·康佛特花了10年研究音乐,10年研究科学,又花了20年研究历史。“我最想做的就是把这些内容整合在一起。”康佛特说道。“如果可能的话,我会把科学当作曲子一样谱写出来。” 作为约翰·霍普金斯大学医学史学院教授,康佛特将生命奉献给了他理想中的科学史学家这一角色:让科学变得通俗易懂,赋予科学以时代及社会意义。 在Nautilus的访谈中,康佛特谈到了科学史的意义、诺贝尔奖、女性科学家地位及时下热门的基因编辑等相关话题。 ◆ ◆ ◆ 科学史学家扮演着什么样的角色? 我们已经有了记者和科学家,为什么还需要历史学家呢?记者很棒,好的记者在追踪新闻事件和人物事迹上无人可及,然而记者的任务只是追踪、记录和报道,并非解读。科学家则总是在解释,他们对自己的研究及其意义抱有特定的观点,从定义上来说是自我本位的。这虽然无可指摘,但从其他角度来看待他们的研究也是可以的。 我可以告诉你我都做些什么,然而在别人眼中我做的可能完全是另一回事。我在努力让科学变得更“接地气”,但有人可能就会说我在拉低科学的地位。所以可能会有多样的解读。我希望的是能让更广泛的人群关注科学,让科学变得通俗易懂,将科学置于更广阔的社会语境中,赋予科学以时代和社会意义。这些既不是记者的工作,也不是科学家的工作。 ◆ ◆ ◆ 科学史中常被遗漏的是什么? 科学人性的一面往往会被科学史学家所忽略。 我试图捕捉科学家的行为——几乎就像我作为科学家时捕捉动物行为一样,但也关注科学家们人性的一面,比如人格,互动,友谊与竞争,各种八卦等等。因为在我看来正是这些造就了科学家们展开研究的方式。 实验室似乎是与世隔绝、自成一派的象牙塔,然而即使置身实验室中,你所有的经历、人际关系,甚至当天的心情都是无法割舍的。所有这些因素都会影响到你的研究课题。 科学家也是人。无论研究什么课题,对什么感兴趣,用什么特定工具来展开调查,都是个人经历所决定的。举例来说,可能在你小时候收到了一套儿童化学实验用具作为生日礼物,你一生对化学的热爱也就此埋下了种子。 调皮的爱因斯坦 个人经历还会影响一个人解读数据的方式。人们总是认为对数据的正确解读是唯一的。有时对某一特定数据的解读确实只有唯一正确的答案,但如果是更宽泛的课题,例如生命起源,研究就一定会被个体经验所影响。在搞科学之前,你首先必须是个活生生的人。机器人是没法完全独立从事科研的。 ◆ ◆ ◆ 科学史诺贝尔奖对科学有益处吗? 我曾经在诺贝尔档案馆工作过,也和诺奖委员会的人谈过,所以对相关内情知道的会比其他人都多得多。在卡罗林斯卡学院(诺贝尔委员会所在地——译者注),大家说起诺奖综合症都觉得是一种病。诺贝尔奖的地位被捧得太高了,而这或许正是阿尔弗雷德·诺贝尔想要达到的效果。他想塑造一个伟大的传奇,让他的名字变得人尽皆知,想让以他名字命名的奖变成每个科学家为之奋斗的终极目标。诺奖为科学树立了崇高的公众形象,让科学成为众人瞩目的焦点。从这些角度说,对科学的确大有裨益。 然而我认为,诺奖也有一些负面效应。它以微妙的方式让科学变得政治化。诚然,诺贝尔奖不是让科学政治化的唯一原因,但确实是一个因素,而且是对大众来说最明显的一个因素。人们为了诺奖四处游说,大张旗鼓,连亲朋好友都不放过。 希特勒和斯大林都曾被提名诺贝尔和平奖 我知道曾经有人发动好友来提名自己竞争诺奖。甚至有人冒充他人来填写表格,寄给诺奖委员会来提名自己。更夸张的是,有一次我甚至在档案库里见过一个奖杯,就是最常见的那种到处都可以买到的普通奖杯,上面刻着字:“诺贝尔和平奖”,还有那个人自己的名字。他把这个奖杯寄给诺奖委员会,要求委员会用他准备好的回邮信封把奖杯给他寄回去,好“告诉别人我得了诺贝尔奖”。诺奖的声望被过度夸大了。它有时会让人陷入疯狂,这对科学可没有好处。 ◆ ◆ ◆ 诺贝尔奖的重要性是否正在下滑? 我认为诺贝尔奖的含金量多多少少有些褪色,原因有几点。其一是因为现在的科研都是协同合作的,许多了不起的发现都是众人合作的成果,就像一幅拼图一样。20世纪那种万里挑一的科学巨匠越来越少见了。 我现在脑子不太灵光了,但是我曾经能够一口气说出40年代到80年代每年生理学奖或医学奖和化学奖的获奖人名,现在可越来越难了。随着参与科学研究的人越来越多,加上各国对科研投入的资金也越来越丰厚,还有其他很多科学大奖陆续出现,诺贝尔奖的影响力已经不如从前了。 ◆ ◆ ◆ 女性在科学领域中的角色是如何变化的? 如果纵观20世纪和21世纪前半段,女性科学家的形象和名誉都有了翻天覆地的变化。女性科学家已经不是什么稀罕事了。 实验室里的居里夫人 以前你会听到实验室里有人说:“小妞,你在这儿干什么呢?快离开实验室,煮你的咖啡去吧。”现在这样的事已经越来越少了。如果现在还有人敢这么说话,多半会被起诉性别歧视然后丢掉饭碗吧。 从70到80年代女权运动开始,女性在科学领域的地位就发生了变化。今天,在女性管理的实验室中很容易见到女性,尤其是年轻的女性科学家的身影。我认为改变是巨大的,情况正在往越来越好的方向发展。 ◆ ◆ ◆ 女科学家在生物学上似乎比在物理学上更容易成功? 物理学确实是很男性化的学科。我在约翰·霍普金斯大学医学院的时候就听说过这样的研究结果。我是学生物和医学出身的,物理的话……我不太清楚。你需要问问物理学家。 获得2015年诺贝尔生理学或医学奖的中国女科学家屠呦呦 不过在基础科学领域中,生物学方面真的有积极鼓励女性科学家参与其中。 你如何看待那些天价资产的基因编辑公司,比如Editas? 在生物技术领域里有句老话,叫买进谣言,卖出商品。别误会,我的意思是生物技术有能力行大善,也有同样的能力做大恶。当我看到科学和医学中的炒作时,我就忍不住想说“扯淡”。现阶段基因编辑被炒作得太过了。你会听到有人鼓吹“哦,我们可以设计出完美的婴儿来”或者“我们能创造出一支超级军队”之类的。这些都是不靠谱的。 CRISPR革命是一场静悄悄的革命。它已经发生,并且还将持续下去。CRISPR几乎已经渗透到了我所知的每一个基础实验生物科学和生物医学实验室中。每个人都在搞这个,而且他们正在不断发现新的方法来应用CRISPR。正像80年代的聚合酶链反应,这不仅是一种技术,而是一系列技术,而且有各种应用。它改变了人们的日常科学工作,将人们渐渐引向更深层次的理解。 这不是一夜之间就会改变世界的大爆炸,而是知识与技术的逐步提升,最终将真正改变我们的生活方式。 ◆ ◆ ◆ 你给科学媒体打几分? 整体来看,C-吧。有许多很不错的A-级别的科学作家,我总是尽可能和他们接触。当我看到一个只能打D-的科学故事,我就会在Twitter上晒出来吐槽。这种蹩脚的作品真的太搞笑了。不过我想强调的是真的有一部分很优秀的科学作者存在,甚至可以说是有史以来最好的一些。但糟糕的作者也不在少数就是了。 ◆ ◆ ◆ 你是如何决定成为一名科学史学家的? 我的大学本科专业是音乐,然后在学习音乐理论和音乐学等科目时很快发现这些人和我大脑思维不太一样,我跟他们不是同一类人。所以我得找点别的事情做。我去咨询了加州大学伯克利分校的就业指导顾问,他说基本上我这种情况只剩下英文和哲学两个专业可选了。我休学了一学期,然后在某次和女友的电话中,我突然意识到我想研究海洋哺乳动物。当时我们的谈话和海洋哺乳动物毫无关系,就是脑子里灵光乍现。 康佛特与爱犬 我想到了一个办法。我住的地方旁边有个海洋世界,他们有个海豚研究项目,我在那儿实习了四个月,觉得超级开心,以至于决定重新回到大学学习海洋生物学专业。这就意味着我需要重新来过,从医学预科的课程开始学习——无机化学、物理学导论等等。我真的非常热爱海洋生物学。然后我决定主攻动物行为的生理学基础,因此就去康奈尔大学学习了神经生物学和动物行为学。我去南美研究了电鱼,但是又一次发现那些在这一领域出类拔萃的人和我不是一类人。所以我又改了主意。最后,我终于发现我其实真正擅长的是写作,长久以来我只是想找到一个写作对象,而我最想写的其实正是科学。 原文发布时间为:2016-09-21 本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号
用电脑的计算器的高级模式。
或者直接在百度上搜索“进制转换“ 居然是表白的二进制
-------------------------
那要看是几进制转成二进制了。