Cutterman - 最好用的切图工具

软件描述Cutterman是一款运行在photoshop中的插件,能够自动将你需要的图层进行输出, 以替代传统的手工 “导出web所用格式"以及使用切片工具进行挨个切图的繁琐流程。 它支持各种各样的图片尺寸、格式、形态输出,方便你在pc、ios、Android等端上使用。它不需要你记住一堆的语法、规则,纯点击操作,方便、快捷,易于上手。下载地址Cutterman更详细的介绍和下载使用方法安装后重启PS窗口->扩展功能->Cutterman (勾选)点击需要导出的图层和选择路径,直接导出对应格式(.PNG24 .JPEG .GIF )切片PS-点击要导出使用切片的场景。例如web,选择导出的格式

April 9, 2019 · 1 min · jiezi

SCSS 环境配置

sass 和 scss 是什么scss的历史2007年 发行2016年 完全成熟sass是什么sass就是把所有分号冒号都去掉的css(哈哈哈)【一本正经】sass的官方解释器是开源的并且用Ruby语言写成的 但是也有用PHP、C语言、Java等实现的版本(C语言版本叫做llibSass,Java语言版本叫做JSass)SassScript提供以下功能:变量、嵌套、混入(Mixin)、选择器继承等。//就像这样… (缩进 格式必须这样写)body color red div color blue 然后呢……大家觉得不好使(最主要是前端工程狮看不懂) 就特别不开心 所以就又把分号冒号都加上了……再然后 scss就出生了scss是什么在sass的基础上把分号冒号都加回来其实就是css加强版…body{ color:red;}p{ color blue}环境配置安装node必须安装node(自己百度吧)node安装完成后 会自带一个 npm yarn 装不装都行 npm如果处理问题就装个yarn查看安装是否成功的方式:1、git bash里看2、cmd 的快捷键:键盘上的小旗键 加 R//这两个命令都一样:/* node -v 输入后安回车显示版本npm -v 输入后安回车显示版本yarn -v 输入后安回车显示版本配置淘宝的源需要配置淘宝的源 http://npm.taobao.org/ 千万不要装 cnpm如果连接有问题 就百度npm淘宝 第一篇文章就可以看到不会的可以点下面这个链接https://segmentfault.com/a/11…安装 http-server有了淘宝源才能安装安装它用来查看当前的html/* 命令行输入: */npm install -g http-server圈出的这两个用谁都行获取预览链接圈出的为预览链接 放入浏览器就能浏览啦它要一直运行 千万不要断 需要写别的命令 就另开一个窗口ctrl + c 中断运行工具安装另开一个命令窗口输入以下代码//第一步npm init -y//第二步npm i -D parcel//parcel 是代替 webpack 不需要任何配置就能使用 webpack 的工具

April 9, 2019 · 1 min · jiezi

多种云服务器安全协同运维改变

2019年的到来,互联网越来越多的企业上云,让公司的业务更加灵活多变,可扩展可管理,让企业能够直观的运维自己的平台,不在是单一的管理的应用,不在是单独服务器的使用和运维. 根据互联网统计报告,到2020年将有85%的企业全部云端协同工作,一些企业的需求将是未来混合云,私有云,云平台等多种工作模式,这些管理云服务器环境,需要一个集成化的服务平台,能够帮助企业把多种模式,集中化管理.首先安全是第一位,混合场景下,充分利用服务器的资源,更大化的平衡功能实现,真正的云安全涉及多个层次和环节. 推荐一款平台化运维平台,能够完美的解决集权化管理云服务器,帮助企业在各种环境下,保持云端可见性和持久工作. 传统的linux运维模式已经过时了,采用新的模式平台化,能够解决,多厂商,多环境,多种服务器的跨平台可视化,减少运维难度和负担,打造出一个协同联动的云安全环境. 集群化SAAS化平台,旗鱼云梯,www.marlinos.com

April 8, 2019 · 1 min · jiezi

我的前端规范系列-前端专属的目录结构[解决项目中的钉子户]

为什么需要前端专属的项目结构这里说到目录结构,想必不少程序员会想到按职能分目录吧!以下所提的目录结构为单页面目录结构以下面这种为例[按职能划分]├──src│ ├──view //页面│ ├──utils //JS工具库│ ├──api //api接口│ ├──style //style│ ├──config //配置│ ├──model //model层其实是redux或vux文件│ ├──component //组件│ ├── App.vue // 入口页面│ ├── main.js // 入口 加载组件 初始化等│ ├── assets // 主题 字体等静态资源├── index.html // html模板└── package.json 其实该目录结构完全没问题,按职能划分结构非常清晰,api放api,静态资源放assets里等等。但是前端目录结构,笔者认为应该对于页面和组件继续细分。举个列子当项目较大时,api目录里存在api将会非常之多。大致效果如下图:该图为笔者某个项目的api结构图,虽然笔者按照某个约定api文件名==view里对应的页面组名.但是真正维护起来有时会遇到这么两种常见情况. 1.删除页面:你将删除pages/carts[购物车页面]里的某个页面,但是问题来了你不确定api/carts[购物车api]哪些api才是不用的,其实没用到的有些IDE会提示。 2.复制移动组件或页面: 比如你想复制组件,由于划分颗粒度不够细,你又一次面临该组件对应什么api和什么静态资源,这么移动复制时只能靠猜了= =其实出现上面问题,就是该种按职能划分的方法不太适合前端。如果你仔细想想前端页面的删除逻辑,你就会知道我们一般会去做删除或废弃的单位就是页面或组件,所以笔者前端目录应该对于页面和组件继续细分这里在扯远点,不知各位看官老爷是否记得MVC框架,这个衍生于后端思维的前端框架。为什么会被MVVM框架逐渐取代? 原因就是MVC这种框架不适合前端这种频繁需要数据和页面组件联动的场景,因为前端不仅仅是管好数据并渲染这么简单,而是要应付各种数据变化对应的页面组件变化,而MVVM框架恰能解决该痛点。所以,后端这种按职能划分的目录结构虽好,但用于前端也不是最合适的方案。目标在按职能划分目录的基础上,再细分到按页面和组件划分目录,做到删除组件时不会牵连到其他组件和页面!不会出现页面删除后,资源还常驻于项目中成为钉子户.解决方案示例结构├──src│ ├──view //页面│ ├──carts //购物车页面 │ ├──component //该页面专用组件│ ├──model.js //该页面的数据层[redux和vuex文件的细分] │ ├──index.js //该页面的布局文件 │ ├──service.js //该页面用到的api │ ├──index.scss //该页面用到的scss │ ├──utils //JS工具库│ ├──api //共用api接口【永不删除】│ ├──style //共用style【永不删除】│ ├──config //配置│ ├──model //共用model层其实是redux或vux文件【永不删除】│ ├──component //共用组件│ ├──map //地图组件│ ├──model.js //该组件的数据层[redux和vuex文件的细分] │ ├──index.js //该组件的布局文件 │ ├──service.js //该组件用到的api │ ├──index.scss //该组件用到的scss │ ├── App.vue // 入口页面│ ├── main.js // 入口 加载组件 初始化等│ ├── assets // 主题 字体等静态资源【永不删除】├── index.html // html模板└── package.json 这里分为三个级别共用级别,页面级别,组件级别共用级别这个好理解,就是项目经常会共用到的资源,基本上一旦定下,为了项目稳定就永不删除了。页面级别│ ├──view //页面│ ├──carts //购物车页面 │ ├──component //该页面专用组件│ ├──model.js //该页面的数据层[redux和vuex文件的细分] │ ├──index.js //该页面的布局文件 │ ├──service.js //该页面用到的api │ ├──index.scss //该页面用到的scss 可见围绕该页面各种职能的文件又再建一遍,且都为该页面专用,连组件也是页面专用级别的。组件级别│ ├──component //共用组件│ ├──map //地图组件│ ├──assets //该组件专用图片或icon │ ├──model.js //该组件的数据层[redux和vuex文件的细分] │ ├──index.js //该组件的布局文件 │ ├──service.js //该组件用到的api │ ├──index.scss //该组件用到的scss 可见围绕该组件各种职能的文件又再建一遍,且都为该组件专用。总结在按职能划分目录的基础上,再细分到按页面和组件划分目录。如此这般,组件想删即删想改即改,副作用更可控!!再也不怕留下钉子户资源啦! ...

April 8, 2019 · 1 min · jiezi

麦肯锡告诉你:培养高效团队的9大法则!|职场必备

最近正逢研究管理知识,有人推荐麦肯锡三部曲,闲暇时啃完了第一本《麦肯锡工具》,并做了一些简单梳理。麦肯锡告诉你:培养高效团队的9大法则!|职场必备《麦肯锡工具》是探索如何通过团队协作来卓有成效的解决问题的一本书,在理论上着墨不多,重点放在了行动上,每一处作者都通过几个方面围绕焦点小组的问题解决方案展开,并对关键概念最了简洁的讨论。本书核心讲的就是TEAM-FOCUS 模型。这个模型分人际要素和分析要素两个部分,具体模型内容可见下图。(TEAM-FOCUS 模型)麦肯锡告诉你:培养高效团队的9大法则!|职场必备在具体阐述模型的每一个要素时,都按照一套明确而直接的标准操作流程(SOP)来作的阐述。所谓SOP,就是概念、执行规格、操作攻略、实战故事、案例研究。在梳理本篇笔记时,根据个人需求,笔者做了一些裁剪,重点梳理的是概念、执行规则,弱化了操作攻略、实战故事、案例研究。如果读者有兴趣了解更多,建议还是读图书原文。标准操作程序:SOP概念:主题概要1、执行规则:给出三条最为重要的行动建议2、操作攻略:给出非常具体的策略建议3、实战故事:介绍麦肯锡校友和商学院学生应用这些概念的情况和体会4、案例研究:讲述在非盈利性咨询项目中应用这些概念的真实故事交流重点通常因为缺乏具体的执行规则;因为偏爱发表高见而不愿倾听;因为固执己见。项目组能否高质量解决是问题的最重要因素之一就是在于是否构建了通畅的沟通渠道。交流中要注意倾听。执行规则规则一:沟通不息。沟通过度和沟通不足的成本分析,沟通不足的潜在成本巨大。(所以企业查询报表要多做,备用,除非上BI)规则二:用心倾听。关注发言者,鼓励发言,会后总结;主动向未发言者征求意见。规则三:人事分离。说出观点,把问题本身的提问人分离,从正反两方面对观点展开讨论,重点关注积极方面。评价重点评价是影响团队成员成长的关键因素评价所涉及的内容必须直截了当良好的评价体系三要素:开诚布公、明晰性、一致性执行规则规则一:讨论团队协作状态。讨论应该涵盖性能、工作喜好、如何处理分析和如何就项目进程进行沟通规则二:确定期望与监控完成情况。确定、记录期望,并跟踪完成情况。是大家有共同的期望。明确哪些任务是重要的。规则三:明确个人发展目标并相应调整工作计划。每位团队成员都有清晰的个人成长目标。评价跟人优势劣势(swot分析)*+分享成长机会。协助重点(与协助相关的问题常出现在三大领域)角色混乱。团队组建后迅速分配任务,团队成员的个人能力和兴趣未得到充分考虑。缺乏反馈或反馈不到位。反馈传递方式缺乏技巧或个人色彩过浓,让人难以接受。过渡关注自己的任务。不关心队友是否需要帮助。执行规则规则一:充分利用专长。基础是充分讨论优势和缺点。规则二:各司其职。每个成员要清楚全局且对自身的任务负责,要强调项目期限的重要性。信任,但需要确认。规则三:实时反馈。有效反馈,及时性。反馈最好私下进行。反馈要做到有正有反,保持平衡。反馈要具体,不要泛泛而谈。要从具体个人的角度而非他人、大家的角度来反映问题。要用实例来说明因果关系和影响。要以正面展望来结尾,同时要提供方向。麦肯锡告诉你:培养高效团队的9大法则!|职场必备激励重点(因人而异)金钱:已将近或加薪形式出现的现金升迁:登上事业图腾的更高位置赏识:非金钱形式的褒奖、认同感激:简短的感谢语执行规则规则一:确定个性化激励因素。首先对成员的差异进行系统的分析。马斯洛需求层次理论。最有效的激励工具之一,亲自示范。规则二:积极正面影响团队成员。5P原则。认真准备(prepare)他人为重(put other first)真诚赞美(praise sincerely)勿施压于人(pressure no one)提供帮助(provide value)规则三:庆祝成就。全员参加,场所灵活,评价亲和。界定重点在确立议题书和基本假设时,做到内容明确、重点突出要通过找出验证性和证伪性论据来证明或推翻假设要切记界定过程需要反复,往往无法一次性得出最佳答案执行规则规则一:明确关键问题。最初所得出的问题并不一定准确,要弄懂客户对关键问题的观点和想法。规则二:创建议题树。信息数树。总结出“到底哪里出了问题”决策树。“我们能做什么”规则三:形成基本假设。是对关键问题所做出的可能的答案。假设是决策树的起点。假设必须符合证伪性。分工重点(既要提高效果,又要提高效率)需要用来检验界定阶段所做假设的工作计划执行规则规则一:构建总体流程图总体上需要完成哪些工作由谁负责完成最终结果该如何什么时候必须完成规则二:制定内容计划以检验假设。高效的团队会将经理重点放在确定和检验最重要的子假设上。规则三:设计故事线索。故事线索是项目结束时项目组要提交的最终汇报(presentation)的大纲。从项目开始实施就开始准备最终汇报。收集重点(国内,主要困难是没有数据或者没可靠数据;美国,主要是信息量太大,难以处理)数据分析是用来证明或证伪假设的工具数据分析师借金额是问题的人得出假设正确的有效结论数据是报告和最终汇报的基础执行规则规则一:通过“草图”呈现必要数据。草拟的幻灯片,用于在问题借解决的早期捕获想法。规则二:进行针对性的访谈。受访者对索要检验的假设能提供直接和互动的反馈。规则三:收集第三方数据。目标是金肯能做到既富效力又有效率,尽量坚守手机哪些对案例不重要的资料。牢记关键问题与基本假设。解读重点。最大的难题是如何形成高质量的见解执行规则规则一:明确“sowhat”。检验具体研究所手机的数据的相关性。规则二:理清对项目相关方面的启示。咨询团队、客户项目团队、客户方案实施团队规则三:记录所有图表中的核心见解。尽早开始,寻求见解,充分考虑对客户的影响。提炼重点。金字塔法则发挥作用的地方。执行规则规则一:获取意见,确保认可。争取客户积极参与,要求管理层必须积极参与。规则二:提供具体的改进建议。每套方案有一个核心思想,给出更为具体的方案。规则三:讲述一个好故事。任何层级的观点都萤爱是对下层观点的总结同一层级的观点总结的高度必须一致同一层级的观点必须按照逻辑顺序排列重要见解洗心:依靠改变意识、方法和工具,来改变工作方式、运作方式、合作方式洗脑:从思维方式上,成为面向客户的解决问题者洗手:提供有效解决问题的技巧性很强的工作方式和诀窍精彩金句回归基本(Back to Basic )。不是初级,而是基本——最近单的三板斧,往往关键的时刻救命,也就是最高级的功夫!因为麦肯锡三个字而买下这本书的你,一定要明白方法论才值你花的那些银子。看完后,千万别迷信麦肯锡:路子对了,你也行。本书的目的很简单,那就是提供提高团队借金额是问题的效率与效力的工具。本书以广大读者的利益为核心,突出并落实了广泛应用于麦肯锡等咨询公司的“特种部队”的方法经验。本书不以追求理论上的高深莫测为目标,相反,强调的是实战应用,可用于知道那些面临Team PS问题单因忙碌而缺乏时间找到解决方案的学者、咨询顾问和学生。优秀的咨询顾问必须知道“讲故事”(story telling)的艺术并善于讲故事。转自:https://www.toutiao.com/i6455…

April 4, 2019 · 1 min · jiezi

我的前端工规范系列--前言

前言程序开发"变是常态,不变是非常态"只有定好不变的规范,并做得足够好,才能更好的应付变化。该系列文章会把平时工作中常遇到的问题场景抛出并提供解决方案,主要来自自己的学习和整理。现主要涉及如下:图标工程化[好用的图标]颜色语义化,变化标准化[要变大家一起变]高清屏适配[按标准来就行]大小规格化[你要大杯 中杯 还是特大杯]设计可复用化[给设计发好人卡]优先字体规范[我为什么就比你好看]距离产生美[什么才是九头身]如何优雅的切换项目环境[再也不怕搞错环境了]如何设计项目目录和文件存放[终于可以想删就删啦]主要优化场景问字号,看不出行高未优化程序员: 不好意思你这个字号多少?设计师:标你妹有程序员[打开标你妹 找到页面]:那行高呢?标你妹看不出来?设计师: 。。。????程序员:随便搞个= =????简单优化程序员:这个是多大字号设计师: xxs程序员: 那肯定是12号了终极优化后程序员: 咦这个是解释性文字 那肯定是12号字体 18行高问颜色,看不出透明度,动态变化色未优化程序员:不好意思你。。设计师: 标你妹????程序员:。。。变化后的点击色没有啊 算了自己搞个= =????终极优化后程序员: 呀!这就是主题色 #xxx ! 这个就是警告色 #xxx 那他点击后肯定是加深10% ????找图标[各种激活,边框,实心,非实心状态]未优化程序员: ….[还没发问]设计师: 标你妹程序员: 这个标你妹还真没有。 。程序员: 你这个图标在哪里?什么名?设计师: 额!找找。。优化后程序员:啊!这个是导航-➕-‘激活’-‘非实心’-‘矩形边框’ 那肯定就是nav-plus ,输入nav试试IDE: 你要的是[✅]nav-plus-actived-o-squre [❌]nav-plus-o-squre[❌]nav-plus-actived-o[❌]nav-plus-actived终极优化方案字体图标方案程序员: nav-plus-o-squre 嗯嗯这个 激活应该是加个主题色 嗯嗯 直接改色????改图标,程序员找目录归属未优化程序员:不好意思!你这个页面的这个图标要改设计师:改好了!!给你程序员:不对额!你这名字对不上 算了自己改下。。呀这文件在哪个目录里呢??优化后程序员:不好意思要改图标 叫nav-plus-actived-o-squre 设计师:哦 在导航那的加号啊 好了给你程序员:嗯嗯!这个应该就在icon>@2x>com>nav> 啊果然在这里!!我真是太聪明了 ????终极优化方案字体图标方案程序员:不好意思要改图标 叫nav-plus-actived-o-squre 设计师:哦 在导航那的加号啊 这份字体图标给你程序员:直接覆盖 哈哈????改图标色系未优化程序员: 改一套蓝色色系吧设计师: 。。。改好了。。。。给你程序员:我要辞职。。名字全乱了优化后程序员: 改一套蓝色色系吧设计师: 。。。改好了。。。。给你程序员:还好还好,可以找到相应的目录 ????不然要辞职了终极优化方案字体图标方案程序员: 改一套蓝色色系吧 嗯嗯 直接把主题色一改 ????IDE: 生成中ok????????图标文字始终对不齐未优化程序员: 呀你这个图标切成 长方形了 对不齐啊设计师: 冷漠脸程序员: 算了! 我自己调调几天后。。。设计师:换图标了程序员: xxx 又差几像素 再调下算了????优化后程序员: 图标大小 和 对应字号 一放 咦 刚刚好饿 日了狗了????要@X图未优化程序员: 少了@1x 少了@2x设计师:冷漠脸app程序员: 额 算了 我直接用@3x 放在一般看不出来web前端工程师: = = 那我怎么办 @3x 文件太大了优化后什么都没发生 ????????不敢随便删除资源文件未优化程序员: 这个文件好像用不到了,要不删掉算了…[被炒鱿鱼]程序员: mmd 我怎么知道你们竟然还用这文件优化后程序员: 这张图片是这个组件专用的,那行一起删掉。真是又安全又省心参考资料iview阿里ant-Design标准移动高清,多屏适配方案微信上的svg ...

April 3, 2019 · 1 min · jiezi

我的前端规范系列-图标工程化[好用的图标]

为什么要有图标规范1.文字和图标能更好的搭配使用图标是具有指代意义的图形,也是一种标识,即文字的一种延展,实际应用中也常与文字一起配合使用,按字体标准规范化设计的图标更容易对齐。2.图标适配变得更简单,图标风格更统一,大小统一矢量化后的图标,由于程序对颜色大小可控,且不失真的特点,更利于适配实现图标的72变。另外由于切图大小统一,不用把时间花费在调整图片容器上。3.能快速修改和得到想要的图标图标命名规范化后,编程人员可以很快配合ide找到想要的图标。 不用把时间浪费在找图上。目标1.图标规格统一2.图标命名规范3.图标切取统一4.图标管理图标命名规范规范顺序[图标名]-[状态?]-[形状?]-[描线?]-[方向?]@[1,2,3]x.png 带?号为可选图标名公用图标名举例:[图标名]举例:button释义:按钮非公用图标名举例:[模块]-[类别]-[功能]举例:nav-button-search释义:导航-按钮-搜索修饰名定义形状这里我们简单分三种情况,一种被方框包围-square,一种被圆圈包围-circle是否实心这里我们使用修饰符-o表示描边型,不带-o为实心型常用状态svg和iconfont可以不需要常用状态激活 actived禁用 disabled悬停 hover示例带圈圈的加号非实心且激活png:plus-actived-circle-osvg/iconfont: plus-circle-o建议使用svg和iconfontpng vs svn vs iconfont格式优势劣势png渲染快存在适配问题需要制作各种x图,程序不可控,适配后体积大svg支持单独和整合打包,支持多色彩,矢量,颜色大小可控,有成熟的管理工具渲染比图片慢iconfont矢量,颜色大小可控,有成熟的管理工具不支持多色彩,字体文件大,低像素屏有锯齿那么简单得出svg和iconfont的特点设计只需出一次图,图标集中处理,程序可批量改色改大小且不失真可以直接获取别人的svg或 iconfont进行修改工具管理示例阿里UX矢量图标库小结如果设计不介意频繁改图片颜色,制作各种大小状态。使用png也是可以的,但基于以后项目换肤的要求还是建议svg和iconfont里二选一。图标设计规范图标要有重心根据不同的图标形状类型使用不同的轮廓线,可以使图标之间保持一致的视觉效果。请将所有图标在 1024×1024(16×16 的 64 倍)的画板中制作。权重不一的图标会破坏视觉平衡图标尺寸规范规范应该与字体搭配时和字体的尺寸保持一致尽量不要标新立异,因为只有和字体大小一致时并排时才能保持水平对齐[一下为@1x时的情况]。劲量不要切入阴影,由于阴影的深度,如果没有切取得当,经常拿到阴影截断的图标,致使反复修改图标切图规范规范不管图标是扁的 还是长的方的 都应该一致切成方的需要按设计图标时的容器轮廓线切图,因为程序设计时如果每个图标都要特定定义一个特别的容器来装的话,工作量和可维护性都会出现很大问题。

April 3, 2019 · 1 min · jiezi

如何做出有价值的竞品分析?

一、为什么要做竞品分析?以笔者比较了解的加点、3C产品厂商为例,企业在信息化建设过程中会选择做内部数据分析,例如销售、生产、库存等,这对企业了解自身整体运营情况非常有用,但是这些信息对把握市场动态、了解客户需求来说作用十分有限,而对外部数据的分析工作可以帮我们很好的弥补这些不足。竞品分析是外部数据分析中非常重要的一个模块,尤其是对一些家电、3C产品为主的企业,会有大部分的营销渠道是通过B2C的方式在电商平台上完成的。如果能将这部分数据包括竞争品牌的经营数据拿到,采取对比、关联、趋势、因果等方法进行分析,会给企业经营带来意想不到的好处,总结如下:电商数据自动分析处理,更高频、更准确,避免传统人工采集带来的信息延迟、错漏、耗时等问题;了解自己品牌产品的市场份额及竞争力,有助于及时调整营销策略;对比竞品的价格分布,规划自己品牌的价格带,有利于渗透市场;分析促销的频度、深度和效果,制定适当的促销策略,抢占市场;分析品牌特征,加速主流产品的资源倾斜,最大化市场占有率;了解客户评价,反馈引导产品及服务改良或创新。二、品类品牌分析竞品分析第一步要做的是找到分析对象,这个对象指的就是竞争对手,家电和3C产品在国内市场中的品牌很多,竞争也相当激烈,按照市场区域分布及产品类别很容易找到对应的竞争企业及品牌。参考市场主流分类方法,按照产品外观、功能、性能等角度,将竞品品类进行细分,并与自身的产品品类结构进行对比,找出缺失和多余的细分品类清单,再分析这些品类目前的销售趋势:如果缺失的品类市场趋势利好,则考虑产品引入,抢占市场;如果多余的品类市场趋势低靡,则考虑放弃该品类,及时释放资源。有助于企业调整自身产品品类结构,跟随市场方向、避免资源浪费。如何做出有价值的竞品分析?三、市场份额分析品类结构梳理出来之后,接下来就是对不同品类的市场份额的分析。同一品牌不同品类销量销售额对比分析,了解不同品牌的主流产品类别、结合成本,分析毛利率和净利率,得出不同品类对销售盈利的贡献程度。如何做出有价值的竞品分析?同一品类不同品牌销量销售额占比分析,了解自己所占的市场份额。按时间维度做走势分析,了解销量占比的变化情况,对于连续下降的情况进行分析,可能是竞品提前做了促销宣传或是拉低价格等手段,避免打破品牌战略的平衡状态,导致市场重新洗牌,到时候就非常被动了。如何做出有价值的竞品分析?四、价格渗透分析某一品类的销量高并不代表该品类的销售额一定高,同理,某一品类的价格高也并不一定代表该品类盈利多,对于关键产品参数相似的品类,价格往往决定市场走向,所以如何在最大化单品盈利和市场接受程度两者平衡中找到属于自己品牌的价格区间显得尤为重要。就单一品类来说,不同企业对于产品研发生产的投入是不一样的,简单的可分为高端、中端、低端产品三种定位,不同定位也有不同的成本和对应的价格,做不同品牌价格区间与销量的对比分析图,如果某一品牌在高端产品有着绝对的市场占有率和竞争力,而低端产品市场品牌混杂收益不高,那么可以选择中端定位来主推产品。在同一定位层,如果在某一价格区间竞争激烈,在成本可接受范围内,可以考虑下降一个价格区间,避开锋芒进行产品定价,对于新产品的投放和市场渗透来说是非常有帮助的。价格带分析可以帮助企业了解自身所处的定位区间,及时调整价格策略,避免价格带留有太大空白,导致竞品垄断。如何做出有价值的竞品分析?五、促销活动分析电商平台上会经常根据季节变化、节假日或集体性活动来开展促销活动,例如五一、双十一、夏季空调促销等。对竞品价格和销量的监控可以有效识别出其是否有促销活动,可以针对性的制定应对措施,防止市场大面积流失;对往年促销活动开始时间点、持续时间、次数的分析,得出促销的频度,以此制定今年的促销策略;对促销过程中价格和销量的走势分析,再做同比、环比分析,可以看出其促销的深度和效果,再和竞品的促销效果做对比,对后续的促销工作有指导意义。如何做出有价值的竞品分析?六、客户评价分析对电商数据分析中比较重要的一个模块是客户评价分析。根据产品SKU获取客户的评价内容,分析其好评率和差评率,得出其客户评价的整体情况,同时也可以和竞品做对比分析。对具体的评价信息进行关键词检索,可以统计出企业关注的一些产品或服务问题,例如空调的制冷效果、噪音大小、安装乱收费等,找出不同品类中最突出的问题,反馈至产品进行设计改良,或者找竞品中问题较少的产品,拆解分析参考改良。客户的评价是对产品在实际使用中的反馈之声,能够帮助企业真切的认识到产品外观、功能、性能上的不足,而针对这些不足的改善也是最能够把握住客户把握住市场的地方。如何做出有价值的竞品分析?七、营销趋势分析通过对自身数据或竞品数据的长期监控,可以进行营销趋势的相关分析。根据相对稳定的销售额年增长率情况以及季节、节假日等相对规律的周期性质的变动情况,来提前预测下一个时间节点的市场需求量,及时调整企业自身的采购计划、生产计划等,避免货物大量积压或缺货断货现象的发生;根据不同品类的销售走势情况,确定主流产品,及时资源倾斜,最大化利益,对没有市场竞争力的老旧产品及时清仓淘汰;分析竞品的营销趋势,掌握竞争对手的营销方向,根据情况及时调整自身的营销策略。如何做出有价值的竞品分析?如何做出有价值的竞品分析?本文以品牌商的角度从市场层面进行分析,并未涉及到店铺维度的分析,所以没有讲解客流量、转化率、订单等指标。如有对以上内容的数据获取、实施落地感兴趣的可直接留言,联系笔者。

April 3, 2019 · 1 min · jiezi

绩效管理这样做,成本减半,员工叫好!

绩效管理无处不在,大到集团的战略规划,小到平时的周报、日报。既然企业都有绩效管理,为什么要对绩效进行数字化管理?如何使用IT手段在绩效中发挥数据价值?一、绩效管理数字化的意义拿营销模块对上述两个问题进行解答。绩效管理是对目前状况的反思和展望,反思现有绩效体系下遇到的问题,并对绩效体系进行优化,它反应的不仅是一个结果,更是对过程的监控。绩效管理自身所具有的性质要求数据具有准确性、即时性、全面性。准确性主要是营销部门之间、营销与财务等之间数据的展现方式、统计方式的统一(避免呈递的报告数据不一致,样式不统一,减轻管理层压力);即时性分为两个方面,一个是保障员工随时可以查看自身业绩完成进度,对异常指标进行预警(预警可以分为正激励和负激励);二是在会议、汇报时能够快速出报告(避免“头重脚轻”,重点在问题的分析和展望,而不是每次为了做出精美的图表而头疼)。一张图来说明绩效数字化管理前后的变化;绩效管理这样做,成本减半,员工叫好!全面性重在保障。从人员角度,保障激励效应的正确执行,该奖励的奖励、该处罚的处罚从部门、区域角度,保障整体目标的正确预估(虽然销售额同比增长了百分之20,但是市场份额扩大了百分之40,此时就应该理性判断目标的设定和市场之间的关系)。公开性重在公平,也是对奖惩机制的加深影响,有利于员工横向和纵向对比,加深自身能力的提高,积极参与到绩效考评中。二、需要明确的几个点在进行绩效管理数字化之前,需要明确三个影响方面:企业现有绩效管理的模式、影响绩效的因素、绩效管理的方法。对上述三个问题的分析能够帮助我们发现企业绩效管理问题,对症下药,切实解决企业业务问题。不管是企业信息人员自行实施,还是外部人员实施,都不宜用一套固有的绩效管理体系直接使用。绩效管理体系一定是基于企业现阶段的发展状况所设定的,跟随企业的发展而不断变化的,盲目套用容易导致“水土不服”。篇幅原因,简单介绍下国内大众的绩效管理体系,方便大家与自身企业对照:(1).粗放式指标管理体系,与薪酬和岗位不挂钩,重点在把控企业的经营状况;(2).调研式管理体系,此类主要为人力牵头对业务部门进行考核,考核范围众多,重在检查评比,对业绩考核弱;(3).评价式管理体系,表现为各层级对人员的工作和能力进行评价,主要应用于国企和事业单位,代表为360度考核评价体系;(4).目标式管理体系,体现为指标和薪酬、岗位挂钩,基本为营销部门绩效管理的主流。其他管理体系,如:阿米巴管理体系,后续开单篇介绍。绩效管理这样做,成本减半,员工叫好!其中,绩效管理的方法如上图,PDCA循环:计划、实施、检查、纠正,下文会详细介绍。绩效管理的影响因素中,员工能力是最核心、影响最大的因素,通过培训和学习可以不断的提高;外部环境和内部资源属于客观原因,不是企业可以完全控制或者是短时间改变的;激励效应不管是从管理角度和数据化的角度,都有很大的空间可以提升。同时激励效应对上述三个方面均会起到积极作用,人员的积极性提高有助于自身能力的提升,积极从内外部资源获取资源。所以,在PDCA循环的设计过程中,激励效应是其中重要的因素。三、绩效管理如何发挥数据的价值?不管企业的绩效管理是否成体系,都有他自身存在的意义,我们使用数据不是来创造一个新的管理体系,而是对原有系统的还原和优化。调研业务遇到的问题,通过数据的途径进行优化。根据咨询和项目实践来看,企业绩效管理的实施主要分为以下四步:计划:从集团到个人层层分解,对考核标准、权重、考核指标、考核方式达成统一见解执行:此阶段更侧重于过程和人员积极性的调动,经常以报告和会议的方式举行)检查:对阶段性绩效进行考评,实行奖惩纠正:对整体绩效体系进行优化,分为两个部分,对计划的整体变更、对数据展现方式的优化)。其中激励效应贯穿于整套体系,同时激励效应也是我们实行数据管理的重点。以下主要以帆软在生产型企业营销绩效管理实践为例进行介绍,企业可以根据自身绩效管理的方式有选择性的实施。1.计划计划阶段侧重对企业数据全面性展示,为企业将要做出的计划提供数据的支持。计划阶段数据展现的全面性是由计划设定的精细度而定。举个例子,国内某大型油漆涂料营销KPI指标设定为:营销部门的计划主要是从两大模块:主体、附属。主体:部门、区域、个人的层层递进;附属:产品、门店、经销商。绩效管理这样做,成本减半,员工叫好!其中销售额、营销费用、附属都对主体负责,同时产品、经销商、门店也有自身的一套指标考核体系。有条件的客户在提供数据时候,可以加上同行业的对标分析、同类型产品的市场占有率分析等。在这个阶段有三忌:(1)忌蜻蜓点水,如上图,营销费用中的市场费用没有继续细分,但是为了营销部门计划设定的准确性,我们还要继续把指标细分展示。如:市场费用还可以划分为会议、活动、广告、门店建设、礼品物料等。(2)忌用力过猛,在没有咨询和实施进场的情况,最好根据自身企业的绩效体系进行制作。(3)忌计划数据不足,这时上述两点的好处就体现出来了,协调营销部门对计划数据进行填报,为后续的实施部分做准备。2.执行执行阶段侧重数据的准确性和及时性,实现对员工的激励和自我激励。执行阶段的数据展现按照时间维度划分可以分为对标激励、KPI报告、会议复盘三个模块。其中对标激励主要通过员工间业务指标的横纵向对比,实现自我激励(指标详细、根据企业自身来设定);KPI报告侧重于监管,企业、部门、区域、人员层层递进,从而实现对企业营销管理从上之下的监管;会议复盘侧重于优化和信息的整合,通过对市场、产品维度的分析,分析现有营销的发展是否合理,通过对案例的分析成功和失败的经验,实现对知识的分享和系统的优化。绩效管理这样做,成本减半,员工叫好!3.检查检查阶段侧重数据的公开性,促进员工积极参与到绩效管理中。实际操作中此步基本为上级的评价和KPI奖励的落地执行,此时要注意两个问题。一、上级的评价入口的设定影响到评价的频率,评价不应该是在最终考核的时候才做出来应付工作的,而是贯穿在业务活动中的。所以要根据企业自身的习惯,设定好评价填报入口。二、KPI奖惩的宣传问题,宣传的力度会影响到业务人员对整个体系的认同度和自我激励的实行效果,所以要提前设定奖惩的公开展示体系,比如:大屏、特殊信息推送等。4.纠正纠正阶段是对整体绩效考核的调整,贯穿整个体系中,是保障整个体系跟随企业和市场的发展而不断进步的必备手段。整个系统的优化可以细分为两个部分:对计划的整体变更(一般为KPI指标的变化)、对数据展现方式的优化(模版样式、展示渠道等)。模版的优化可以根据业务人员使用频率和反馈建议来不断进行改进;指标体系的变更就回到了计划阶段,此时在经过了一个循环过程中,除了计划阶段可以提供的支持,我们还可以对指标预警的数据进行收集,供业务人员参考,从而优化指标体系。

April 3, 2019 · 1 min · jiezi

新城控股精细化数据运营案例

新城控股概况新城控股集团股份有限公司(以下简称“新城控股”)于1993年成立于江苏常州,业务涉及房产开发投资、商业管理等多个板块。经过二十多年的发展,新城控股已经成为跨足住宅地产和商业地产的综合性地产集团,并于2015年在A股上市;2016年公司全年合同销售金额达650.60亿,同比增长103.76%,跑赢行业平均40%的增幅。凭借优异的市场表现,新城控股荣升“2016中国房地产百强企业”第15位。数据应用上升为集团战略1、由粗放式经营进入精细化管理阶段随着国家管控政策和市场的变化,整个地产行业利润目前呈现出逐年下滑的趋势。同时,业内巨头并购事件持续演绎,行业分化、企业整合速度和洗牌速度加快,中小型房企通过粗放式经营获得稳定发展的愿望化为泡影。在这样的时代浪潮下,新城控股逐步关注企业利润和增长质量,将数据应用提升到了集团战略层面,为集团主营业务的持续跨越式发展赢得了契机,并于2016年凭借优异的市场表现,成功荣升“2016中国房地产百强企业”第15位。2、“住宅+商业”的业务模式对数据应用提出了更高要求在整个行业不看好商业地产的情况下,新城控股还在逐年加大商业地产项目的建设和投入。截止到2016年底,新城控股已经累计开业11个新城广场,全年实现租金及管理费收入4.41亿元,出租率达 98.96%,新城控股在向规模化商业运营的业务方向上,迈出了坚实的脚步。相比住宅销售,商业运营无论是对内还是对外,都面临更高的管理要求。对内,财务的精细化运营、风险评估;对外,如何实现高质量的招商,如何提升消费者粘性,都是对集团信息化和数据应用提出的全新命题。数据应用愿景新城控股的集团数据决策平台建设,坚持以业务和需求为出发点、以数据为驱动的原则,所有的需求都是来自于业务部门,IT人员根据当前数据基础和质量等情况,构建数据仓库和数据集市,满足业务人员需求。新城控股精细化数据运营案例根据对当前业务现状和集团战略的理解,新城控股将集团数据决策平台的建设目标确定为以下两个主要方向:1、 对内精细化运营:整合企业内部各核心业务系统数据,打造内部经营分析平台。用数据说话,辅助决策分析;智能监测、风险评估,实现精细化运营。并在此过程中沉淀企业数据资产。2、 对外价值变现:充分挖掘企业数据资产并与外部资源对接,跨界合作。探索新的营销模式,寻找新的盈利点,进行数据资产价值变现。在对项目目标进行了充分的理解和调研后,新城控股选择了帆软的两款产品。其中Finereport面向领导决策层,采用固定模板展示高度聚合的汇总指标数据,有效支持内部经营决策;FineBI平台面向业务人员,将企业的经营数据进行标准业务数据集整合,通过业务包的授权开放给相应的业务人员,支持他们通过自助式的定义可视化的界面,看他们需要的数据,及时了解外部变化。数据驱动的全新运营思路新城控股数据决策平台从业务发展的角度,全面整合集团各业态数据,构建业务模型,为实现集团大数据应用、寻找创新突破、进行数据资产变现,提供了平台基础。数据决策平台上的业务模型主要包含以下几块:1、项目IRR模型项目回收周期长、资金占用量大是地产行业评估项目收益时需要考量的特点。因此,项目IRR(内部收益率)成为所有地产企业老板最为关注的经营指标,同时也是项目跟投人决定是否跟投项目最重要的依据。因为IRR指标的计算涉及到销售、财务、成本甚至项目交付等诸多方面,任何一个环节发生变化都可能造成IRR的波动。以往通过线下报表的方式统计IRR,进行层层数据收集和汇总,容易出现以偏概全的情况,另外,这样的数据时效性差,并不能准确说明当前项目准确的收益情况。新城在数据决策平台上建立了IRR模型,通过对明源全面预算系统数据进行ETL处理,将IRR数据进行标准化存储。决策层可以获得及时、准确的IRR数据,制定有效的经营策略。同时,模型还结合了项目合伙人跟投系统,进行跟投收益率计算。按月动态监测项目IRR变化情况及项目跟投收益情况。新城将IRR动态监控集成到了移动端,进一步放大了IRR模型的价值:通过移动端能够及时掌握每个项目的收益(和项目IRR绑定),提高了新城员工跟投项目的积极性。集团则可以通过IRR实时激励整个公司的运营和管控。2、货值统计模型对于房地产企业来说最重要的产出就是货值,货值的多少与动态变化过程实时地反映着企业的经营规模和经营状况。那如何动态地获悉销售总货值,及时精准的计算销售总货值与销售去化的情况?已成为房地产企业多年来一直在追寻的答案。曾经国内某知名房企在年末的高层会议上要求精准地汇报本年的销售总货值、已售货值、入账货值、待售货值、未开工预计货值。但面对集团下属上百个项目,营销部门统计这些数据足足花了2周多的时间才完成收集统计,部分项目的数据还无法检验其真实性。新城控股的数据决策平台,打通了包括主数据、生产计划、销售计划、销售数据以及财务经营指标等所有环节的过程数据,做到了全生命周期的统计。能够及时反馈包括未售、已推未售、预计推盘、剩余未推在内处于各个生命周期的货值统计。通过这个平台,决策层可以通过时间轴来分析,哪一天库存卖完了,从而决策什么时候可以继续拿地投入新的项目,以发挥资金的最大价值。新城控股精细化数据运营案例3、动态利润和奖金测算模型对于周期较长的项目,操盘手或者执行公司的领导,对于项目上的动态利润和奖金情况得不到准确的信息,就很难产生持续的动力投入项目。新城控股通过数据决策平台建立了动态利润和奖金测算模型,作为项目的操盘手或者执行公司的领导,可以看到截止到当前可以拿到多少奖金,另外预测到年底可以拿到多少奖金,实现动态激励。动态利润模型:整合多方数据源,从公司、项目、分期、产品、业态、日期构建数据分析维度。动态获取财务、营销数据每日进行销售净利润计算,匹配年度利润目标,进行实时动态监测,辅助决策分析。奖金测算模型:整合项目回笼数据、签约利润、结转利润,按计奖公式进行奖金计算,从项目到城市公司进行奖金包合并测算。实现实时激励作用。4、商业经营分析模型近年来,国内大型购物中心数量增长加快,同质化竞争加剧,加上电商平台对实体商业的冲击,商业广场如何实现精细化招商,如何吸引消费者,走出经营困境……成为供过于求阶段商业广场运营者需要思考的问题。新城吾悦广场的运营,在新城集团“住宅+商业”的业务模式中占有重要地位。围绕新城吾悦广场打造高质量的商业运营模式,能够有效提升品牌价值,促进整体销售。建立商业经营分析模型,则是提升新城商业运营能力的重要手段。新城数据决策平台在商业运营分析模型建立方面,主要完成以下三点工作:第一, 利用Finereport自定义地图功能建立商场模型,并与店铺数据进行绑定;第二, 根据商业的客流还有租赁系统进行数据清洗和整合,实现了客流动态监测,包括租赁收入统计分析;第三, 另外通过财务系统的数据抓举,实现了商业运营的投资回报率的查询分析。新城控股精细化数据运营案例5、客户分析模型在新城控股“住宅+商业”的业务模式中,除了有限的购房用户,还有数量庞大的商场消费者用户。依托包括住宅销售、物业、商业和其他多业态在内的海量用户数据,新城控股构建了用户大数据平台,积极探索基于用户属性和用户行为的大数据应用,进行内部交叉运营、寻找创新突破、进行数据资产变现。用户大数据平台实践的主要内容包括:新城控股精细化数据运营案例客户数据的汇集,基于现有业务系统进行数据集成、数据模型搭建,完成客户数据的存储;根据采集到的用户基本信息和行为信息数据,进行新城客户的全景画像,知道客户什么时候买了新城的房子,什么时候入住小区,小孩什么时候到我们的儿童乐园玩过,以及投资理财的情况等等;做了一些数据应用的仪表盘,包括客户触达的环节,支持针对客户的精准营销。转自:https://www.toutiao.com/i6469…

April 1, 2019 · 1 min · jiezi

挑战!怎么确定企业利润的变化和IT建设有直接关系?

内容大纲低调探讨:先问有啥价值1.1. IT 部门就是个成本中心,目标是提高执行效率、降低成本1.2. IT部门也是行政命令的眼和手,目标是传达执行管理意图,实时反馈执行效果,提高管理者的管理幅度1.3. IT 部门也是风险控制中心,目标是降低企业经营管理风险1.4. IT 部门也是机会管理中心,目标是及时高效发现降本增效的机会1.5. IT 系统,是解决人与机器矛盾的有效方案,让人从机械劳动中更多解放抛砖引玉:如何具体量化正文1.低调探讨:先问有啥价值挑战!怎么确定企业利润的变化和IT建设有直接关系?1.1 IT 部门就是个成本中心,目标是提高执行效率、降低成本有人说,是迷之难题,他没办法。我这里姑且做这样第一个假设。持有这类看法的人呢,很可能是被这个问题伤到了。或者,他曾经提出一些解决办法,但是被直属领导或者其他部门否定了。所以,现在他手里,拿不出什么更有效的办法。这里还有第二个假设,就是这些人其实还想找到新的办法来量化 IT 建设的价值的,或者能够让他的老办法推行起来。所以,我们也认为这波人,想和我们一起讨论这个破局的办法的,而不是给咱们起哄、泼冷水的。有人说,计算自己公司 IT部门节省多少软件费用,节省了多少外包费用。这个笔者觉得相对好计算一些。因为自行开发周期和自行开发的人力成本比较方便计算,但总觉得是“以偏概全”,忽略了真正的价值。比如说,忙了一天饿了,有人给你送到办公室一碗热馄饨,姑且卖给你15块钱吧。那这个热馄饨的价值你觉得怎么计算好?是自己亲手做需要40元,然后直接点外卖15元,中间差价25元是你创造的利润吗?还是为你节约的成本?外卖真正的价值不是在于解放了你的精力和节约了时间吗?也就是说,我认为 IT 建设,也是解放了企业的精力,节约了时间,而真正价值大小,就是节约的时间在企业内值多少钱。下面我也是相同的观点,只是在不同的角度来谈一谈。有人说,是降低人力成本,提高人均效率。就是相比IT 系统建设前需要的人力成本,建设后直接降低了多少这块的成本,提供了企业运营的时效性和准确率。这种看法呢,我也是相对部分认同。哪些认同呢?是 IT 建设确实能为一些企业降低人力成本,提高人均效率。但和前面相似,一份馄饨的价值,除了节约自己做饭的时间,还在于这个时间你可以做对你更有意义和价值的事情。比如一个奋战电脑前的淘宝店家,节约这个做饭的时间,可能带来的就是十几笔订单,甚至更多。比如正在转型或者想要探索创新的企业,如果能节约出来这些人力,那么他们就可以进行新的探索。像永辉超市,就是节约出人员来专门分析门店销售,总结优秀店长的经营经验,并分解成 IT 系统,最终形成微信上人人可以简单操作的帆软门店零售分析系统。这就像古代行军打仗,两军对垒,IT 建设就像是某个战法,让你能抽调出一个分队来,这个分队的价值仅仅是几个人头吗?还是价值仅仅是他们粮饷、军饷等费用的总和?难道企业之中,每个岗位,都是只要支付同等的报酬,相应职员像 USB 一样随时从社会中入职,入职就能出活?所以,IT 系统的价值之一,就是如果所说,为企业节约出来人力资源,而这个人力资源关键看企业如何高效实用。其实,计算成本的方式是被动的,甚至是忽视了IT 系统建设的真正价值,完全把 IT 系统和 IT 人当做效率工具了。IT是成本中心这个说法已经根深蒂固了,想翻身不容易,但IT 部门要做好自身规划,企业要更高效率经营管理,IT 部门就是要翻身。1.2 IT部门也是行政命令的眼和手,目标是传达执行管理意图,实时反馈执行效果,提高管理者的管理幅度。有人说,核心就是效率。实际包括了及时性、准确性、直观性等等。核心的一点就是效率的变更。在此基础上,由于更准确,及时,明确的数据指导,从而进行风险规避、精准营销等都是利润的最本质体现吧。不借助 IT 系统,按照彼得·德鲁克的《卓有成效的管理者》的研究,一个理想的、卓越的管理者最多能单独管理200人,当然这200人值得是相互之间有工作联系的人员,下同。当前大多数管理者达不到彼得·德鲁克所谓的“理想的管理者”“完美的管理者”,一个管理者真正能高效管理的团队超不过100人。所以可以简略的划分,大多数大中小型企业,团队超过100人都要借助各种 ERP、OA、Data Analysis System 等等。就拿餐饮业独树一帜的眉州东坡集团来说,他们通过监控和分析每个酒店的客流和菜品订单情况,中层和高层每天能都所有门店经营中出现的问题。领导层向下传达的管理意图,门店执行效果如何,领导层在手机和大屏上就轻松可见。针对具体问题,直接找到对应的负责人,层层向下传达管理意图,确保管理政策执行到位,极大提高了管理幅度,截至到2017年10月,梅州东坡员工已经达到了将近10000名,而只要管理层随时兴起,都可以通过帆软移动决策平台,来查看到每个人的每日工作情况和绩效。虽然说,集团大了,管理者精力有限,不会事必躬亲。但对于很多企业,其管理者都是精通业务之人,甚至董事长创始人当初就是业务专家。在这样的企业里,领导层是十分注重企业经营透明化的,虽然高层多半不会亲自处理企业经营的每一个小问题,但是他们通过透明化的信息系统,直观感受到业务经营的变化,“春江水暖鸭先知”,时时刻刻保持对市场和业务的敏感,这既是高层的焦虑,也是决策层的秘密武器。1.3 IT 部门也是风险控制中心,目标是降低企业经营管理风险如何降低企业经营管理的风险呢?这里我举两个例子。一个是全球赫赫有名的宝洁公司,一个是汽车物流行业闻名的江汽物流公司。宝洁公司呢,推出新的产品前,必须先做市场调研。当然,可能作为消费者,我们接触到的,大多是一些纸质的调查问卷,同时可能网上也会有一些电子版问卷,甚至手机上一些 Html5效果的问卷。总觉得这些和 IT 系统距离有点远。其实不然,这是宝洁采集市场数据的一个大杀招,他们一直沿用至今。宝洁公司的每次调研问卷设计,都是有问卷分析模型在背后做支撑的。市场调研人员采集到的各种形式的数据,宝洁公司有一整套的 IT 系统,能在短短数日就将其处理成市场需求报告,指导产品的研发和市场推广。通过这一整套调研系统,及时降低了企业推出新产品失败的概率和风险。作为消费级产品提供商,宝洁多年来的业绩可以支撑我这个判断。江汽物流公司呢,是安徽的一家主营整车物流、车辆管理、维修、租赁等业务的年轻企业。仅仅成立一年,就获得了国家4A级综合型物流企业和2014年度全国先进物流企业等荣誉。笔者有幸曾走进其调研流程监控数据可视化体系统。那这个系统主要带来哪些价值呢,给我印象深刻的一点是:这套系统能看得见业务运行和状态监控的系统,实时的监控分析数据,曾几次及时监控到汽车物流的异常,管理层及时处理,控制了事态,避免了企业遭受重大损失,比如 GPS事件、某仓库积压事件。所以,笔者所理解的降低企业经营管理风险,其实更多是将风险控制在可接受范围内。虽然,有时也会有 IT 系统将风险消于无形的情况,比如万达集团建立了上游原材料采购系统,能够直接从系统中分析出每个项目工程材料的成本价格,直接避免了超标采购的可能性。就像我们在双十一之前,了解了淘宝商品全年的价格轨迹,很难再被双十一的价格“虚假跳水”所欺骗。1.4 IT 部门也是机会管理中心,目标是及时高效发现降本增效的机会说到降本增效,最容易理解的,我想多半是餐饮零售行业了。餐饮零售行业流量大,店面多,管理经营在整个企业活动中占比最大。同时,这也是我们普通大众相对比较熟悉的行业。还是那个眉州东坡、永辉超市,他们都曾用 IT 系统发现企业降本增效典范行为。眉州东坡开设一家新餐,需要考虑前厅和后厨的面积应该是怎样一个比例?二人桌、四人桌、八人桌以及包间该怎么搭配摆设?这些信息在过去都是凭借经验去决定。以往公司的领导比较热衷于大店的模式,但是到底适不适用,并没有一个准确的结论。IT 部门通过对以往餐厅数据的统计和分析,针对门店分析每平方米可获得多少营收,得到一个数据参考。最终发现小型门店所获得的效益要比大型门店高。因此针对这种情况,公司在战略上做出了相应的调整,降低部分大型门店的数量,增加小型门店。这个降本增效的故事,让眉州集团的数据分析工作,首次得到高层认可,并开启了数据驱动决策的改革之路。永辉超市和眉州东坡的情况有所不同。永辉超市门店众多,经营的品牌和品类更是数不胜数。那个区域哪些品类销量好,哪个品类哪个品牌进货价低,这些都是一个极难回答的问题。以前,这些经验更多掌握在一线的采购经理手里,同时各个采购经理掌握的也都是一份残缺的进货渠道和价格表。以为市场是最物美价廉的商品,是很难让一个采购经理全部掌握的。永辉超市的 IT 部门,用帆软数据分析平台,搭建了一套全集团的供应商信息共享系统和销售情报分享系统,将全国各子公司的内部进货价格和对外销售情况匹配不同权限,分层次的对各个门店公开。这样每个门店就可以再重新装修和人员扩张的情况下,通过选择合适进价的供货商以及销量较高的品类和品牌,直接将单个门店毛利率提升了3个百分点,有的门店甚至阶段性的提高810个百分点。IT 系统的建设,确实是可以为企业降本增效的,所以 IT 部门,完全可以成长为企业的机会管理中心。这其中最要变革的,是 IT 人的思维与头脑,是管理者的视野与格局。1.5 IT 系统,是解决人与机器矛盾的有效方案,让人从机械劳动中更多解放这是个有趣的话题了,值得多做一些外延探讨了。之前大数据、人工智能概念流行于报,媒体大肆渲染其神奇,甚至开始担心人工智能取代人。比如说富士康引进机械臂,将导致某某工厂十万员工下岗;比如人工智能引入财务领域,将导致中低端财务人才无处求职;比如大数据分析引入金融银行保险风控系统,极大地影响了精算师、传统风控计算的人员的地位。说来或许好笑,或许显得我这个外行无知。我们人与机器的差别之一,不就是人会自主思考,擅长创造性的劳动吗?而机器更擅长的是有规则的重复性操作。当人类学会制造使用核桃夹(像钳子一样能轻松夹开核桃的工具)时,或许用不上了锤子以及其他的力气大的男人手掰核桃。但这些人被解放出来,去开发设计电梯了呀,是不是让你更方便了呢。再来个企业经营中的例子。曾有一个传统制造业企业,内部管理很是严格,采用的也是金字塔管理体系。员工申请、物料审批、产品进出厂,都需要层层签字确认。比如这批货品只能从 A 大门出,并且需要张三领导和王五领导签字,而另一批原理智能从 B 大门进,并且需要赵二和丁四领导签字。一天下来,为了原料货品的进出,底下员工要不断找各个领导签字确认,领导忙于各个车间生产,员工不得不追着领导签字,同时门卫不断通过内部电话核对。大量的时间被消耗在不断的签字确认、电话核查的过程中。玩笑点说,一代人的芳华或许因此而耗尽。不过,2016年有了转机,集团 IT 部门引进了帆软数据平台, IT 部门基于此平台开发了请假流程、审批流程、数据分析系统,因为是个性化的需求,而且经常随着生产需要而变动,市面上没有现成的系统支持。这套 IT 系统帮助这个集团将审批效率提高了20倍。基本上之前需要半天到一天审批下来的流程,现在只需要25分钟的手机操作,就走完所有的流程。让员工和领导极大地提高了效率,解放了自己。当然也解放了门卫哈,因为门口再也不见堵车的队伍和争吵的同事了。这里面,其实还有更高的价值,企业进出物料,快速审批,这是提高企业的执行效率啊。如果和同行对比,就像是中世纪的两个人在比枪决斗。 这扣动扳机的快与慢之间,决定的是两个人的生死。我们聊到这里,其实暗含一个假设:整个社会是不断进步的,而每个人也是不断学习更新的。所以,如果某个人或者某个群体想放慢学习的脚步,甚至停下来,确实会在社会大潮中“落伍”,也就是担心自己“下岗”或者被迫接受企业“裁员”。如果我们跳出这个“悲伤”,我们应该都能看到,IT 系统,为解决人与机器的矛盾迈进了一大步,让更多人从机械劳动中解放出来。挑战!怎么确定企业利润的变化和IT建设有直接关系?前面呢,聊了挺多 IT 的价值,说来说去,都是在推销一个理念“IT 建设价值巨大”,那这个“大”究竟有“多大”呢?其实笔者也每个出确切答案,只是提供了从不同的维度和视角来衡量审视这个“大”。笔者这里正在调研一些价值量化的思路,也希望能和大家多多交流,这里我做了个分解图,大家可以从文末看到。总体来说,量化的思路就是先积累原始数据,让相关提出需求的部门给出他们认可的量化维度和大致的量化标准,然后根据市面上的专家意见对其进行调整,最终形成一个企业内部可以执行的起来的量化模型。简单粗暴点理解的话,可以先按照这个公司的经验来执行。在需求评估阶段,1,在不改变业务流程和工作流程的前提下,算出节省的人力和时间,这个是可以精确到月节省工资支出的2,不改变成本支出的前提下,算出管理人员节省的管理成本,包含物料和人力的管理,这个也是可以按照月工资/月工作小时来精确的,我们主要做公司内部的业务开发,所以从节约上考虑,节省金额必须写进需求文档里的,否则不开发。对,我们 IT 人,就要开始这么牛气起来!挑战!怎么确定企业利润的变化和IT建设有直接关系?转自:https://www.toutiao.com/i6501… ...

March 29, 2019 · 1 min · jiezi

在Vue中使用表单按钮

在tag <form>内部使用<button>,会导致:首次点击内部button按钮会刷新页面。(可以注意到url会新增一个"?“号)可以使用<input type=“button”>代替。或者在<form>外部使用button(不建议这样操作,不符合HTML语义)关键词:vue、form、@click、首次点击刷新页面

March 27, 2019 · 1 min · jiezi

基于webpack下在vue中使用scss,背景图片的使用

在scss设置背景图片(background-image),在项目webpack打包后,图层路径会增加css文件夹所在路径。我们希望的情况下,背景图路径应为’static/img/imgname.png’,而实际则会出现:‘static/css/static/img/imgname.png’,注意,这里static/css是多余的。解决方法有2个:1.在template中直接设置style=“background-image:url(’’)";2.在webpack配置文件夹找到utils.js,作以下更改:增加publicPathif (options.extract) { return ExtractTextPlugin.extract({ use: loaders, //增加publicPath publicPath: ‘../../’, fallback: ‘vue-style-loader’ })}

March 26, 2019 · 1 min · jiezi

上云端运维打破孤岛式管理服务器

这是2019年linux运维市场的一个变革,也是新一轮技术突破.2019年之前很多linux运维人员还在使用传统的linux面板运维服务器,在服务器敲击安装代码,上服务器配置才能启动管理链接地址,服务器被黑,被恶意登陆也是事后才知道,这里就凸显了一个问题,现在国内所有的服务器都是单线单机运维,安全和管理隐患很大. 现在很多企业和个人把网站或服务搬上互联网,其中的载体云服务器,就需要多方面的管理和运维,尤其是批量化操作,集群式管理多台服务器时,这时候”云端运维”就比较有市场需要. 各个云服务器厂家已经意识到这一步,比如腾讯云有针对企业级大用户开发的PAAS平台,通过云端运维来管理批量化的管理云服务器. 云端融合是”云端运维”的第一步,现在市场上已经有厂家针对这样的需求有产品推出,有别于传统单机ip地址化管理云服务器,这家厂家采用云端SAAS化管理模式,通过平台吧云服务器添加进控制台,进行批量或单独的管理运维,这家厂商未来不可限量.厂商的产品名称为旗鱼云梯,网址:www.marlinos.com,毕竟自动化运维先做到的就是让IT运维人员配置和操作服务器做的简单,缩短开发中维护方面的难度和时间. 只有让运维人员做到使用简单,云端操作,工具可以集群管理和批量使用,那么这个平台将是以后的趋势,是运维市场一个变革,是脱离传统运维模式的一种革命.

March 26, 2019 · 1 min · jiezi

PDF转CAD手机也可以快速进行转换吗?

PDF转CAD手机也可以快速进行转换吗?当然也是可以的得啦,毕竟现在CAD相关的计技术的应用那么广泛,相对应的相关的各项应用也在不断的升级完善,那现在运用的最广泛的手机就更不用说了,怎么快速的在手机上将接受到的PDF图纸文件快速转换成其他的格式?其实方法也很简单,只需要手机安装一个相关的CAD转换器app就可以快速完成转换格式了,那么下面小编就给大家具体的演示一下流程,希望可以对大家有所帮助哦!步骤一:首先需要进行打开的是你们手机上面的迅捷CAD转换器,手机上面没有这款软件的,可以在我们的手机上找到并打开手机应用市场,搜索“迅捷CAD转换器”,找到对应APP后,点击下载到手机桌面上即可。或者是我们直接点击任意浏览器点击搜索关键词也是可以实现安装下载的。步骤二:完成软件下载后将其安装到你们的手机桌面上就可以进行操作使用,打开进行入软件的首页面!进入转换的主界面,我们可以看到四个主要CAD转换功能,这里我们直接点击选择PDF转CAD即可。步骤三:点 击【PDF转CAD】功能进入,软件会自动检索手机中的所 有的CAD图纸,比如dwg、dxf等格式,那么我们一般接收到的图纸文件的话,只要下载,都是在 【Tencent—micromsg—download】中,我们找到并选择需要转换的CAD图纸。或者是在全部文件中自己查找即可。步骤四:选择好需要转换的图纸后,点 击【开始转换】即 可进入转换状态。软件进入转换状态,稍等一下,PDF转CAD就快速转换完成。PDF转CAD手机也可以快速进行转换哦,要是还有什么其它的需要了解的教程的话,直接点击【迅捷官网http://www.xunjiecad.com/help…】就可以查询跟多相关咨询哦!

March 25, 2019 · 1 min · jiezi

企业如何选择数据分析架构?——谈谈3种架构的利弊

在之前的文章《讲透大数据,我只需要一顿饭》里,我用做饭这件大家身边的事情来介绍了大数据及数据分析工程,应该能够让大家对数据分析这件看上去很专业的行业有了一定的认识,很高兴的是文章也得到了很多数据圈专业人士的共鸣和互动。这篇文章我们会顺着之前的思路,稍微深入一点,聊聊数据分析架构。什么叫数据分析架构,说的通俗点,其实就是数据采集(买菜)、数据建模(配菜)、数据加工(炒菜)、数据分析(吃菜)这些数据分析流程应该如何划分功能模块(专业化分工),才能方便灵活、规模化、最大化的满足广大数据消费者(吃货)的数据分析(美食)需求。就好比吃饭这件事,我们可以自己在厨房里做,去饭店吃,或者叫外卖等不同方式,这几种吃饭方式是人类生活方式的一种进化,更是通过不同的专业化分工满足了吃货们不同时期、不同层次的需求。而数据分析作为一件相对来说比吃饭更专业的事情,也同样需要通过流程设计和专业化分工来满足更广泛的数据消费需求,我们通常叫做架构设计。闲话少说,先直接上图,我把迄今为止的数据分析架构的历史简单分为三个阶段:企业如何选择数据分析架构?——谈谈3种架构的利弊数据分析1.0阶段:业务报表这个阶段是数据分析的初始阶段。随着数据库技术的出现,企业纷纷开始信息化建设,业务流程信息化沉淀了大量数字化的业务数据,而数据分析的需求其实大家一直都有,既然有了数据沉淀,通过这些数据进行报表统计和数据分析的需求自然就出现了。1.0阶段,数据分析开始萌芽,数据加工、报表统计都在业务系统里直接进行的(数据产生和数据分析都在同一个系统里进行,所以这个时候还没有数据采集一说)。这就好比自己在家里做饭吃,可以想象,由于食材(数据)、厨房(数据库资源)、手艺(专业能力)等方面的限制,吃饭的体验不会太好,主要满足吃饱(报表统计)的需求。当然现代业务报表有了很大的改变,比如帆软finereport一类的报表工具,可以跨业务系统、跨数据库取数做报表做分析,甚至对接数据集市、数据仓库(接下来我正要说)。企业如何选择数据分析架构?——谈谈3种架构的利弊finereport制作的dashboard数据分析2.0阶段:数据集市由于在业务系统里直接做数据分析体验不好,还可能会影响正常的业务流程,而企业数据分析的需求越来越完善,业务人员自然而然的希望在业务系统之外专门搭建一个用于数据分析的独立新系统,既能用于支持数据分析,又可以不影响正常的业务流程,于是,数据集市应运而生。从数据集市开始,数据分析开始作为一个正式的行业出现,出现了从业务系统到数据集市的数据采集和传输(买菜)需求,另外,数据加工,数据分析等专业岗位和从业人员开始出现。这就好比饭店的出现使得在吃饭这件事上出现了专业化分工,同时也开创了餐饮行业。饭店里有人专门买菜,配菜,炒菜,大厨开始出现,这一方式很好的满足了广大吃货在省事、美食选择、口感方面的需求,体验自然是棒棒的。数据分析2.5阶段:数据仓库随着企业数据分析活动如火如荼的开展,数据集市开始越建越多,同样的数据加工逻辑、指标等难免在分散的数据集市里被重复计算,浪费计算资源不说,经常就会出现数据统计口径不一致的问题,让领导们不知道自己该相信哪个数据。这就好比饭店开的多了,同样的菜品在不同的饭店里难免会雷同,但是同一个“鱼香肉丝”不同饭店做出来的的口味难免会不一样,吃货们肯定会迷惑哪家才是最正宗的,也希望知道哪个才是最好吃的。这个时候,数据仓库概念应运而生。数据仓库为了解决数据集市分散建设带来的数据不一致、重复计算浪费资源等问题,提倡以一个集中式平台来统一进行数据采集、数据清洗、数据加工,并且向外部提供各种数据分析产品和服务。数据仓库算是开创了数据分析史真正意义上的一个时代,对数据分析行业的发展和成熟有着不可磨灭的贡献:诞生了专门的数据仓库技术(MPP,massively parallel processing)以及一大批相关的专业厂商,来解决大量数据需要集中进行存储、加工和分析的技术难题发展了体系化的数据仓库系统建设方法论和最佳实践培养了一大批数据仓库从业人员(DWer)既然,数据仓库时代在数据分析史上有着如此重要的地位,并且在今天仍然有着深远的影响,那么,问题来了。为什么数据仓库阶段只是2.5而不是3.0呢?首先,从架构的角度来看,个人认为数据仓库相对于数据集市并没有本质的区别,这个从上面的“数据分析架构发展的三个阶段”图中也能看出来,数据集市和数据仓库的架构是非常相似的,数据仓库可以简单的认为是一个超级数据集市,区别只在于规模,这就好比为了规范菜品质量,让大家能够一站式吃到各种五花八门的菜品,我们开了个超级大饭店,虽然这个饭店很大,但仍然是个饭店。其次,数据仓库以解决数据集市数据分散、数据口径不统一为目标,提出了打造企业级统一业务视图的愿景(The single view of business ),其建设方法强调数据采集规范化,数据管理标准化以及数据加工流程化,这种建设思路从数据管理的角度来说是非常有价值的,产出了很多成熟的数据管理规范和数据治理方法论。但……是……从数据分析的角度来看,虽然数仓系统的建设的确一定程度上满足了业务部门的数据分析需求,然而,传统数据仓库建设方法在灵活的支持各种数据需求、敏捷的响应分析请求、普及企业数据驱动的分析文化方面,却始终心有余而力不足。造成这种情况,虽然有着技术、成本方面的原因,但架构耦合性高、建设方法过于僵化也是重要原因,比如:数据仓库集中式的平台架构方式,将数据加工和数据服务都通过一个平台来支持,必然会造成资源竞争,无法兼顾。这就好比一个饭店里,后厨占得地方太大,堂食的空间就小了,能够同时响应的消费者数量必然受到限制。数据仓库的数据加工是层层递进、环环相扣的方式,有着严格的加工流程,并且涉及到多个角色的互相配合,任何一个数据分析需求,从需求的提出到最终实现,快的要好几周,慢的要好几个月,自然是跟不上业务的快速变化。客户到了饭店,只要是想点个菜单上没有的菜品,饭店都需要把买菜、洗菜、配菜、炒菜这些环节都走一遍,上菜起码得等2、3个小时甚至是第二天才有,没有哪个消费者能忍受的了吧。很多数仓采用数据驱动的建设方式,不管是不是需要的数据,先往仓库里放,总觉得以后会用的上,导致仓库规模极速膨胀,并且存在大量无产出数据,运维成本和难度非常大。就好像开个饭店不管客人喜欢吃什么,先把能买到的菜都买来,抛开成本不说,光是运输、清洗、仓储的工作量就能把人给耗死。数仓建设有着成熟完善的数据治理配套理论,什么元数据管理、数据标准管理、数据质量管理等等,但是这些理论的落地往往最走变成了一纸规范,却没法和数据仓库建设过程有机的结合,最后变成了你定你的规范,我建我的系统,或者是我先建系统,你再定规范,随着系统越来越庞大,没人能够很清楚的知道仓库里到底有什么,整个数仓自然就变的难以管理和使用。于是,虽然数据仓库进行了数十年的发展,很多企业也是花了大量的人力和成本来进行数据仓库系统的建设,但缺乏敏捷性的平台建设方式,自主选择少,服务响应慢,各类数据消费者的满意度始终都不高。因此,慢慢的,很多企业中的数据仓库系统,开始变得有点古代皇宫御膳房的味道,汇集各种食材,对于食材、流程、样式有着严格的加工规范,充分保证了菜品的质量和水准,但是其上菜速度、翻台率以及能够服务的食客数量都受到了极大的限制,所以只有能力为特定群体(皇家)提供各种特定的菜品。企业如何选择数据分析架构?——谈谈3种架构的利弊所以,虽然数据仓库对于数据存储、数据采集、数据加工、数据治理这些方面发展了成熟的方法论(相当于专业的饭店后厨管理理论),但对于满足各种灵活、敏捷、普及的数据分析需求,其作用一直是被诟病的。而进入到今天的大数据时代,这个弊病就更加的明显。大数据浪潮带来的挑战不仅仅是数据量的爆发式增长,更重要的是把个人、企业、政府对数据、数据分析的重视性提升到了前所未有的高度,整个社会对数据分析的需求也呈现爆发式的增长。所以,Gartner提出了平民数据科学家(citizen data scientist)的概念,更有厂商和业内大牛喊出了“人人都是数据分析师”的口号。企业如何满足成千上万的内部员工对于数据分析的需求?企业如何满足千万级以上的外部客户对于数据分析的需求?政府如何满足上亿的社会大众对于数据分析的需求?这成了大数据时代的数据架构师们需要去回答的问题。可以说,用户日益增长的数据分析需求与落后的数据服务能力之间的矛盾已经成为大数据时代的主要矛盾。所以,数据仓库强调数据加工流程而忽视数据服务效率,过于严苛、繁琐的建设方法,数据开发与数据治理脱节的问题,使得其难以快速进行规模化扩展,也就无法应对爆发式的数据分析和数据服务需求,抛开技术、成本上的限制不说,传统数仓的建设方法论显然也是无法解决大数据时代的主要矛盾的。那,大数据时代,大数据分析架构的出路在哪呢?什么样的数据平台建设方法才是最有效的?是否可以在数据仓库成熟的建设方法论上进行改造来应对爆发式的数据分析需求?转自:https://www.toutiao.com/i6580…

March 25, 2019 · 1 min · jiezi

怎样做高质量的财务数据分析?难道你只用excel ?

在制作财务分析前,首先要站在领导老板们的角度考虑他们想看到什么样的财务汇报!是密密麻麻的数据列表吗?是抽象的统计公式吗?是繁琐的数据来源吗?以上都不是!老板们真正关心的是能直观体现企业的经营状况:盈利能力、营运能力、偿债能力、发展能力的财务分析报表。先贴出三张根据不同商业需求做出的可视化财务分析报表,其通过多维度、全方面的可视化图表,让领导们快速准确的掌握公司运营现状,为公司未来风险控制和财务决策提供有效依据!财务相关重要指标公司营收情况集团经营全貌数据查询的报表那么如何做出上述三种高质量财务分析报表呢?1、看菜下碟做分析首先,你的财务分析要想引起老板领导们的兴趣,就要站在他们的立场出发,来分析数据。2、可视化表达报表数据能用一张图表达清楚数据信息的,尽量不要用密密麻麻的数字表。如下公司资产负债表。显然上图更能一目了然看清楚结构,避免了研究。3、搭建成经营驾驶,以便及时监控如开头提到的4张驾驶舱报表。4、用听得懂的语言汇报领导/老板关注的数字财务ers总是习惯用会计科目和语言还有一些财务比率去说明一个问题,没有注意和领导沟通的共同语言。时间长了领导听不懂,会计人员也不愿意再说了,慢慢就造成了沟通上的障碍,一点点的会对会计的工作不利,做的许多事情他听不懂,工作就不会得到领导的理解和赞同。所以,要用通俗的话和领导沟通。如果领导是讲究逻辑的,那汇报时要讲究123;如果领导讲究理解,那你的汇报就要有描述性,把事说清楚。举个例子,本人的曾经的一个领导就是一位农学博士,对折旧这个事情理解不了,他认为我的钱已经支出了,怎么还有提取折旧呢,这不是重复的支出了。其实是不懂权责发生制,银行存款的支出不等于会计上的支出,固定资产的支出是要分期慢慢从利润中列支的,这是两个标准,两个思路。因此要有针对性的和领导沟通,要知道他存在哪些盲点,给领导讲明白,其次能用简单通俗的话把会计说明白。比如现金银行存款就不用说了可以统称为现金或者钱,应收账款和其他应收款就是和销售产品直接相关和间接相关的事,把这些科目都说成欠款,把科目都翻译成生活中的俗语,固定资产你把它说成买的什么设备这个领导很清楚,就更加通俗了。以现金流量为主的视角来阐述通常我们以资产负债表和利润表为主,以现金流量表为辅来说明报表,可能和领导理解报表的有方向性的偏差,要以现金流量表为主,其他两张表为辅的阐述模式,现金流量知未来。从这个视角更能说清企业的运作顾虑和风险所在。许多领导都会问你觉得未来公司的财务问题在什么地方,其实通过现金流量的分析可以知道企业的未来,通过现金流量就可以看出企业创造价值和风险控制的问题,要分析企业现金流的都流向什么地方,现金收入分几类,支出了多少、全年那个月支出的多那个月支出的少,有什么规律性的问题。企业的经营性现金流量各项收支相抵后的净额有多少,有缺口怎么办,能不能找人借的来钱,经营上富裕的现金流是否能够用于扩大再生产和购买一些孳息性财产,输入的现金流肯定是不可靠地,不如自己肌体的造血更好,因此现金流量的经营,投资,筹资的匹配程度的好坏决定了企业是否健康,血液是至关重要的,是决定企业生死的大事。可资产负债表和利润更多的涉及会计假设和会计原则,带有很强的专业性,是利用会计原理计算出来的。资产负债是看你公司的整体问题的,看你这个人是不是整体平衡,是不是一个肩高一个肩低,腿脚是不是有毛病,还能不能够站的稳,蹲的下,坐的好。利润表是看你公司都卖什么东西,与人家有什么不同的地方,你的产品是薄利多销还是厚利少销,你是靠主营业务赚钱还是靠其他业务赚钱,你为了销售产品产生了多少销售费用管理费用,为销售产品产生了多少借款利息,是不是靠变卖家底过日子。这样突出现金流量表将三张报表有机的组合在一起看,就可从内到外立体的分析一个企业的情况了。报表揭示哪些风险财务管理还讲究经营风险和财务风险,什么风险最可怕,就是固定支出越多越可怕,你收到的现金越多就越可靠,像好的产品,供不应求,客户要先付款,我先给你钱产品还没出来就可以收到钱,这是最理想的,连流动资金都不占用这个风险就小多了,因此风险从业务链上分析,才是源头,当你的产品在做定位的时候就决定了你的一些特有风险,如薄利多销的企业,就需要你快周转,当你的存货周转率慢慢再下降,风险就较大了,这个趋势是不好的,就需要要企业详细分析了。报表上的钱都去哪里了领导一看利润表都会问,我这么多利润,可是钱都去哪里了,这就需要你要把权责发生制和现金收付制进行转换,利润是从会计的视角来计算出来的,它带有很多的规定性和主观性,看看现金流量表的附表,盈利增长固然重要,但是真金白银更重要。盈利只是纸上富贵,不是真金白银。从盈利到经营现金流的转换过程就是从纸上富贵到真金白银的过程。现金流量表附表从净利润到到经营活动产生的现金流量净额可以分三步进行调整。第一个调整是非现金调整,它包括摊销、折旧和处置资产的变动的情况,由于会计准则中很多成本与费用都是非现金的,这些非现金的部分需要调整回来。例如如公司购买的软件原价30元钱,按照3年摊销。有些企业的经营性现金流量净额长期大于净利润,说明企业是真的赚到了钱,是其经营实力和经营模式的体现,而且像类金融企业还可以利用别人的钱来发展自己,体现了一种很强的获取现金的能力,但是净利润很高的企业可能非常的缺钱,甚至到了捉襟见肘的境地,甚至其利润是通过从二级市场出售股票获取的收益,或者通过关联往来在控制其现金流量净额的金额,以达到管理中的某些目的,但其无法支持其持续产生现金流量的能力,会昙花一现的,是没有根基的。如果经营现金净流量忽高忽低,没有规律性,也是不正常的,说明企业获取现金的能力也在下降,也是不可持续的,当然如果企业资本支出过度,靠借款来维持其资本的支出也是不可持续的,风险可能是迟早的事情,当然企业情况千差万别,不同行业的企业有不同的特点,需要再细致仔细的分析,现金流量表附表的分析可以提供一个分析企业经营情况的一个入口,因为大部分企业最重要的就是经营性现金流,所以通过现金流量表附表可以很快的抓住企业经营中的要害获取关键信息,找出企业赚钱的能力,迅速的说明领导想要知道的问题。附:上图报表都由 FineReport报表 - 专业的企业级Web报表工具制作

March 19, 2019 · 1 min · jiezi

彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理

本文为“数据生产力大奖赛 - 帆软”参赛案例,未经授权,请勿转载!引言我国传统制造业一直是我国经济发展的支柱型产业,改革开放以来,我国传统制造业一直是以简单粗放、高耗能的劳动密集型的低端生产模式进行运作经营的。在工业4.0的新形态之下,传统的制造业愈加趋向服务型的制造业,从产品的设计生产到销售都由信息网络连接在一起,实行一条龙的服务。这种趋势为制造业提供了从B2C的商业模式到C2B模式的转化,生产形式也从单纯的工厂集中化生产转变为分散化生产,促成了生产地点不固定、生产方式多样化的制造生产新特点。传统的人工信息采集模式已经无法适应碎片化、场景化的信息时代,从而影响公司在未来战略发展上的决策评估,如公司财务预算,风险评估等的时效性和准确度,无法满足公司业务快速发展的需求。那么如何将如今庞大而又复杂的碎片化信息在短时间内变为具有商业价值的信息成为企业在未来长远发展道路上的首要问题!精达股份在这方面有着非常丰富的经验,利用帆软的数据分析工具,建立了一套用于财务和业务分析的可视化管理系统。精达股份有限公司概况铜陵精达特种电磁线股份有限公司为国家重点高新技术企业,是特种电磁线行业的龙头企业(以下简称“精达”)位列全球前三位的特种电磁线制造商1990年2月建厂,目前员工总数2925多人;拥有12个子公司(4个中外合资公司、6个内资子公司、2个贸易公司),1个省级技术中心。在全国制冷压缩机领域,市场覆盖面达80%,市场占有率为35%。已经形成安徽、广东、天津、江苏四大生产基地,产品直接覆盖中国经济最发达的长三角、珠三角和环渤海地区,并有部分产品销往欧洲及东南亚。企业数据分析的"绊脚石"1、市场需求瞬息万变导致数据分析的需求不断发生变更,传统报表开发方式太慢,并且会因为一些简单的BUG造成开发进度不可控,跟不上需求部门大数据分析需求的变更速度;2、公司大部分流程通过人工比对+Excel+文件打印确认实现,浪费大量人力物力;3、公司有12家子公司,产业链多维度,涉及生产到销售即端到端的每个供应环节,大量的扁平化数据信息,人工无法快速高效进行分门别类,很难从大量数据中总结各维度间的逻辑关系,重新发现表观现象下的问题,从而导致公司后期在决策上失误等结果。面对这样的问题,精达股份公司意识到,搭建一个自动化的可视化分析平台,替代人工审核数据,将数据规整成按业务划分的指标、报表,尤为紧迫。精达数据分析建设应用1、应用场景一:财务分析为了做好公司的财务风险评估预测,企业高管需要全局分析企业财务数据。但目前财务信息的填报是由财务人员人工+Excel+文件打印的形式输出,再收集整理上交至财务主管,数据分析效率完全不能满足业务快速发展的需求。于是,用帆软报表搭建如下可视化看板,按照收入、毛利、费用等财务指标划分成不同模块,在一张报表中呈现,点击即可切换。1)集团总体利润概况2)收入分析彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理3)费用分析彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理4)财务指标分析彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理5)销售趋势分析彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理6)单位成本分析公司追产量、保进度、盯销售,而有时会忽视成本,所以精达股份对生产成本单独进行了深度剖析、成本核算,从而实现实时检查、监督考核预算和成本计划的执行情况,依据成本控制绩效以及成本管理水平评价成本管理体系的有效性,发现问题所在,持续进行优化改进,最大程度降低成本。彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理7)账款报表通过对各公司客户的应收账款分析、逾期账款分析、90天以上逾期分析以及销量,帮助改善公司的流动资金周转,减轻短期资金压力,化解潜在的财务风险甚至可以增加公司间的销售能力。彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理2、应用场景二:业务分析业务部门利用高效多维分析工具,可以自由分析各类业务指标,从产品、网点、部门、财务管理等不同纬度挖掘分析数据,如多维盈利分析,可以利用各类图形形象展现某产品在各子公司的分布情况及由哪些客户贡献及该客户的明细数据等。业务人员积极利用该平台获取大量有价值的信息,提升了数据需求的响应速度,减少了报表工作量提高单个人员的工作效率的同时保证单个员工的工作量,增加了基层网点的精细化管理。1)单据整合为物流公司提供数据收集,免去业务人员下工厂手工记录数据的时间,简化业务内容,提高业务能力彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理2)电磁线客户收入排行榜各公司可以查看自己的客户的信息,同比不同客户的销量和收入,减少客户量的异常情况,便于销售管理人员立即发现问题并采取行动。彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理3)人事看板彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理3、应用场景三:大屏展示1)销售大屏丰富且有意义的图形有助于让高管和来访的业务伙伴了解公司业务现状和未来发展计划。彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理2)技术中心实验室实时监测彻底告别“人工+Excel”模式,传统企业实现“一站式”数据化管理最后就整体项目而言,帆软解决了数据的展现和业务流程的管理,可以直连数据库,灵活定制各种复杂表样,做出美观、逻辑清晰的报表。上手操作上,不论是IT人员还是使用者都能很快去操作,让想要的数据触手可及。数据可视化与普通静态图表不同,它可以实时监控风险变化,所以精达鼓励使用者们去探索甚至推翻数据,以发现其他因素,为业务带来更多价值。转自:https://www.toutiao.com/i6665…

March 19, 2019 · 1 min · jiezi

4种灵活的Scss编译输出风格整理

很多人从使用Scss的那一刻起,就被别人告诉了如何编译。所以,基本上也就只会一种命令编译方式。其实Scss提供了4种风格输出CSS,以满足更多人的需求。不同的输出方式如下:嵌套输出方式 nested展开输出方式 expanded紧凑输出方式 compact压缩输出方式 compressed那么,以后就可以随意的使用参数来生成自己喜欢的CSS风格。1、nestednested为嵌套输出风格,即左花括号和CSS类名(第一行)齐行。右侧花括号和最后一行齐行,不换行。此风格一般使用较少,因为正常这样写CSS的人不多,风格比较别扭。编译命令为:sass abc.scss:abc.css –style nested生成结果:.header { background: #f00; color: #000; font-size: 20px; }.sidebar { float: left; width: 300px; height: 500px; }.main { float: right; width: 800px; padding: 20px; min-height: 500px; }2、expandedexpanded为展开输出方式,也是一般前端开发直接写CSS使用较多的一种风格。其左花括号和第一行齐行,不换行。右侧的花括号在结尾处换行,另起一行。编译命令为:sass abc.scss:abc.css –style expanded生成结果:.header { background: #f00; color: #000; font-size: 20px;}.sidebar { float: left; width: 300px; height: 500px;}.main { float: right; width: 800px; padding: 20px; min-height: 500px;}3、compactcompact为紧凑输出方式,也是前端开发直接写CSS使用较多的另外一种方式。其左花括号和右花括号均不换行。花括号内的CSS属性值也不换行,一个接着一个写。对于比较喜欢写单行CSS的朋友十分友好。编译命令为:sass abc.scss:abc.css –style compact生成结果:.header { background: #f00; color: #000; font-size: 20px; }.sidebar { float: left; width: 300px; height: 500px; }.main { float: right; width: 800px; padding: 20px; min-height: 500px; }4、compressedcompressed为压缩输出方式。其所有内容均不换行,而且会删除所有注释和空格。把所有代码压成一团。一般在上线情况,或者完全不用阅读修改CSS文件的情况下使用。文件会比较小。编译命令为:sass abc.scss:abc.css –style compressed生成结果:.header{background:#f00;color:#000;font-size:20px}.sidebar{float:left;width:300px;height:500px}.main{float:right;width:800px;padding:20px;min-height:500px} ...

March 8, 2019 · 1 min · jiezi

全局SASS/SCSS变量在Vue项目中应用解决方案

场景说明// 这是一个存放变量的scss文件 “@/styles/_variables.scss”// color font …$cf-light: #B6B6B6;$cf-gray: #8C8C8C;$cf-med: #505050;$cf-dark: #333333;$cf-highlight: #1775F0;我要在其他文件内都用这个来保证样式统一。比如某个组件<template> <div class=“notice”>注意!</div></template><style lang=“scss” scoped>.notice { color: $cf-highlight;}</style>这样就报错了。要改成下面这样<template> <div class=“notice”>注意!</div></template><style lang=“scss” scoped>@import “@/styles/_variables.scss”;.notice { color: $cf-highlight;}</style>简单描述一下:做Vue项目的时候,有时候我们预先设置了一个主题样式文件(_variables.scss),存放大量的定义的SASS变量,需要在不同的组件中使用,默认是无法使用的,除非每个组件内都引入这个_variables.scss文件,十分麻烦,这里提供几种方案。解决办法我有几个解决方案,理论上都可行,大家不妨根据实际应用场景来实践一下。使用sass-resources-loader如果项目使用Vue-cli 2/3,或者Vue项目用的Webpack,用这个loader都是可以的。官方对于各种场景已经写的很清楚了,请看sass-resources-loader。具体不说明了。Vue-cli 3.x 下的最方便的方案这个我还没实践,不过应该是可行的。。。给小白们自己去试,好用的话记得留言回复下哦打开vue.config.js文件,进行如下配置:module.exports = { css: { loaderOptions: { sass: { data: @import "@/styles/_variables.scss"; } } }};具体细节,请阅读:Globally Load SASS into your Vue.js ApplicationsHow to Import a Sass File into Every Vue Component in an App这两篇原理相同,就是细节上有点不同,怕有的打不开就放两个给大家研究下。Nuxt这里还是接住一个插件style-resources-module,这个最近才出的,高级很多,在他之前,都是用nuxt-sass-resources-loader,如果你的项目还在用旧的,可以换成新的。nuxt-sass-resources-loader官方也说了不在更新维护,建议使用style-resources-module。怎么用呢?这里有Example,我也复制一份,醒目。打开nuxt.config.jsexport default { modules: [’@nuxtjs/style-resources’], styleResources: { scss: [ ‘./assets/styles/_variables.scss’, ‘./assets/styles/mixins.scss’ // use underscore “” & also file extension “.scss” ] }}自己注意文件路径结语现在不用每个组件都写导入变量文件了,是不是轻松多了,也不会因为文件名,路径调整,而胆战心惊的文件批量替换。我为什么写这个文章,因为虽然以前研究过,但是时代变化很快,一些更好的方案出现了,但是很多人依旧采用旧的,可能在新的项目上带来一些问题,所以就更新了。(小字,看不见):其次,我其实在使用easywebpack的egg+vue脚手架遇到了这个问题,搞了半天没搞好。。。去官方群里问没人鸟我,于是凄惨退群(底层技术渣的待遇)。参考:Load a global settings.scss file in every vue component? ...

March 7, 2019 · 1 min · jiezi

CSS预编译是什么?

背景:大厂的任职要求里还有一条是:熟悉使用Sass.Less等CSS预编译工具。学习一样东西的第一步就是首先知道它是什么CSS预编译工具有人开发了一些扩展CSS功能的写法,比如less,sass,其目的是让css能支持一些编程语言才有的功能,比如:表达式,函数,变量,循环,判断.有这些功能就能方便重复定义,写css时省事.举以下例子.var colorRed {color:red}//用var定义一个字体颜色变量样式//定义一个新闻列表样式.news-list{ font-size:12px; line-height:1.76; color:@colorRed; //这里文字颜色引用自变量 var colorRed}上面这段扩展css语言的写法里面有变量,然而浏览器的css解析引擎是不认识css里面的var这些东西的,这就是一个无效的css,所以这些扩展css的语言有预处理器,作用是把上面这段浏览器不认识的代码,还原为浏览器认识的CSS标准发给浏览器解析.如下:.news-list{ font-size:12px; line-height:1.76; color:red;}以上见解参考以下链接,可点击查看.

February 28, 2019 · 1 min · jiezi

【转】SASS用法指南

SASS用法指南 阮一峰的,偏sass用法教程sass入门 偏实战的基础用法

February 27, 2019 · 1 min · jiezi

基于 less,sass,stylus三种预处理rem

一. less形式 //定义一个变量和一个mixin(全局) @fontSizeBase: 75;//基于视觉稿横屏尺寸/100得出的基准font-size .px2rem(@name, @px){ @{name}: @px / @fontSizeBase * 1rem; } //使用示例: .fontsize { .px2rem(fontsize, 750); } //less翻译结果: .fontsize { font-size: 10rem; }二. sass形式 //定义一个变量和一个mixin $fontSizeBase: 75;//基于视觉稿横屏尺寸/100得出的基准font-size @mixin px2rem($name, $px){ #{$name}: $px / $fontSizeBase * 1rem; } //使用示例: .fontsize { @include px2rem(height, 750); } //scss翻译结果: .fontsize { font-size: 10rem; }三. stylus形式 //定义一个变量和一个mixin $fontSizeBase: 75;//基于视觉稿横屏尺寸/100得出的基准font-size px2rem(name, px){ {name}: px / $baseFontSize * 1rem; } //使用示例: .fontsize { px2rem(‘font-size’, 750); } //stylus翻译结果: .fontsize { font-size: 10rem; } ...

February 26, 2019 · 1 min · jiezi

前端_前置处理器

预编译语言CSS的预编译语言:基于CSS语言的语法扩展,支持嵌套的书写,拥有继承机制,SaSSSaaS是对CSS的扩展,允许使用变量,嵌套规则,混合,导入等功能且完全兼容CSS语法.变量: $basiccolor: green;嵌套: ul{padding:0; li {margin:0;}}导入: @import url(’s’);

February 25, 2019 · 1 min · jiezi

vue 配置sass、scss全局变量

下载vue项目下载vue项目就不多说了,大家既然搜索这个标题,肯定不差这一步依赖:1.下载sass-resources-loader执行npm/cnpm install sass-resources-loader –save-dev修改配置打开build文件夹,找到下面的utils文件,找到exports.cssLoaders里的下面这段,将scss配置改成如下形式return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders(’less’), sass: generateLoaders(‘sass’, { indentedSyntax: true }), scss: generateLoaders(‘sass’), stylus: generateLoaders(‘stylus’), styl: generateLoaders(‘stylus’)}把scss项替换成如下形式scss: generateLoaders(‘sass’).concat({ loader:‘sass-resources-loader’, options:{ resources:path.resolve(__dirname,’../src/assets/sass/common.scss’) }}),这里我的common.scss放置了变量文件variable.scss和mixin.scss// mixin.scss@import ‘./variable.scss’;@import ‘./mixin.scss’;重新执行npm run dev 启动服务在vue组件里写上一段试试吧,例如:<style lang=“scss”>#app { font-size: 14px; font-family: “Avenir”, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: $fontMainColor; height: 100%;}.triangle-top{ display: inline-block; @include triangle(bottom, 10px, #ff0000)}.test{ background: #ccc; @include box-shadow(0 0 5px rgba(0,0,0,.3));}</style>

February 20, 2019 · 1 min · jiezi

JavaScript五十问——对比来说CSS的Grid与FlexBox(上篇)

前言春节假期有幸拜读了张鑫旭大大的关于Flex与Grid的两篇文章(见参考文献),很有收获;自己在开发的过程中,很多时候都会采用Flex布局,而Float与inline-box这种方式已经很少使用了;这次在春假期间学习了Grid,深感Grid的好用与便利。趁着这次机会总结一下Grid与Flex的使用。浏览器支持Flex 浏览器支持情况Grid浏览器支持情况可以看出来,相对于Grid来说,Flex无论实在PC端还是移动端都得到了很好的支持,而Grid,在移动端的支持还是差强人意。FlexBox在flex布局中,有两个概念需要谨记:容器与元素。在一个html标签中声明样式:display:flexordisplay:inline-flex即声明了一个flex的容器,在这个容器里面的元素即为flex元素。而flex所有的样式属性分为两类:容器属性与元素属性,他们均作用于flex元素,只不过flex容器中声明的属性统领flex所有元素整体显示与排布方式,而flex元素的属性表示单一元素的排布方式。下面,根据上面脑图的思路,依次介绍flex的属性。声明:下面师范的所有元素都遵从以下HTML结构 和基本样式<style>.container{ height:200px; background-color:#999;}.container >.item{ background-color:#456; width:80px; font-size:30px; color:white; text-align:center;}</style><div class=“container”> <div class=“item”>1</div> <div class=“item”>2</div> <div class=“item”>3</div> <div class=“item”>4</div> …</div>容器属性flex-directionflex-direction顾名思义,是控制flex元素的整体布局方向的,它包括四个属性:1.row //从左到右 默认2.row-reverse //从右到左3.column //从上到下4.column-reverse //从下到上1、flex-direction:row2.flex-direction:row-reverse3.flex-direction:column4.flex-direction: column-reverse上面四个图是分别在容器上(.container)设置flex-direction四个属性得到的效果。flex-wrapflex-wrap是控制元素是换行显示还是单行显示,它共有三个属性1.no-wrap //不换行 默认2.wrap // 换行3.wrap-reverse //换行反序为了更加明显的看出区别,我特别添加了一个难看的边框。在容器属性上添加flex-wrap,分别设置三个wrap属性1.flex-wrap: no-wrap2.flex-wrap: wrap3.flex-wrap: wrap-reverse在这里需要注意no-wrap属性:如果容器元素设置了最小宽度,而且元素的最小宽度之和>父容器的宽度,则显示内容溢出。如果容器元素没有设置最小宽度或者最小宽度之和<父容器的宽度,则容器元素收缩并将父元素填满,在上面no-wrap例子中,就没有设置子元素的最小宽度,读者可以自行添加验证。设置wrap-reverse属性后,我们可以看到它的换行结果与wrap的换行结果在行这一维度上是相反的。读者可以试试将flex-direction设置为column或者其他非默认值,再查看在不同的flex-wrap值下的显示,会有不同的结果哟。flex-flowflex-flow是 flex-direction与flex-wrap的统写,语法是flex-flow:<‘flex-direction’> || <‘flex-wrap’>justify-contentjustify-content控制flex元素水平方向的对齐方式,它共有 个属性:1.flex-start // 默认值 默认情况下左对齐2.flex-end // 右对齐3.center // 居中下面以space开头的属性都是描述剩余空间的排布方式的4.space-around //剩余空间围绕在每个子元素的周围5.space-between //剩余空间只分布在子元素之间,两端元素左右没有剩余空间6.space-evenly // 剩余空间均匀分布在元素两端、之间下面看例子:1.flex-start2.flex-end3.center4.space-between5.space-around6.space-evenly为了更加明显的看出不同space下的额外空间分布特点,我使用红框框出每一属性下的剩余元素。几个属性分布不同不言而喻了。align-contentalign-content与justify-content对应,代表元素垂直方向上的分布。而这种分布方式只有在多行的情况下才能够凸显出来,单行情况下设置此属性无效。相对于justify-content,它多出来一个stretch的属性,代表拉伸,默认属性。1.stretch2.flex-start3.flex-end4.space-between5.space-around6.space-evenly可以看出,它的排布方式与justify-content的逻辑是一致的,只不过方向不同而已。align-items既然有了多行情况下控制元素排布方式,就会有单行情况下元素排布方式。align-items就是在单行情况下,控制元素排布方式的。共有5个属性:1.stretch 默认属性,会将元素的高度拉伸至父容器的高度2.flex-start 顶部对齐3.flex-end 底部对齐4.baseline 基线对齐5.center 居中注意:以上所有的例子展示都是在其他属性默认情况的显示情况,如果更改其他属性(如:flex-direction 与 flex-wrap)值,会有不同的显示效果。元素属性orderorder属性可以控制flex元素的排布顺序,flex元素会根据order从小到大依次排布,order的默认值为0,因此如果想要某个元素排在前面,只需要将他的order值设为比0小的值即可。flex-growflex-grow控制元素所占宽度,默认值为0,当容器内有剩余空间时,flex-grow不为0的元素将会按照以下规则扩展:容器中只有一个元素设置了flex-grow 1、flex-grow 值>=1 那么这个元素会填充容器的剩余空间.container .item:first-child{ order:2; flex-grow:1;}2、flex-grow 在0-1之间,那么这个元素会多占用空间为剩余空间乘以这个flex-grow的值。.container .item:first-child{ order:2; flex-grow:0.5;}.container{ display:flex; justify-content:space-around;//如果子元素的flex-grow<1,此属性依然有效}.container .item:first-child{ order:2; flex-grow:0.5;}容器中有多个元素设置了flex-grow1、所有元素的flex-grow的值之和>1则占用全部的剩余空间,多占用的剩余空间比例即为各个元素所设置flex-grow的比例。2、所有元素的flex-grow的值之和<1所占用的剩余空间的比例即为各个元素的felx-grow的值的比例。flex-shrinkflex-shrink的属性与flex-grow相反,指的是当空间不足的时候,元素的收缩比例,默认值为1;其核心思路与grow一致,这里不再赘述,读者可以自行检验。flex-basisflex-basis定义了在分配剩余空间之前,每个元素的默认宽度,默认为auto即元素的宽度;当flex-basis的值不为auto时,其显示的优先级是高于元素的width的。flexflex属性为以上三个属性的统称,语法为:flex: none | auto | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ]flex翻译为中文就是弹性的,所以这个属性就是说明当有空间过大or空间不足时,每个元素如何分布。align-selfalign-self顾名思义,就是确定单个元素垂直分布状态;其在父容器对应的属性是algin-items;其属性值有align-items一致,只不过多了一个auto默认属性,表示与父元素的auto-items值一致。来看例子:对应css代码:.container{ display:flex; align-items:center;}.container .item:nth-child(2n+1){ order:2; flex-grow:2; align-self:flex-start;}我在父元素上添加align-items属性,使flex元素居中对齐,在子元素上添加align-self属性,使奇数子元素向上对齐。当有多行的情况下,但是align-content未设置,我们可以看到,每一个设置了align-self属性的子元素会在当前的行按照align-self属性显示,但是当align-content属性设置后,其align-self属性失效(见下图)。对应代码:.container{ display:flex; align-content:center; flex-wrap:wrap;}.container .item:nth-child(2n+1){ order:2; flex-grow:2; align-self:flex-start;}总结flex布局就总结到这里,里面有些类似属性没有举例子,还需要读者自己去验证。相对于其他解决方案,flex布局更加简洁,也更加具有语义性;最显而易见的,可以很方便的解决我们平时面试过程中遇到的多栏布局,垂直居中问题。其实细细品读flex,相比于Grid而言,他还是更加线性化,就是把所有的元素都看成一条线,确定这条线的方向、居中垂直方式,当这条线超过父元素的范围,我们怎样处理。所以,虽然flex看似有许多属性,但是合理的理解后,还是非常简单的。这篇是glex与Grid的上篇,主要介绍了flex,而Grid的相关属性与应用,我们下篇见。参考文献张鑫旭:写给自己看的display: flex布局教程阮一峰:Flex 布局教程 ...

February 17, 2019 · 1 min · jiezi

大话css预编译处理(三):基础语法篇

一、Sass、LESS和Stylus的语法每一种语言都有自己一定的语法规则,CSS预处理器语言也不例外,在真正使用CSS预处器语言之前还有一个不可缺少的知识点,就是对语法的理解。值得庆幸的是,这三款CSS预处理器语言的语法和CSS语法都差不多。1.Sass语法Sass3.0版本开始使用的是标准的CSS语法,和SCSS可以说是一样的。这样Sass代码转换成CSS代码变得更容易。默认Sass使用.scss扩展名。Sass语法规则可以像CSS那样书写:/style.sass新版语法规则/h1{ color:#936; background-color:#333;} 正如你所看到的,在Sass样式中,这样的代码是在简单不过的了。重要的一点是,Sass也同时支持老的语法,老的语法和常规的CSS语法略有不同,他需要严格的语法,任何的缩进和字符的错误都会造成样式的编译错误。Sass可以省略大括号({})和分号(;),完全依靠严格的缩进和格式化代码,而且文件使用.sass扩展名,他的语法类似于:/style.sass/h1 color:#936 background-color: #3332.LESS语法LESS是CSS的一种扩展形式,它并没有阉割CSS的功能,而是在现有的CSS语法上,添加了很多额外的功能。就语法规则而言,LESS和Sass一样,都是使用CSS的标准语法,只是LESS的源文件的扩展名是.less,其基本语法类似于:/style.less/h1 { color: #963; background-color: #333;}3.Stylus语法Stylus的语法花样多一些,它的文件扩展名是.styl,Stylus也接受标准的CSS语法,但是他也像Sass老的语法规则,使用缩进控制,同时Stylus也接受不带大括号({})和分号的语法,如下所示:/style.styl//类似于CSS标准语法/h1 { color: #963; background-color:#333;}/省略大括号({})/h1 color: #963; background-color: #333;/省略大括号({})和分号(;)/h1 color:#963 background-color:#333在Stylus样式中,你也可以在同一个样式文件中使用不同的语法规则,下面这样的写法也不会报错:/style.styl/h1 { color #963}h2 font-size:1.2em 二、 Sass、LESS和Stylus特性这三款CSS预处理器语言具有一些相同的特性,例如:变量、混入、嵌套、函数等。在这一节中,我们依次来对比一下这三款CSS预处理器语言各种特性的异同之处,以及使用方法。1.变量(Variables)如果你是一个开发人员,变量应该是你最好朋友之一。在CSS预处理器语言中你也可以声明变量,并在整个样式表中使用。CSS预处理器语言支持任何变量(例如:颜色、数值、文本)。然后你可以在任意地方引用变量。a)Sass的变量Sass声明变量必须是“$”开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号(:)分隔开。就像CSS属性设置一样:/声明变量/$mainColor: #963;$siteWidth: 1024px;$borderStyle: dotted;/调用变量/ | /转译出来的CSS/——————————————+——————————body { | body { color: $mainColor; | color: #963; border:1px $borderStyle $mainColor; | border:1px dotted #963; max-width: $siteWidth; | max-width: 1024px;} | } b) LESS的变量LESS样式中声明变量和调用变量和Sass一样,唯一的区别就是变量名前面使用的是“@”字符:/声明变量/ @mainColor: #963; @siteWidth: 1024px; @borderStyle: dotted; /调用变量/ | /转译出来的CSS/ —————————————-+——————————- body { | body { color: @mainColor; | color:#963; border:1px @borderStyle @mainColor; | border:1px dotted #963; max-width: @siteWidth; | max-width:1024px; } | } c)Stylus的变量Stylus样式中声明变量没有任何限定,你可以使用“$”符号开始。结尾的分号(;)可有可无,但变量名和变量值之间的等号(=)是需要的。有一点需要注意的是,如果我们使用“@”符号开头来声明(0.22.4)变量,Stylus会进行编译,但其对应的值并不会赋值给变量。换句话说,在Stylus中不要使用“@”符号开头声明变量。Stylus中调用变量的方法和LESS、Sass是完全相同的。/声明变量/mainColor = #963;siteWidth = 1024px;$borderStyle = dotted;/调用变量/ | /转译出来的CSS/—————————————-+——————————–body | body { color mainColor | color: #963; border 1px $borderStyle mainColor | border:1px dotted #963 max-width siteWidth | max-width:1024px; | } Stylus还有一个独特功能,不需要分配值给变量就可以定义引用属性:/水平垂直居中/ | /转译出来的CSS/————————————+————————————#logo | #logo { position absolute | position:absolute; top 50% | top:50%; left 50% | left:50%; width w = 150px | width:150px; height h = 80px | height:80px; margin-left -(w / 2) | margin-left:-75px; margin-top -(h / 2) | margin-top:-40px; | } 从上面的代码中我们可以看出,CSS预处理器语言中的变量是值级别的重复使用,可以将相同的值定义成变量统一管理起来。CSS预处理器语言中变量的特性适用于定义主题(也就是我们常说的换肤),我们可以将背景颜色、字体颜色、边框属性等常规样式统一定义,这样不同的主题只需要定义不同的变量文件就可以。2.作用域(Scope)CSS预处理器语言中的变量和其他程序语言一样,可以实现值的复用,同样它也存在生命周期,也就是Scope(变量范围,开发人员习惯称之为作用域),简单点讲就是局部变量还是全局变量的概念,查找变量的顺序是先在局部定义中找,如果找不到,则查找上级定义,直至全局。下面我们通过一个简单的例子来解释这三款CSS预处理器的作用域使用。a)Sass的作用域Sass中作用域在这三款预处理器是最差的,可以说在Sass中是不存在什么全局变量。具体来看下面的代码:/Sass样式/$color: black;.scoped { $bg: blue; $color: white; color: $color; background-color:$bg;}.unscoped { color:$color;} 先看转译出来的CSS样式:.scoped { color:white;/是白色/ background-color:blue;}.unscoped { color:white;/白色(无全局变量概念)/} 示例明显的告诉我们,在Sass样式中定义变量,调用变量是没有全局变量一个概念存在,因此在Sass中定义了相同变量名时,在调用之时千万要多加小心,不然会给你的样式带来错误。b)LESS的作用域LESS中的作用域和其他程序语言中的作用域非常的相同,他首先会查找局部定义的变量,如果没有找到,会像冒泡一样,一级一级往下查找,直到根为止,同样上面的例子,我们来看看他在LESS下所起的变化。/LESS样式/ @color: black; .scoped { @bg: blue; @color: white; color: @color; background-color:@bg; } .unscoped { color:@color; }转译出来的CSS样式:.scoped { color:white;/白色(调用了局部变量)/ background-color:blue;}.unscoped { color:black;/黑色(调用了全局变量)/}c)Stylus的作用域Stylus虽然起步比较晚,但其作用域的特性和LESS一样,可以支持全局变量和局变量。会向上冒泡查找,直到根为止。3.混合(Mixins)Mixins是CSS预处理器中语言中最强大的特性,简单点来说,Mixins可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用。平时你在写样式时肯定有碰到过,某段CSS样式经常要用到多个元素中,这样你就需要重复的写多次。在CSS预处理器语言中,你可以为这些公用的CSS样式定义一个Mixin,然后在你CSS需要使用这些样式的地方直接调用你定义好的Mixin。这是一个非常有用的特性,Mixins被当作一个公认的选择器,还可以在Mixins中定义变量或者默认参数。a)Sass的混合Sass样式中声明Mixins时需要使用“@mixin”,然后后面紧跟Mixins的名,他也可以定义参数,同时可以给这个参数设置一个默认值,但参数名是使用“$”符号开始,而且和参数值之间需要使用冒号(:)分开。在选择器调用定义好的Mixins需要使用“@include”,然后在其后紧跟你要调用的Mixins名。不过在Sass中还支持老的调用方法,就是使用加号“+”调用Mixins,在“+”后紧跟Mixins名。一起来看个简单的例子,比如说在你的Sass样式中定义了一个名叫“error”的Mixin,这个“error”设置了一个参数“$borderWidth”,在没特别定义外,这个参数的默认值设置为“2px”:/声明一个Mixin叫作“error”/@mixin error($borderWidth:2px){ border:$borderWidth solid #f00; color: #f00;}/调用error Mixins/.generic-error { @include error();/直接调用error mixins/}.login-error { @include error(5px);/调用error mixins,并将参数$borderWidth的值重定义为5px/} b)LESS的混合在LESS中,混合是指将定义好的“ClassA”中引入另一个已经定义的“Class”,就像在当前的“Class”中增加一个属性一样。不过LESS样式中声明Mixins和Sass声明方法不一样,他更像CSS定义样式,在LESS可以将Mixins看成是一个类选择器,当然Mixins也可以设置参数,并给参数设置默认值。不过设置参数的变量名是使用“@”开头,同样参数和默认参数值之间需要使用冒号(:)分隔开。正如Sass混合是的示例,同样在LESS样式中定义一个名叫“error”的Mixin,这个“error”设置了一个参数“@borderWidth”,在没有特别定义外,这个参数的默认值是“2px”:/声明一个Mixin叫作“error”/.error(@borderWidth:2px){ border:@borderWidth solid #f00; color: #f00;}/调用error Mixins/.generic-error { .error();/直接调用error mixins/}.login-error { .error(5px);/调用error mixins,并将参数@borderWidth的值重定义为5px/} c)Stylus的混合Stylus中的混合和前两款CSS预处理器语言的混合略有不同,他可以不使用任何符号,就是直接声明Mixins名,然后在定义参数和默认值之间用等号(=)来连接。/声明一个Mixin叫作“error”/error(borderWidth=2px){ border:borderWidth solid #f00; color: #f00;}/调用error Mixins/.generic-error { error();/直接调用error mixins/}.login-error { error(5px);/调用error mixins,并将参数$borderWidth的值重定义为5px/}三个示例都将会转译成相同的CSS代码:.generic-error { border: 2px solid #f00; color:#f00;}.login-error { border:5px solid #f00; color: #f00;} 4.嵌套(Nesting)CSS预处理器语言中的嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而减少代码量,并且增加了代码的可读性。比如说,我们在CSS中多个元素有一个相同的父元素,那么写样式会变得很乏味,我们需要一遍一遍的在每个元素前写这个父元素,除非给特定的元素添加类名“class”或者ID。section { margin:10px;}section nav { height:25px;}section nav a { color: #0982c1;}section nav a:hover { text-decoration: underline;} 相反,使用CSS预处理器语言的嵌套特性,我们可以在父元素的大括号({})里写这些元素。同时可以使用“&”符号来引用父选择器。对于Sass、LESS和Stylus这三款CSS预处理器语言的嵌套选择器来说,他们都具有相同的语法:section { margin:10px; nav { height:25px; a { color:#0982c1; &:hover { text-decoration:underline; } } }} 上面的预处理器转译出来的CSS代码和我们开始展示的CSS代码是相同的,非常的方便吧!5.继承(Inheritance)对于熟悉CSS的同学来说,对于属性的继承并不陌生。平时在写CSS样式常碰到多个元素应用相同的样式时,我们在CSS中通常都是这样写:p,ul,ol{/样式写在这里/}这样做非常的好,但往往我们需要给单独元素添加另外的样式,这个时候我们就需要把其中选择器单独出来写样式,如此一来我们维护样式就相当的麻烦。为了应对这个问题,CSS预处理器语言可以从一个选择继承另个选择器下的所有样式。a)Sass和Stylus的继承Sass和Stylus的继承是把一个选择器的所有样式继承到另个选择器上。在继承另个选择器的样式时需要使用“@extend”开始,后面紧跟被继承的选择器:.block { margin: 10px 5px; padding: 2px;}p { @extend .block;/继承.block选择器下所有样式/ border: 1px solid #eee;}ul,ol { @extend .block; /继承.block选择器下所有样式/ color: #333; text-transform: uppercase;} 上面的代码转译成CSS:.block,p,ul,ol { margin: 10px 5px; padding:2px;}p { border: 1px solid #eee}ul,ol { color:#333; text-transform:uppercase;} b)LESS的继承LESS支持的继承和Sass与Stylus不一样,他不是在选择器上继承,而是将Mixins中的样式嵌套到每个选择器里面。这种方法的缺点就是在每个选择器中会有重复的样式产生。.block { margin: 10px 5px; padding: 2px;}p { .block;/继承.block选择器下所有样式/ border: 1px solid #eee;}ul,ol { .block; /继承.block选择器下所有样式/ color: #333; text-transform: uppercase;}转译出来的CSS代码:.block { margin: 10px 5px; padding:2px;}p { margin: 10px 5px; padding:2px; border: 1px solid #eee}ul,ol { margin: 10px 5px; padding:2px; color:#333; text-transform:uppercase;}正如所看到的,上面的代码“.block”的样式将会被插入到相应的你要继承的选择器中,但需要注意的是优先级的问题。6.运算符(Operations)CSS预处理器语言还具有运算的特性,其简单的讲,就是对数值型的Value(如:数字、颜色、变量等)进行加减乘除四则运算。这样的特性在CSS样式中是想都不敢想的,但在CSS预处理器语言中对样式做一些运算一点问题都没有了,例如:@base_margin: 10px;@double_margin: @base_margin * 2;@full_page: 960px;@half_page: @full_page / 2;@quarter_page: (@full_page / 2) / 2; 上面代码是LESS的运算示例,声明一下,在取得“@quarter_page”变量时,我们可以直接除以4,但是在这里,我们只是想演示一下圆括号组成的“运算顺序”(这个运算顺序小学生也知道)。在复合型运算中,小括号也是很有必要的,例如:border: (@width / 2) solid #000;Sass在数字运算上要比LESS更专业,他可以直接换算单位了。Sass可以处理无法识别的度量单位,并将其输出。这个特性很明显是一个对未来的尝试——证明W3C作出的一些改变。Stylus的运算是三款预处理器语言中最强大的一款,他拥有其他程序语言一样的运算功能,简单点的加减乘除,复杂的有关系运算、逻辑运算等。受限于篇幅,感兴趣的同学可以到官网上仔细阅读。7.颜色函数颜色函数是CSS预处理器语言中内置的颜色函数功能,这些功能可以对颜色进行处理,例如颜色的变亮、变暗、饱和度控制、色相控制,渐变颜色等处理十分的方便。a)Sass颜色函数lighten($color, 10%); /* 返回的颜色在$color基础上变亮10% /darken($color, 10%); / 返回的颜色在$color基础上变暗10% /saturate($color, 10%); / 返回的颜色在$color基础上饱和度增加10% /desaturate($color, 10%); / 返回的颜色在$color基础上饱和度减少10% /grayscale($color); / 返回$color的灰度色*/complement($color); /* 返回$color的补色 /invert($color); / 返回$color的反相色 /mix($color1, $color2, 50%); / $color1 和 $color2 的 50% 混合色*/这只是Sass中颜色函数的一个简单列表,更多详细的介绍可以阅读Sass文档。颜色函数可以运用到任何一个元素上,只要其有颜色的属性,下面是一个简单的例子:$color: #0982C1;h1 { background: $color; border: 3px solid darken($color, 50%);/边框颜色在$color的基础上变暗50%/} b)LESS颜色函数lighten(@color, 10%); /* 返回的颜色在@color基础上变亮10% /darken(@color, 10%); / 返回的颜色在@color基础上变暗10%/saturate(@color, 10%); / 返回的颜色在@color基础上饱和度增加10% /desaturate(@color, 10%); / 返回的颜色在@color基础上饱和度降低10%/spin(@color, 10); / 返回的颜色在@color基础上色调增加10 /spin(@color, -10); / 返回的颜色在@color基础上色调减少10 /mix(@color1, @color2); / 返回的颜色是@color1和@color2两者的混合色 /LESS的完整颜色函数功能,请阅读LESS文档。下面是LESS中如何使用一个颜色函数的简单例子:@color: #0982C1;h1 { background: @color; border: 3px solid darken(@color, 50%);} c)Stylus的颜色函数lighten(color, 10%); / 返回的颜色在’color’基础上变亮10% /darken(color, 10%); / 返回的颜色在’color’基础上变暗10% /saturate(color, 10%); / 返回的颜色在’color’基础上饱和度增加10% /desaturate(color, 10%); / 返回的颜色在’color’基础上饱和度降低10% / 有关于Stylus的颜色函数介绍,请阅读Stylus文档。下面是Stylus颜色函数的一个简单实例:color = #0982C1h1 background color border 3px solid darken(color, 50%) 从上面展示的部分颜色函数可以告诉我们,Sass、LESS和Stylus都具有强大的颜色函数功能,功能特性上都大同小异,只是在使用方法上略有不同。而且他们都具有相同的一个目的,就是方便操作样式中的颜色值。8.导入(Import)在CSS中,并不喜欢用@import来导入样式,因为这样的做法会增加http的请求。但是在CSS预处理器中的导入(@import)规则和CSS的有所不同,它只是在语义上导入不同的文件,但最终结果是生成一个CSS文件。如果你是通过“@import‘file.css’”导入“file.css”样式文件,那效果跟普通CSS导入样式文件一样。注意:导入文件中定义了变量、混合等信息也将会被引入到主样式文件中,因此需要避免他们的相互冲突。Sass、LESS和Stylus三款CSS预处理器语言,导入样式的方法都是一样:被导入文件的样式:/ file.{type} /body { background: #EEE;} 需要导入样式的文件:@import “reset.css”;@import “file.{type}";p { background: #0982C1;} 转译出来的CSS代码:@import “reset.css”;body { background: #EEE;}p { background: #0982C1;} 9.注释(Comment)CSS预处理器语言中的注释是比较基础的一部分,这三款预处理器语言除了具有标准的CSS注释之外,还具有单行注释,只不过单行注释不会被转译出来。a)Sass、LESS和Stylus的多行注释多行注释和CSS的标准注释,他们可以输出到CSS样式中,但在Stylus转译时,只有在“compress”选项未启用的时候才会被输出来。/ 我是注释/body padding 5px b)Sass、LESS和Stylus的单行注释单行注释跟JavaScript语言中的注释一样,使用双斜杠(//),但单行注释不会输出到CSS中。//我是注释 @mainColor:#369;//定义主体颜色 在Stylus中除了以上两种注释之外,他还有一种注释,叫作多行缓冲注释。这种注释跟多行注释类似,不同之处在于始的时候,这里是”/!”。这个相当于告诉Stylus压缩的时候这段无视直接输出。/!给定数值合体/add(a, b) a + b 上面从九个常用的特性对Sass、LESS和Stylus三款CSS预处理器语言的使用做了对比,在某些特性上可以说是一模一样,而有一些特性上功能其实一样,只是在部分书写规则上有所不同。当然有些特性是完全不同。在这里几是从使用方法上做为一个比较,主要目的是让大家经过对比之后,使自己选择哪一款CSS预处理器语言有所方向和帮助。三、 CSS预处理器的高级应用我们知道,Sass、LESS和Stylus都具有变量、混合、嵌套、函数和作用域等特性,但这些特性都是一些普通的特性。其实除了这些特性之外,他们还拥有一些很有趣的特性有助于我们的开发,例如条件语句、循环语句等。接下来,我们同样从使用上来对比一下这三款CSS预处理器语言在这方面应用又有何不同异同。a)条件语句说到编程,对于编程基本控制流,大家并不会感到陌生,除了循环就是条件了。条件提供了语言的可控制,否则就是纯粹的静态语言。提供的条件有导入、混合、函数以及更多。在编程语言中常见的条件语句:if/else if/else if表达式满足(true)的时候执行后面语然块,否则,继续后面的else if或else。在这三款CSS3预处理器语言中都具有这种思想,只不过LESS中表达的方式略有不现,接下来我们依次看看他们具体如何使用。Sass的条件语句Sass样式中的条件语句和其他编程语言的条件语句非常相似,在样式中可以使用“@if”来进行判断:p { @if 1 + 1 == 2 { border: 1px solid; } @if 5 < 3 { border: 2px dotted; } @if null { border: 3px double; }}编译出来的CSS:p { border: 1px solid; }在Sass中条件语句还可以和@else if、@else配套使用:$type: monster;p { @if $type == ocean { color: blue; } @else if $type == matador { color: red; } @else if $type == monster { color: green; } @else { color: black; }}转译出来的CSS:p {color:green;} Stylus的条件语句Stylus的条件语句的使用和其他编程的条件语句使用基本类似,不同的是他可以在样式去省略大括号({}):box(x, y, margin = false) padding y x if margin margin y xbody box(5px, 10px, true) Stylus同样可以和else if、else配套使用:box(x, y, margin-only = false) if margin-only margin y x else padding y x Stylus除了这种简单的条件语句应用之外,他还支持后缀条件语句。这就意味着if和unless(熟悉Ruby程序语言的用户应该都知道unless条件,其基本上与if相反,本质上是“(!(expr))”)当作操作符;当右边表达式为真的时候执行左边的操作对象。例如,我们定义了negative()来执行一些基本的检查。下面我们使用块式条件:negative(n) unless n is a ‘unit’ error(‘无效数值’) if n < 0 yes else no 接下来,我们利用后缀条件让我们的方法简洁:negative(n) error(‘无效数值’) unless n is a ‘unit’ return yes if n < 0 no 当然,我们可以更进一步。如这个“n < 0 ? yes : no”可以用布尔代替:“n < 0”。后缀条件适合于大多数的单行语句。如“@import,@charset”混合书写等。当然,下面所示的属性也是可以的:pad(types = margin padding, n = 5px) padding unit(n, px) if padding in types margin unit(n, px) if margin in typesbody pad()body pad(margin)body apply-mixins = true pad(padding, 10) if apply-mixins 上面代码转译出来的CSS:body { padding: 5px; margin: 5px;}body { margin: 5px;}body { padding: 10px;} LESS的条件语句LESS的条件语句使用有些另类,他不是我们常见的关键词if和else if之类,而其实现方式是利用关键词“when”。.mixin (@a) when (@a >= 10) { background-color: black; } .mixin (@a) when (@a < 10) { background-color: white; } .class1 { .mixin(12) } .class2 { .mixin(6) } 转译出来的CSS:.class1 { background-color: black; } .class2 { background-color: white; } 利用When以及<、>、=、<=、>=是十分简单和方便的。LESS并没有停留在这里,而且提供了很多类型检查函数来辅助条件表达式,例如:iscolor、isnumber、isstring、iskeyword、isurl等等。.mixin (@a) when (iscolor(@a)) { background-color: black; } .mixin (@a) when (isnumber(@a)) { background-color: white; } .class1 { .mixin(red) } .class2 { .mixin(6) }转译出来的CSS.class1 { background-color: black; } .class2 { background-color: white; } 另外,LESS的条件表达式同样支持AND和OR以及NOT来组合条件表达式,这样可以组织成更为强大的条件表达式。需要特别指出的一点是,OR在LESS中并不是or关键词,而是用,来表示or的逻辑关系。.smaller (@a, @b) when (@a > @b) { background-color: black; } .math (@a) when (@a > 10) and (@a < 20) { background-color: red; } .math (@a) when (@a < 10),(@a > 20) { background-color: blue; } .math (@a) when not (@a = 10) { background-color: yellow; } .math (@a) when (@a = 10) { background-color: green; } .testSmall {.smaller(30, 10) } .testMath1 {.math(15)} .testMath2 {.math(7)} .testMath3 {.math(10)}转译出来的CSS.testSmall { background-color: black; } .testMath1 { background-color: red; background-color: yellow; } .testMath2 { background-color: blue; background-color: yellow; } .testMath3 { background-color: green; } b)循环语句Sass和Stylus还支持for循环语句,而LESS并没支持for循环语句,但值得庆幸的是,在LESS中可以使用When来模拟出for循环的特性。Sass的循环语句Sass中使用for循环语句需要使用@for,并且配合“from”和“through”一起使用,其基本语法:@for $var from <start> through <end> {语句块}我们来看一个简单的例子:@for $i from 1 through 3 { .item-#{$i} { width: 2em * $i; }} 转译出来的CSS代码:.item-1 { width: 2em; }.item-2 { width: 4em; }.item-3 { width: 6em; } 在Sass中循环语句除了@for语句之外,还有@each语句和@while语句@each循环语法:@each $var in <list>{语句块} 来看个简单的实例:@each $animal in puma, sea-slug, egret, salamander { .#{$animal}-icon { background-image: url(’/images/#{$animal}.png’); }} 转译出来的CSS.puma-icon { background-image: url(’/images/puma.png’); }.sea-slug-icon { background-image: url(’/images/sea-slug.png’); }.egret-icon { background-image: url(’/images/egret.png’); }.salamander-icon { background-image: url(’/images/salamander.png’) }@while循环使用和其他编程语言类似:$i: 6;@while $i > 0 { .item-#{$i} { width: 2em * $i; } $i: $i - 2;}转译出来的CSS.item-6 { width: 12em; }.item-4 { width: 8em; }.item-2 { width: 4em; }Stylus的循环语句在Stylus样式中通过for/in对表达式进行循环,形式如下:for <val-name> [, <key-name>] in <expression> 例如:body for num in 1 2 3 foo num 转译出来CSSbody { foo: 1; foo: 2; foo: 3;} 下面这个例子演示了如何使用<key-name>:body fonts = Impact Arial sans-serif for font, i in fonts foo i font 转译出来的CSSbody { foo: 0 Impact; foo: 1 Arial; foo: 2 sans-serif;} LESS的循环语句在LESS语言中并没有现在的循环语句,可是像其条件语句一样,通过when来模拟出他的循环功能。.loopingClass (@index) when (@index > 0) { .myclass { z-index: @index; } // 递归 .loopingClass(@index - 1);}// 停止循环.loopingClass (0) {}// 输出.loopingClass (3); 转译出的CSS.myclass {z-index: 3;}.myclass {z-index: 2;}.myclass {z-index: 1;} 相比之下,Sass和Stylus对条件语句和循环语句的处理要比LESS语言强大。因为他们具有真正的语言处理能力。综上所述,我们对Sass、LESS和Stylus做一个简单的对比总结: 三者都是开源项目;Sass诞生是最早也是最成熟的CSS预处理器,有Ruby社区和Compass支持;Stylus早期服务器NodeJS项目,在该社区得到一定支持者;LESS出现于2009年,支持者远超于Ruby和Node JS社区;Sass和LESS语法较为严谨、严密,而Stylus语法相对散漫,其中LESS学习起来更快一些,因为他更像CSS的标准;Sass和LESS相互影响较大,其中Sass受LESS影响,已经进化到了全面兼容CSS的SCSS;Sass和LESS都有第三方工具提供转译,特别是Sass和Compass是绝配;Sass、LESS和Stylus都具有变量、作用域、混合、嵌套、继承、运算符、颜色函数、导入和注释等基本特性,而且以“变量”、“混合”、“嵌套”、“继承”和“颜色函数”称为五大基本特性,各自特性实现功能基本相似,只是使用规则上有所不同;Sass和Stylus具有类似于语言处理的能力,比如说条件语句、循环语句等,而LESS需要通过When等关键词模拟这些功能,在这一方面略逊一层; ...

February 13, 2019 · 5 min · jiezi

sass入门总结

变量 $$width: 5em;#main { width: $width;}嵌套引用嵌套引用在其他编程语言中即是字符串插值,需要用#{}进行包裹:$left: left;.div { border-#{$left}-width: 5px;}继承 @extend.class1{ font-size:19px;}.class2{ @extend .class1; color:black;}Mixin使用@mixin命令,定义一个代码块使用@include命令,调用这个mixin@mixin left { float: left; margin-left: 10px;}div { @include left;}参数和缺省值@mixin left($value: 10px) { float: left; margin-right: $value;}div { @include left(20px);}高级用法流程控制条件语句@if @else@if lightness($color) > 30% { background-color: #000;} @else { background-color: #fff;}循环语句@for@for $i from 1 to 10 { .border-#{$i} { border: #{$i}px solid blue; }}@while $i$i: 6;@while $i > 0 { .item-#{$i} { width: 2em * $i; } $i: $i - 2;}函数@function double($n) { @return $n * 2;}#sidebar { width: double(5px);} ...

January 31, 2019 · 1 min · jiezi

sass和compass基础用法

一、一些基本的命令sass都是通过gem安装,以下是一些基础的命令移除ruby的镜像地址gem sources –remove https://rubygems.org/添加淘宝的镜像 gem source -a http://ruby.taobao.org查看镜像 gem source -v单文件转换命令sass style.scss style.css单文件监听命令(监听会自动编译)sass –watch style.scss:style.css文件夹监听命令sass –watch sassFileDirectory:cssFileDirectorycss文件转成sass/scss文件(在线转换工具css2sass)sass-convert style.css style.sasssass-convert style.css style.scss运行命令行帮助文档,可以获得所有的配置选项sass -h–style表示解析后的css是什么格式,有四种取值分别为:nested,expanded,compact,compressedsass –watch style.scss:style.css –style compact—————-以下是compass———–compass创建一个编译目录,会生成config.rb文件,里面是一些配置compass create sassAPPcompass编译compass compilecompass compile –forcecompass监视compass watchcompass watch –force

January 9, 2019 · 1 min · jiezi

MPVUE -学习笔记

MPVUE -学习笔记

January 7, 2019 · 1 min · jiezi

前端性能优化从css说起

我们都知道性能对于一个网站来说相当重要,以至于很多公司都会专门招聘人员优化网站性能,网上关于探讨网站性能优化的文章也非常多。性能是什么呢?简单来说,就是用户打开网站到网页完全呈现在用户面前所耗费的时间,研究表明:用户最满意的打开网页时间是2-5秒,如果等待超过10秒,99%的用户会关闭这个网页。影响网站的性能有多重因素,我们就着重从前端方面来进行探讨,首先我们先了解一下网页的解析过程。主要过程有:1.解析HTML构建DOM树 ;2.解析css构建CSSOM树 ;3.根据DOM树和CSSOM来构造 Rendering Tree(渲染树);4.Layout页面位置计算布局; 5.Paint绘制;css的加载不会阻塞DOM树的解析,但是会阻塞DOM树的渲染和后面js语句的执行,所以说才有了优化css的必要性,针对这一问题,我们可以从以下方面进行考虑优化。1.结合构建工具(webpack,gulp…),对css文件进行打包压缩,抽离公共样式,删除多余的样式、空格、注释。2.减少样式选择器的层级,减少样式匹配时间。 3.尽量使用class选择器,增强样式的复用;中还有两个重要的知识点repaint(重绘)和reflow(回流),repaint主要是针对某一个DOM元素进行的重绘,reflow则是回流,针对整个页面的重排,我们都知道这两个特性都会消耗网页性能,他们的触发场景也是不同的。不涉及任何DOM元素排版问题的变动为repaint,例如元素的color/text-align/text-decoration等等属性的变动,除上面所提到的DOM元素style修改基本为reflow,例如元素的任何涉及长、宽、行高、边框、display等style的修改。很多时候我们是无法避免引起repaint和reflow,但是我们还是要尽量通过各种方法来减少引起这两个特性,我们可以从以下方面进行考虑优化。1.尽可能在DOM末梢通过改变class来修改元素的style属性:尽可能的减少受影响的DOM元素。2.避免设置多项内联样式:使用常用的class的方式进行设置样式,以避免设置样式时访问DOM的低效率。3.设置动画元素position属性为fixed或者absolute:由于当前元素从DOM流中独立出来,因此受影响的只有当前元素,元素repaint。4.牺牲平滑度满足性能:动画精度太强,会造成更多次的repaint/reflow,牺牲精度,能满足性能的损耗,获取性能和平滑度的平衡。5.避免使用table进行布局:table的每个元素的大小以及内容的改动,都会导致整个table进行重新计算,造成大幅度的repaint或者 reflow。改用div则可以进行针对性的repaint和避免不必要的reflow。6.避免在CSS中使用运算式:学习CSS的时候就知道,这个应该避免,不应该加深到这一层再去了解,因为这个的后果确实非常严重,一旦存在动画性的repaint/reflow,那么每一帧动画都会进行计算,性能消耗不容小觑7.css放在head中,减少引起repaint和reflow;接下来我们再来讨论一下base64图片与CssSprites(雪碧图或css精灵),在网页中我们会用到很多图标,如果每一个图标是单独的一张图片,那网页加载的时候,就会有多个请求去请求图片,显而易见会影响网页性能,所以要采取方法对网页中图标使用进行优化处理。Css Sprites(雪碧图):将许多的小图片整合到一张大图片中,利用css中的background-image属性,background-position属性定位某个图片位置,来达到在大图片中引用某个部位的小图片的效果。优点:减少网页的http请求,提升网页加载速度;合并多张小图片,减少资源体积。缺点:前期需要处理图片,增加工程量;不利于改动和维护。&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspbase64编码:base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,要求把每三个8Bit的字节转换为四个6Bit的字节,Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,通俗点来讲就是将资源原本二进制形式转成以64个字符基本单位,所组成的一串字符串。优点:减少http请求;图片可以避免跨域问题。缺点:低版本IE不兼容;过多使用base64图片会使得css过大,不利于css加载和解析;&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp在网页开发中我们经常会在引入图片,也会使用到上面两种方法来优化处理网页,他们有各自不同的使用场景。Css Sprites 主要针对一些不需要经常变动的小图片,如表情,标志等,base64主要适用于小于几k的图片,图片太大的话反而得不偿失。&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspcss洋洋洒洒写了一些关于css优化的东西,当然也汲取了前辈们的智慧,算是总结一下吧,我相信关于css的优化知识还有很多,不断学习吧!!

January 5, 2019 · 1 min · jiezi

[ webpack4 ] 配置属于自己的打包系统教程(二)—— 资源配置篇

GitHub 完整配置文件地址: https://github.com/yhtx1997/webpack4-Instance 由于篇幅过长分三次发布,建议按顺序看[ webpack4 ] 配置属于自己的打包系统教程(一)—— 基础配置篇[ webpack4 ] 配置属于自己的打包系统教程(二)—— 资源配置篇[ webpack4 ] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇资源配置篇资源配置篇ES6 -> ES5提取 css 到单独文件css 浏览器兼容前缀补全css 代码压缩使用 sass使用 HTML 模板清理旧的打包文件静态资源加载与解析通过下面的配置 可以在 js 里引入相应的文件,然后进行解析 也可以直接解析相应的文件配置 babel 将 ES6 转换为兼容性语法(低版本语法 ES5 或 ES3)安装 babel-loadernpm install -D babel-loader @babel/core @babel/preset-env babel-loader:使用 Babel 转换 JavaScript 依赖关系的 Webpack 加载器@babel/core: 将 ES6 代码转换为 ES5@babel/preset-env: 决定使用哪些 api 为旧浏览器提供现代浏览器的新特性module: { rules: [ { test: /.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: ‘babel-loader’, options: { presets: [’@babel/preset-env’] } } } ]}加载 css安装提取 css 相关的 npm 包npm install style-loader css-loader -D提取 css 相关配置const path = require(‘path’);module.exports = { entry: { 2048: ‘./src/js/2048.js’, 1024: ‘./src/js/1024.js’, 512: ‘./src/js/512.js’ }, output: { filename: “[name].js”, path: path.resolve(__dirname, ‘dist’) }, module: { rules: [ { test: /.css$/, //匹配所有以 .css 为后缀的文件 use: [//使用以下loader来加载 ‘style-loader’, ‘css-loader’ ] } ] }}安装 sass开发 css 现在多数使用 sass 和 lass ,所以配置下 sass 相应的安装 lass 只需要把 sass-loader 切换为 less-loadernpm install sass-loader node-sass -D配置{ test: /.scss$/, use: [ “style-loader”, “css-loader”, “sass-loader” ]}CSS 分离成文件方案一 安装 extract-text-webpack-plugin方案一简单写下,推荐方案二npm install extract-text-webpack-plugin -Dextract-text-webpack-plugin 提取 css 到单独文件配置const ExtractTextPlugin = require(“extract-text-webpack-plugin”);plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title:‘2048’, template: ‘./src/index.html’, minify:true, hash:true }), new ExtractTextPlugin({ filename: ‘css/[name].css’ }),],module: { rules: [ { test: /.scss$/, use: ExtractTextPlugin.extract({ fallback: “style-loader”, use: [“css-loader”,“sass-loader”] }) }, ]}方案二 安装 MiniCssExtractPlugin 推荐与extract-text-webpack-plugin相比异步加载没有重复的编译(性能)更容易使用特定于CSSnpm install mini-css-extract-plugin postcss-loader autoprefixer postcss optimize-css-assets-webpack-plugin -Dmini-css-extract-plugin 提取 css 到单独文件autoprefixer 浏览器兼容前缀补全(例如 -webkit-)optimize-css-assets-webpack-plugin 代码压缩配置const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);const OptimizeCSSAssetsPlugin = require(“optimize-css-assets-webpack-plugin”);optimization: { minimizer: [ new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: true // set to true if you want JS source maps }), new OptimizeCSSAssetsPlugin({}) ] },plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title:‘2048’, template: ‘./src/index.html’, minify:true, hash:true }), new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: “css/[name].css” })],module: { rules: [ { test: /.scss$/, use: [ MiniCssExtractPlugin.loader, ‘css-loader’, ‘postcss-loader’, ‘sass-loader’, ] }, ] }这里需要注意的是需要新建一个 postcss.config.js 文件,用来配置自动加前缀module.exports={ plugins: [ require(‘autoprefixer’)({ /* …options */ }) ]}加载数据数据文件包括 JSON 文件,CSV、TSV 和 XML JSON 默认就是支持的,所以如果需要处理剩下的使用下面的方法就可以了安装提取 数据 相关的 npm 包npm install csv-loader xml-loader -D安装提取 数据 相关的 npm 包{ test: /.(csv|tsv)$/, use: [ ‘csv-loader’ ]},{ test: /.xml$/, use: [ ‘xml-loader’ ]}加载其他资源加载其他静态资源都可以使用 file-loader 来加载npm install file-loader -D加载图片{ test: /.(png|svg|jpg|gif)$/, use: [ ‘file-loader’ ]}加载字体{ test: /.(woff|woff2|eot|ttf|otf)$/, use: [ ‘file-loader’ ]}设定 HtmlWebpackPlugin当我们真正应用我们写的代码时,需要我们新建 HTML ,并且需要我们手动的在 HTML 里引入,使用 HtmlWebpackPlugin 可以让我们不用每次都新建 HTML 以及 手动去引入我们的代码 它会帮我们每次运行 webpack 时新建一个 HTML 并引入所有打包好的 js css安装npm install html-webpack-plugin -D配置 HTML 模板const HtmlWebpackPlugin = require(‘html-webpack-plugin’);//引入HtmlWebpackPlugin//官网是将其放到了入口 entry 与出口 output 之间plugins: [ new HtmlWebpackPlugin({ title: ‘Output Management’,//表示 HTML title 标签的内容 template: ‘./src/index.html’,//表示模板路径 minify: true,//压缩代码 hash: true//加上哈希值来达到去缓存的目的 })]清理 ./dist 文件夹如果我们使用了哈希值来命名我们的文件,那么每次更该内容都会生成新的文件,同时旧的文件依然存在,这样的话一个是乱,一个是浪费 我们可以使用 CleanWebpackPlugin 在每次打包时都会将之前的旧文件清除掉安装npm install clean-webpack-plugin -D配置const CleanWebpackPlugin = require(‘clean-webpack-plugin’);plugins: [ new CleanWebpackPlugin([‘dist’]),//删除dist new HtmlWebpackPlugin({ title: ‘Output Management’,//表示 HTML title 标签的内容 template: ‘./src/index.html’,//表示模板路径 minify: true,//压缩代码 hash: true//加上哈希值来达到去缓存的目的 })] ...

January 3, 2019 · 2 min · jiezi

➹使用webpack配置多页面应用MPA:100

使用webpack配置MPA为什么需要使用 webpack 构建多页应用呢?因为某些项目使用 SPA 不太合适(大多是 SEO 的原因),或者您在做项目时有其他的需求。如果你有如下需求:使用 ES6 进行开发期望使用面向对象开发(class)自动压缩合并 CSS 和 JS 文件使用 ESLint 进行代码检查自动生成 HTML 文件自动抽取 CSS 文件 …有了这些需求,基本上就必须使用 webpack 了。安装依赖首先是项目中需要使用的依赖安装。安装 webpack 和 webpack-dev-servernpm install webpack webpack-dev-server –save-dev安装 webpack-mergenpm install webpack-merge –save-dev该插件用来对 webpack 配置进行合并操作。安装 babel 相关插件npm install babel-core babel-loader babel-preset-env –save-dev这系列插件用来对 ES6 语法进行转换。安装样式处理相关插件npm install css-loader style-loader postcss-loader autoprefixer –save-dev这系列插件用来处理 CSS 样式,其中 autoprefixer 是 postcss 的一个插件,用来自动给 CSS 样式添加前缀。安装 file-loader该插件将在导入图片、字体等文件时发挥作用。PS.您也可以安装 url-loader 以实现相同的作用:npm install file-loader –save-devnpm install url-loader –save-dev安装 ESLint 相关的插件npm install eslint eslint-loader –save-dev这些插件用来对 JavaScript 代码进行检查。安装 html-webpack-plugin 插件npm install html-webpack-plugin –save-dev该插件用来自动生成 HTML 文件。安装 extract-text-webpack-plugin 插件npm install extract-text-webpack-plugin –save-dev该插件用来将 CSS 抽取到独立的文件。安装 clean-webpack-plugin 插件npm install clean-webpack-plugin –save-dev该插件用来对 dist 文件夹进行清理工作,每次打包时先清理之前的 dist 文件夹。下面是这些安装了的所有依赖:… “devDependencies”: { “autoprefixer”: “^7.1.3”, “babel-core”: “^6.26.0”, “babel-loader”: “^7.1.2”, “babel-preset-env”: “^1.6.0”, “clean-webpack-plugin”: “^0.1.16”, “css-loader”: “^0.28.7”, “eslint”: “^4.6.1”, “eslint-loader”: “^1.9.0”, “extract-text-webpack-plugin”: “^3.0.0”, “file-loader”: “^0.11.2”, “html-webpack-plugin”: “^2.30.1”, “postcss-loader”: “^2.0.6”, “style-loader”: “^0.18.2”, “url-loader”: “^0.5.9”, “webpack”: “^3.5.5”, “webpack-dev-server”: “^2.7.1”, “webpack-merge”: “^4.1.0” },…配置文件划分使用 webpack 进行项目构建时,我们有不同的目的,因此最好将配置文件进行拆分,以适应不同的工作:├─config│ config.js│ webpack.config.base.js│ webpack.config.dev.js│ webpack.config.lint.js│ webpack.config.prod.js│ webpack.config.js下面是一些配置的说明:config.js:一些全局的配置,比如 HTML 文件的路径、publicPath 等webpack.config.base.js:最基础的配置文件webpack.config.dev.js:开发环境配置文件webpack.config.lint.js:使用 ESLint 代码检查时的配置文件webpack.config.prod.js:生产环境配置文件webpack.config.js:主配置文件,根据环境变量引用相应的环境的配置这些配置文件之间是通过 webpack-merge 这个插件进行合并的。配置多页应用的关键点如何使用 webpack 配置多页面应用呢?实现多页面应用的关键点在哪里呢?首先需要简单看一下多页应用和单页应用功能的区别。单页应用的特点:只有一个入口页面(index.html)这个单页页面(index.html)中需要引入打包后的所有 JavaScript 文件所有的页面内容完全由 JavaScript 生成单页应用有自己的路由系统,服务器端没有和路由对应的文件···多页应用的特点:每个版块对应一个页面每个页面需要对公共的 JavaScript 进行引入每个页面还需要引入和其自身对应的 JavaScript 文件由于对应了多个页面,因此不是所有页面内容都是由 JavaScript 生成的没有自己的路由系统,服务器端有对应的静态文件···抛开生成页面内容和路由系统,我们可以看到单页应用和多页应用最大的区别就是:单页应用需要在入口页面引入所有的 JavaScript 文件多页应用需要在每个页面中引入公共的 JavaScript 文件以及其自身的 JavaScript 文件由于 CSS 文件是可以由 extract-text-webpack-plugin 这个插件自动提取并插入到 HTML 页面的,因此我们只需要关心如何在 HTML 页面中引入 JavaScript 文件了。webpack 在打包时,会将入口文件中的 JavaScript 文件打包到某个目标文件中,在不考虑代码分割提取的情况下,一个入口文件会打包为一个目标文件,多个入口文件会打包为多个对应的目标文件。因此,我们可以将每个多页页面中的特有的 JavaScript 文件作为入口文件,在打包时将对应打包成不同的 bundle 文件(结果文件),如果你想要的话,还可以在打包时进行代码分割处理,将公用代码抽取成一个文件,然后在 HTML 中引入这些 JavaScript 文件就好了。总结一下,使用 webpack 配置多页应用的关键点在于:将每个页面中特有的 JavaScript 文件作为入口文件进行打包在打包后,每个页面中都需要引入这些打包后的文件您可以在打包时进行公用代码提取,然后在 HTML 文件中引入说了这么多,其实就是利用了 webpack 多入口文件进行打包。自动生成 HTML 页面在使用 webpack 对 JavaScript 文件进行打包时,通常需要在打包的文件名中加一个 hash 字符串用来防止缓存,当我们修改了 JavaScript 代码后,打包后的文件名也会发生变化。此时如果手动在 HTML 中引用这些 JavaScript 文件,是非常麻烦的。因此,我们期望能自动生成 HTML 文件,并自动引用打包后的 JavaScript 文件。所谓自动生成 HTML 文件,可以理解为将源代码的 HTML 复制到目标文件夹中,同时自动引用打包后的 JavaScript 文件。要完成这项操作,就需要使用前面安装的 html-webpack-plugin 这个插件。html-webpack-plugin 插件的使用首先,在我的项目中,有这么一些 HTML 页面,将它们放在 html 文件夹中:Mode LastWriteTime Length Name—- ————- —— —–a—- 2017/9/5 18:04 1071 company_intro.html-a—- 2017/9/5 18:04 988 contact_us.html-a—- 2017/9/5 18:04 1131 cooperate.html-a—- 2017/9/5 18:04 1244 enterprise_culture.html-a—- 2017/9/5 18:04 1011 hornors.html-a—- 2017/9/5 18:04 1365 index.html-a—- 2017/9/5 18:04 1769 investment.html-a—- 2017/9/5 18:04 1005 join_us.html-a—- 2017/9/5 18:04 1037 news_center.html-a—- 2017/9/5 18:04 987 news_item.html-a—- 2017/9/5 18:04 1134 operate.html-a—- 2017/9/5 18:04 1255 product.html-a—- 2017/9/5 18:04 1132 schools.html然后,把这些 HTML 文件名(不要后缀)都写在 config.js 文件中,以供取用:module.exports = { HTMLDirs:[ “index”, “company_intro”, “enterprise_culture”, “hornors”, “news_center”, “news_item”, “product”, “schools”, “operate”, “cooperate”, “join_us”, “contact_us”, “investment” ], }HTMLDirs 是一个数组,其中保存了项目中会用到的所有 HTML 页面。接下来,每个 HTML 页面都对应一份 JavaScript 代码,因此在 js 文件夹中建立对应的 JavaScript 文件:Mode LastWriteTime Length Name—- ————- —— —–a—- 2017/9/5 18:04 2686 company_intro.js-a—- 2017/9/5 18:04 594 contact_us.js-a—- 2017/9/5 18:04 1725 cooperate.js-a—- 2017/9/8 16:54 3505 enterprise_culture.js-a—- 2017/9/5 18:04 2208 hornors.js-a—- 2017/9/8 16:54 4491 index.js-a—- 2017/9/5 18:04 3180 investment.js-a—- 2017/9/5 18:04 1327 join_us.js-a—- 2017/9/8 16:55 3689 news_center.js-a—- 2017/9/5 18:04 1972 news_item.js-a—- 2017/9/5 18:04 2728 operate.js-a—- 2017/9/5 18:04 2664 product.js-a—- 2017/9/5 18:04 2476 schools.js这两项是必须的,只有提供了每个页面的 HTML 文件和对应的 JavaScript 文件,才能构建多页面应用。同时,可能每个页面都有自己的样式,因此您也可以在 css 文件夹中建立一些样式文件:Mode LastWriteTime Length Name—- ————- —— —–a—- 2017/9/5 18:04 419 company_intro.css-a—- 2017/9/5 18:04 167 contact_us.css-a—- 2017/9/5 18:04 214 cooperate.css-a—- 2017/9/5 18:04 926 enterprise_culture.css-a—- 2017/9/5 18:04 255 hornors.css-a—- 2017/9/5 18:04 693 investment.css-a—- 2017/9/5 18:04 136 join_us.css-a—- 2017/9/5 18:04 541 news_center.css-a—- 2017/9/5 18:04 623 news_item.css-a—- 2017/9/5 18:04 342 operate.css-a—- 2017/9/5 18:04 236 product.css-a—- 2017/9/5 18:04 213 schools.css关于建立样式这一项,不是必须的。最后,我们就可以使用 html-webpack-plugin 这个插件来自动生成 HTML 文件了,html-webpack-plugin 插件的用法如下:// 引入插件const HTMLWebpackPlugin = require(“html-webpack-plugin”);// 引入多页面文件列表const { HTMLDirs } = require("./config");// 通过 html-webpack-plugin 生成的 HTML 集合let HTMLPlugins = [];// 入口文件集合let Entries = {}// 生成多页面的集合HTMLDirs.forEach((page) => { const htmlPlugin = new HTMLWebpackPlugin({ filename: ${page}.html, template: path.resolve(__dirname, ../app/html/${page}.html), chunks: [page, ‘commons’], }); HTMLPlugins.push(htmlPlugin); Entries[page] = path.resolve(__dirname, ../app/js/${page}.js);})在上面的代码中,首先引入了所需的插件和变量,然后利用 html-webpack-plugin 循环生成 HTML 页面。简单说下 HTMLWebpackPlugin 构造函数的几个参数:filename:生成的 HTML 文件名,我这里选择和原始文件名保持一致template:生成 HTML 文件使用的模板,也就是我们之前在 html 文件夹中建立的那些文件chunks:生成 HTML 文件时会自动插入相应的代码片段(也就是 JavaScript 文件),我这里选择插入每个页面对应的 JavaScript 文件,以及最后提取出来的公共文件代码块。关于 chunks 还需要说明一点,chunks 是一个数组,在生成 HTML 文件时会将数组中的对应的 JavaScript 片段自动插入到 HTML 中,这些片段也就是 webpack 打包时的 output 选项中的 [name]。这里只需要写上 [name] 值就行了,无需使用打包生成的完整名称,因为这会还没开始打包呢,打包后生成的名称咱也不知道。最后,我们把这些生成 HTML 文件的配置插入到 HTMLPlugins 这个数组中,同时设置 webpack 的入口文件。目录划分在这个脚手架中,我是这样划分项目结构的: ├─app │ ├─css │ ├─html │ ├─img │ ├─js │ └─lib ├─config └─dist ├─css ├─img └─js 其中 app 是项目的源码,config 是 webpack 相关的一些配置文件,dist 是存放打包后的文件,是由 webpack 自动生成的。 更详细的文件结构如下: │ .babelrc │ .eslintrc.js │ .gitignore │ package.json │ postcss.config.js │ webpack.config.js │ ├─app │ │ favicon.ico │ │ │ ├─css │ │ main.css │ │ │ ├─html │ │ index.html │ │ │ │ │ ├─img │ │ back.png │ │ │ ├─js │ │ ajax.js │ │ footer.js │ │ index.js │ │ nav.js │ │ public.js │ │ tity_nav.js │ │ │ └─lib │ flexible.js │ normalize.css │ swiper.css │ swiper.js │ └─config config.js webpack.config.base.js webpack.config.dev.js webpack.config.lint.js webpack.config.prod.jspackage.json所有的功能都是从 package.json 的 scripts 入口开始执行的,我想要脚手架有以下功能:开发环境构建生产环境构建ESLint 代码检查环境生产环境构建后的服务器预览环境在开发或代码检查环境,需要启用 webpack-dev-server 命令,生产环境构建需要启用 webpack 命令,预览环境需要启用 http-server 环境。上文介绍时把 http-server 给落下了,您现在可以进行如下安装:npm install http-server –save-devscripts 命令行配置如下: “scripts”: { “dev”: “set NODE_ENV=dev && webpack-dev-server –open”, “build”: “set NODE_ENV=prod && webpack -p”, “lint”: “set NODE_ENV=lint && webpack-dev-server –open”, “serve”: “http-server ./dist -p 8888 -o”, “serve2”: “http-server ./dist -p 8888” },下面是整个 package.json 文件:{ “name”: “xxx”, “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “dev”: “set NODE_ENV=dev && webpack-dev-server –open”, “build”: “set NODE_ENV=prod && webpack -p”, “lint”: “set NODE_ENV=lint && webpack-dev-server –open”, “serve”: “http-server ./dist -p 8888 -o”, “serve2”: “http-server ./dist -p 8888” }, “author”: “”, “license”: “ISC”, “devDependencies”: { “autoprefixer”: “^7.1.3”, “babel-core”: “^6.26.0”, “babel-loader”: “^7.1.2”, “babel-plugin-transform-es2015-spread”: “^6.22.0”, “babel-preset-env”: “^1.6.0”, “clean-webpack-plugin”: “^0.1.16”, “css-loader”: “^0.28.7”, “eslint”: “^4.5.0”, “eslint-loader”: “^1.9.0”, “extract-text-webpack-plugin”: “^3.0.0”, “file-loader”: “^0.11.2”, “html-webpack-plugin”: “^2.30.1”, “http-server”: “^0.10.0”, “postcss-loader”: “^2.0.6”, “style-loader”: “^0.18.2”, “url-loader”: “^0.5.9”, “webpack”: “^3.5.5”, “webpack-dev-server”: “^2.7.1”, “webpack-merge”: “^4.1.0” }, “dependencies”: {}}启用环境如果您想启用某个环境,需要使用 npm run xxx 命令:npm run dev:进入开发环境npm run build:进入生产环境npm run lint:执行代码检查npm run serve:服务器环境下预览(打开浏览器)npm run serve2:服务器环境下预览(不打开浏览器)默认情况下,使用这些命令都会先引入和 package.js 同目录下的 webpack.config.js 文件。由于我们不会将所有的配置都放在 webpack.config.js 中,而是过环境变量进行区分,在 webpack.config.js 中引用其他的配置文件。设置环境变量采用的语法:set NODE_ENV=xxx这里我们为开发、生产、代码检查和预览这几个环境设置了环境变量。webpack.config.jswebpack.config.js 文件比较简单,只有两行代码,其作用就是用来引用其他的配置文件:// 获取环境命令,并去除首尾空格const env = process.env.NODE_ENV.replace(/(\s*$)|(^\s*)/ig,"");// 根据环境变量引用相关的配置文件module.exports = require(./config/webpack.config.${env}.js)webpack.config.base.jswebpack.config.base.js 是最基础的配置文件,包含了这些环境都可能使用到的配置。1)相关插件引入const path = require(“path”);// 引入插件const HTMLWebpackPlugin = require(“html-webpack-plugin”);// 清理 dist 文件夹const CleanWebpackPlugin = require(“clean-webpack-plugin”)// 抽取 cssconst ExtractTextPlugin = require(“extract-text-webpack-plugin”);#### 2)自动生成 HTML 的配置// 引入多页面文件列表const config = require("./config");// 通过 html-webpack-plugin 生成的 HTML 集合let HTMLPlugins = [];// 入口文件集合let Entries = {}// 生成多页面的集合config.HTMLDirs.forEach((page) => { const htmlPlugin = new HTMLWebpackPlugin({ filename: ${page}.html, template: path.resolve(__dirname, ../app/html/${page}.html), chunks: [page, ‘commons’], }); HTMLPlugins.push(htmlPlugin); Entries[page] = path.resolve(__dirname, ../app/js/${page}.js);})3)主配置文件一览module.exports = { // 入口文件 entry:Entries, // 启用 sourceMap devtool:“cheap-module-source-map”, // 输出文件 output:{}, // 加载器 module:{ rules:[ ], }, // 插件 plugins:[],}4)配置 css 加载器{ // 对 css 后缀名进行处理 test:/.css$/, // 不处理 node_modules 文件中的 css 文件 exclude: /node_modules/, // 抽取 css 文件到单独的文件夹 use: ExtractTextPlugin.extract({ fallback: “style-loader”, // 设置 css 的 publicPath publicPath: config.cssPublicPath, use: [{ loader:“css-loader”, options:{ // 开启 css 压缩 minimize:true, } }, { loader:“postcss-loader”, } ] })},这里有两点需要说明:A.publicPath:在 css 中设置背景图像的 url 时,经常会找不到图片(默认会在 css 文件所在的文件夹中寻找),这里设置 extract-text-webpack-plugin 插件的 publicPath 为图片文件夹所在的目录,就可以顺利找到图片了。在 config.js 中,设置 cssPublicPath 的值:cssPublicPath:"../“B.postcss 我主要用来自动添加 css 前缀以及一点美化操作,在使用 postcss 时,需要在 postcss.config.js 中进行配置:module.exports = { plugins: { ‘autoprefixer’: { browsers: [’last 5 version’,‘Android >= 4.0’], //是否美化属性值 默认:true cascade: true, //是否去掉不必要的前缀 默认:true remove: true } } } 5)配置 js 加载器js 加载器的配置如下:{ test: /.js$/, exclude: /node_modules/, use: { loader: ‘babel-loader’, options: { presets: [’env’] } }},6)配置图片加载器图片加载器的配置如下:{ test: /.(png|svg|jpg|gif)$/, use:{ loader:“file-loader”, options:{ // 打包生成图片的名字 name:"[name].[ext]”, // 图片的生成路径 outputPath:config.imgOutputPath } }},outputPath 规定了输出图片的位置,默认情况下,图片在打包时会和所有的 HTML/CSS/JS 文件打包到一起,通过设置 outputPath 值可以将所有的图片都打包到一个单独的文件中。设置 config.js 的 imgOutputPath:imgOutputPath:“img/",在打包时,会将所有的图片打包到 dist 文件夹下的 img 文件夹中。7)配置自定义字体加载器自定义字体加载器的配置如下:{ test: /.(woff|woff2|eot|ttf|otf)$/, use:[“file-loader”]}8)插件配置插件配置如下:plugins:[ // 自动清理 dist 文件夹 new CleanWebpackPlugin([“dist”]), // 将 css 抽取到某个文件夹 new ExtractTextPlugin(config.cssOutputPath), // 自动生成 HTML 插件 …HTMLPlugins],同打包图片,在抽取 css 时也可以指定抽取的目录,只需将路径传入 extract-text-webpack-plugin 插件的构造函数中。配置 config.js 的 cssOutputPath 选项:cssOutputPath:”./css/styles.css",这里将所有的 css 提取到 dist 文件夹下的 css 文件夹中,并命名为 style.css。webpack.config.base.js 详细配置下面是 webpack.config.base.js 的详细配置文件:const path = require(“path”);// 引入插件const HTMLWebpackPlugin = require(“html-webpack-plugin”);// 清理 dist 文件夹const CleanWebpackPlugin = require(“clean-webpack-plugin”)// 抽取 cssconst ExtractTextPlugin = require(“extract-text-webpack-plugin”);// 引入多页面文件列表const config = require("./config");// 通过 html-webpack-plugin 生成的 HTML 集合let HTMLPlugins = [];// 入口文件集合let Entries = {}// 生成多页面的集合config.HTMLDirs.forEach((page) => { const htmlPlugin = new HTMLWebpackPlugin({ filename: ${page}.html, template: path.resolve(__dirname, ../app/html/${page}.html), chunks: [page, ‘commons’], }); HTMLPlugins.push(htmlPlugin); Entries[page] = path.resolve(__dirname, ../app/js/${page}.js);})module.exports = { entry:Entries, devtool:“cheap-module-source-map”, output:{ filename:“js/[name].bundle.[hash].js”, path:path.resolve(__dirname,"../dist") }, // 加载器 module:{ rules:[ { // 对 css 后缀名进行处理 test:/.css$/, // 不处理 node_modules 文件中的 css 文件 exclude: /node_modules/, // 抽取 css 文件到单独的文件夹 use: ExtractTextPlugin.extract({ fallback: “style-loader”, // 设置 css 的 publicPath publicPath: config.cssPublicPath, use: [{ loader:“css-loader”, options:{ // 开启 css 压缩 minimize:true, } }, { loader:“postcss-loader”, } ] }) }, { test: /.js$/, exclude: /node_modules/, use: { loader: ‘babel-loader’, options: { presets: [’env’] } } }, { test: /.(png|svg|jpg|gif)$/, use:{ loader:“file-loader”, options:{ // 打包生成图片的名字 name:"[name].[ext]", // 图片的生成路径 outputPath:config.imgOutputPath } } }, { test: /.(woff|woff2|eot|ttf|otf)$/, use:[“file-loader”] } ], }, plugins:[ // 自动清理 dist 文件夹 new CleanWebpackPlugin([“dist”]), // 将 css 抽取到某个文件夹 new ExtractTextPlugin(config.cssOutputPath), // 自动生成 HTML 插件 …HTMLPlugins ],}webpack.config.dev.js这个配置文件主要用来在开发环境使用,需要 webpack-dev-server 这个插件提供支持。该文件的配置如下:// 引入基础配置文件const webpackBase = require("./webpack.config.base");// 引入 webpack-merge 插件const webpackMerge = require(“webpack-merge”);// 引入配置文件const config = require("./config");// 合并配置文件module.exports = webpackMerge(webpackBase,{ // 配置 webpack-dev-server devServer:{ // 项目根目录 contentBase:config.devServerOutputPath, // 错误、警告展示设置 overlay:{ errors:true, warnings:true } }});其中,webpack-merge 这个插件用来对配置文件进行合并,在 webpack.config.base.js 的基础上合并新的配置。devServer 配置项的 contentBase 项是项目的根目录,也就是我们的 dist 目录,区别在于这个 dist 目录不是硬盘上的 dist 目录,而是存在于内存中的 dist 目录。在使用 webpack-dev-server 时,将会以这个内存中的 dist 目录作为根目录。devServer 的 overlay 选项中设置了展示错误和警告,这样当代码发生错误时,会将错误信息投射到浏览器上,方便我们开发。这里将 contentBase 指向了 config 中的一个配置:devServerOutputPath:"../dist",webpack.config.prod.js该配置文件用来在生产环境启用,主要用来压缩、合并和抽取 JavaScript 代码,并将项目文件打包至硬盘上的 dist 文件夹中。// 引入基础配置const webpackBase = require("./webpack.config.base");// 引入 webpack-merge 插件const webpackMerge = require(“webpack-merge”);// 引入 webpackconst webpack = require(“webpack”);// 合并配置文件module.exports = webpackMerge(webpackBase,{ plugins:[ // 代码压缩 new webpack.optimize.UglifyJsPlugin({ // 开启 sourceMap sourceMap: true }), // 提取公共 JavaScript 代码 new webpack.optimize.CommonsChunkPlugin({ // chunk 名为 commons name: “commons”, filename: “[name].bundle.js”, }), ]});在抽取公共的 JavaScript 代码时,我们将公共代码抽取为 commons.bundle.js,这个公共代码的 chunk(name)名就是 commons,在使用 html-webpack-plugin 自动生成 HTML 文件时会引用这个 chunk。webpack.config.lint.js这项配置用来进行代码检查,配置如下:const webpackBase = require("./webpack.config.base");const webpackMerge = require(“webpack-merge”);const config = require("./config");module.exports = webpackMerge(webpackBase,{ module:{ rules:[ { test: /.js$/, // 强制先进行 ESLint 检查 enforce: “pre”, // 不对 node_modules 和 lib 文件夹中的代码进行检查 exclude: /node_modules|lib/, loader: “eslint-loader”, options: { // 启用自动修复 fix:true, // 启用警告信息 emitWarning:true, } }, ] }, devServer:{ contentBase:config.devServerOutputPath, overlay:{ errors:true, warnings:true } }});在使用 eslint-loader 时,我们设置了 enforce:“pre” 选项,这个选项表示在处理 JavaScript 之前先启用 ESLint 代码检查,然后再使用 babel 等 loader 对 JavaScript 进行编译。在 eslint-loader 的 options 选项中,设置了自动修复和启用警告信息,这样当我们的代码出现问题时,ESLint 会首先尝试自动修复(如将双引号改为单引号),对于无法自动修复的问题,将以警告或错误的信息进行展示。配置 .eslintrc.js要想使用 ESLint 进行代码检查,除了使用 eslint-loader 之外,还需针对 ESLint 本身进行配置,这就需要一个 .eslintrc.js 文件。该文件的配置如下:module.exports = { env: { browser: true, commonjs: true, es6: true, node: true, }, extends: ’eslint:recommended’, parserOptions: { sourceType: ‘module’, }, rules: { ‘comma-dangle’: [’error’, ‘always-multiline’], indent: [’error’, 2], ’linebreak-style’: [’error’, ‘unix’], quotes: [’error’, ‘single’], semi: [’error’, ‘always’], ’no-unused-vars’: [‘warn’], ’no-console’: 0, },};package.json{ “name”: “xxx”, “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “dev”: “set NODE_ENV=dev && webpack-dev-server –open”, “build”: “set NODE_ENV=prod && webpack -p”, “lint”: “set NODE_ENV=lint && webpack-dev-server –open”, “serve”: “http-server ./dist -p 8888 -o”, “serve2”: “http-server ./dist -p 8888” }, “author”: “”, “license”: “ISC”, “devDependencies”: { “autoprefixer”: “^7.1.3”, “babel-core”: “^6.26.0”, “babel-loader”: “^7.1.2”, “babel-plugin-transform-es2015-spread”: “^6.22.0”, “babel-preset-env”: “^1.6.0”, “clean-webpack-plugin”: “^0.1.16”, “css-loader”: “^0.28.7”, “eslint”: “^4.5.0”, “eslint-loader”: “^1.9.0”, “extract-text-webpack-plugin”: “^3.0.0”, “file-loader”: “^0.11.2”, “html-webpack-plugin”: “^2.30.1”, “http-server”: “^0.10.0”, “postcss-loader”: “^2.0.6”, “style-loader”: “^0.18.2”, “url-loader”: “^0.5.9”, “webpack”: “^3.5.5”, “webpack-dev-server”: “^2.7.1”, “webpack-merge”: “^4.1.0” }, “dependencies”: {}}.gitignorenode_modulesdistnpm-debug.log.babelrc{ “plugins”: [“transform-es2015-spread”]}.eslintrc.jsmodule.exports = { env: { browser: true, commonjs: true, es6: true, node: true, }, extends: ’eslint:recommended’, parserOptions: { sourceType: ‘module’, }, rules: { ‘comma-dangle’: [’error’, ‘always-multiline’], indent: [’error’, 2], ’linebreak-style’: [’error’, ‘unix’], quotes: [’error’, ‘single’], semi: [’error’, ‘always’], ’no-unused-vars’: [‘warn’], ’no-console’: 0, },};postcss.config.jsmodule.exports = { plugins: { ‘autoprefixer’: { browsers: [’last 5 version’,‘Android >= 4.0’], //是否美化属性值 默认:true cascade: true, //是否去掉不必要的前缀 默认:true remove: true } } } config.jsmodule.exports = { HTMLDirs:[ “index”, “company_intro”, “enterprise_culture”, “hornors”, “news_center”, “news_item”, “product”, “schools”, “operate”, “cooperate”, “join_us”, “contact_us”, “investment” ], cssPublicPath:"../", imgOutputPath:“img/”, cssOutputPath:"./css/styles.css", devServerOutputPath:"../dist",}webpack.config.js// 获取环境命令,并去除首尾空格const env = process.env.NODE_ENV.replace(/(\s*$)|(^\s*)/ig,"");// 根据环境变量引用相关的配置文件module.exports = require(./config/webpack.config.${env}.js)webpack.config.base.jsconst path = require(“path”);// 引入插件const HTMLWebpackPlugin = require(“html-webpack-plugin”);// 清理 dist 文件夹const CleanWebpackPlugin = require(“clean-webpack-plugin”)// 抽取 cssconst ExtractTextPlugin = require(“extract-text-webpack-plugin”);// 引入多页面文件列表const config = require("./config");// 通过 html-webpack-plugin 生成的 HTML 集合let HTMLPlugins = [];// 入口文件集合let Entries = {}// 生成多页面的集合config.HTMLDirs.forEach((page) => { const htmlPlugin = new HTMLWebpackPlugin({ filename: ${page}.html, template: path.resolve(__dirname, ../app/html/${page}.html), chunks: [page, ‘commons’], }); HTMLPlugins.push(htmlPlugin); Entries[page] = path.resolve(__dirname, ../app/js/${page}.js);})module.exports = { entry:Entries, devtool:“cheap-module-source-map”, output:{ filename:“js/[name].bundle.[hash].js”, path:path.resolve(__dirname,"../dist") }, // 加载器 module:{ rules:[ { // 对 css 后缀名进行处理 test:/.css$/, // 不处理 node_modules 文件中的 css 文件 exclude: /node_modules/, // 抽取 css 文件到单独的文件夹 use: ExtractTextPlugin.extract({ fallback: “style-loader”, // 设置 css 的 publicPath publicPath: config.cssPublicPath, use: [{ loader:“css-loader”, options:{ // 开启 css 压缩 minimize:true, } }, { loader:“postcss-loader”, } ] }) }, { test: /.js$/, exclude: /node_modules/, use: { loader: ‘babel-loader’, options: { presets: [’env’] } } }, { test: /.(png|svg|jpg|gif)$/, use:{ loader:“file-loader”, options:{ // 打包生成图片的名字 name:"[name].[ext]", // 图片的生成路径 outputPath:config.imgOutputPath } } }, { test: /.(woff|woff2|eot|ttf|otf)$/, use:[“file-loader”] } ], }, plugins:[ // 自动清理 dist 文件夹 new CleanWebpackPlugin([“dist”]), // 将 css 抽取到某个文件夹 new ExtractTextPlugin(config.cssOutputPath), // 自动生成 HTML 插件 …HTMLPlugins ],}webpack.config.dev.js// 引入基础配置文件const webpackBase = require("./webpack.config.base");// 引入 webpack-merge 插件const webpackMerge = require(“webpack-merge”);// 引入配置文件const config = require("./config");// 合并配置文件module.exports = webpackMerge(webpackBase,{ // 配置 webpack-dev-server devServer:{ // 项目根目录 contentBase:config.devServerOutputPath, // 错误、警告展示设置 overlay:{ errors:true, warnings:true } }});webpack.config.prod.js// 引入基础配置const webpackBase = require("./webpack.config.base");// 引入 webpack-merge 插件const webpackMerge = require(“webpack-merge”);// 引入 webpackconst webpack = require(“webpack”);// 合并配置文件module.exports = webpackMerge(webpackBase,{ plugins:[ // 代码压缩 new webpack.optimize.UglifyJsPlugin({ // 开启 sourceMap sourceMap: true }), // 提取公共 JavaScript 代码 new webpack.optimize.CommonsChunkPlugin({ // chunk 名为 commons name: “commons”, filename: “[name].bundle.js”, }), ]});webpack.config.lint.jsconst webpackBase = require("./webpack.config.base");const webpackMerge = require(“webpack-merge”);const config = require("./config");module.exports = webpackMerge(webpackBase,{ module:{ rules:[ { test: /.js$/, // 强制先进行 ESLint 检查 enforce: “pre”, // 不对 node_modules 和 lib 文件夹中的代码进行检查 exclude: /node_modules|lib/, loader: “eslint-loader”, options: { // 启用自动修复 fix:true, // 启用警告信息 emitWarning:true, } }, ] }, devServer:{ contentBase:config.devServerOutputPath, overlay:{ errors:true, warnings:true } }});项目结构│ .babelrc│ .eslintrc.js│ .gitignore│ package.json│ postcss.config.js│ webpack.config.js│ ├─app│ │ favicon.ico│ │ │ ├─css│ │ main.css│ │ │ ├─html│ │ index.html│ │ │ │ │ ├─img│ │ back.png│ │ │ ├─js│ │ ajax.js│ │ footer.js│ │ index.js│ │ nav.js│ │ public.js│ │ tity_nav.js│ │ │ └─lib│ flexible.js│ normalize.css│ swiper.css│ swiper.js│ └─config config.js webpack.config.base.js webpack.config.dev.js webpack.config.lint.js webpack.config.prod.js注释:想引用jquery而不是每个页面都引用只需要:引入jquery后如果开启lint检查模式 可以正常使用的前提是每个页面都require 一次webpack.config.base.jscnpm i jquery –saveconst ProvidePlugin = new webpack.ProvidePlugin({ $: ‘jquery’, jQuery: ‘jquery’,});引入sasswebpack.config.base.js{ // s?css => scss或者css test:/.s?css$/, // 不处理 node_modules 文件中的 css 文件 exclude: /node_modules/, // 抽取 css 文件到单独的文件夹 use: ExtractTextPlugin.extract({ fallback: “style-loader”, // 设置 css 的 publicPath publicPath: config.cssPublicPath,//在 css 中设置背景图像的 url 时,经常会找不到图片(默认会在 css 文件所在的文件夹中寻找),这里设置 extract-text-webpack-plugin 插件的 publicPath 为图片文件夹所在的目录,就可以顺利找到图片了 use: [{ loader:“css-loader”, options:{ // 开启 css 压缩 minimize:true, } }, { loader:“postcss-loader”, }, { loader:“sass-loader”, //启用sass 虽然在这只写了sass-loader 但还要下载node-sass } ] })},如果import了类似swiper这种库函数 但不处理modules里面的swiper,所以这里要允许除了node_modules里面的swiper的其他所有文件webpack.config.base.js{ test: /.js$/, exclude: /^node_modules*swiper$/, use: { loader: ‘babel-loader’, options: { presets: [’env’] } }},➳ github地址:点我 ...

December 29, 2018 · 10 min · jiezi

TOP100summit分享实录 | 有赞程功夫:打造最具竞争力的SaaS解决方案

本文内容节选自由msup主办的第七届全球软件案例研究峰会,现任有赞产品总监程功夫,分享的《有赞在SaaS领域的产品设计观》实录。本文为有赞产品总监程功夫在TOP100summit上的演讲实录。分享者程功夫,曾就职于房天下(搜房网),担任产品副总监的岗位。在阿里巴巴移动事业群就职期间,负责流量产品化的工作。目前就职于有赞,负责有赞美业的产品规划与管理工作。编者按:2018年11月30日-12月3日,第七届全球软件案例研究峰会在北京国家会议中心盛大开幕,现场解读2018年「壹佰案例榜单」。本文为有赞产品总监程功夫老师分享的《有赞在SaaS领域的产品设计观》案例实录。大家好,在有赞我们有一条金句——真诚的友谊来自于不断的自我介绍,为了跟各位保持长久的友谊,开始前我也简单的作个自我介绍:我是来自有赞的功夫,一位带有浓重湖北口音的产品经理,今天我要分享的主题是《打造最具竞争力的SaaS解决方案》。我们的CEO白鸦大家应该比较了解,现场应该有不少他的粉丝,不过在座的朋友可能对我们在做的一些事情还不是特别了解,所以接下来我会简单介绍下有赞。有赞是一个商家服务公司,我们通过产品和服务帮助互联网时代的生意人让生意更好做,商家使用我们的解决方案可以建立自己的私域流量,拓展互联网客群。我们是一个去中心化的交易平台,同时还间接服务了超过4亿的消费者,每天处理百万级的订单和数亿条消息。整家公司目前有超过2200名的小伙伴,其中有超过62%是纯技术人员,所以你可以说我们是一家典型地技术驱动型的公司。我们的产品线包括面向电商卖家的微商城、面向全渠道经营的有赞零售,而我今天要分享的案例主要来源于我们团队负责的一款面向美业商家的SaaS解决方案——有赞美业,它的目标用户是美容养生、美甲美睫、医疗美容、健身塑型以及牙科口腔的商家。商家经营解决方案的四个阶段记账这是比较早期比较原始的阶段,商家是通过一个厚厚的本子来管理店里面的经营情况,这个我相信大家应该有印象,甚至到现在还有很多商家是用这种解决方案。IT化然后,一部分追求效率的商家开始使用单机不联网的ERP去管理店里面的经营情况,相比原来数据不易丢失,也能省不少时间。与此同时,商家初步具备了事“后”分析的能力,比如美业商家经营里有个很重要的场景——预约,通常的场景大概是这样的:顾客打电话给前台预约某个时间做服务,前台打开系统录入后,告知技师客户姓名以及具体的服务时间和项目。店长在晚上复盘能看到今天每个时间段的客户预约量,接下来她可能会和老板商量要不要在明天采取一系列动作。互联网化这是当前处在的阶段,美团用了7年的时间让商家开始接受了互联网的工具,知道怎么在线上找流量进而引导进店。商家开始使用微信公众号和小程序客服功能和他的顾客进行互动,从顾客的角度来讲体验变得更好了,因为不再是冷冰冰的买卖关系。这个阶段解决方案创造的价值是,让商家具备了事“中”反应的能力,还是以刚才的预约为例:顾客打开公众号或小程序预约时,能看到商家门店里的动态流量,当她提交信息完成预约后,前台的预约看板里会以可视化的形式展示出来,与此同时,技师也会收到实时提醒。店长随时随地打开App能知道哪个房间、哪个技师处于空闲状态,进而决定是否开启一波限时促销的活动。智能化这是不久的将来我们一定会发生的,当然前提条件是有了足够多、颗粒度足够丰富的活数据,平台间的数据可以实时共享,到那个时候商家一定能具备事“前”分析的能力,比如,一个新顾客进店后,装在店里面的人脸识别系统会调取出这个顾客在其他店的消费记录,以及别的商家给她打上的标签,营销顾问再基于这些信息做针对性的营销。回到今天我要分享的主题——打造最有竞争力的SaaS解决方案,从我个人的角度来看,无非就是这三方面:事、人、思维。首先作为一个业务负责人你得定义每个阶段需要做哪些事情,哪些事情不做。想清楚了这些节奏后,你还需要找到一批适合做这些事情的小伙伴。最后,为了保持高效,你还得和大家一起总结形成属于你们特有的做事方式和思维。事先说“事”,把它放第一个的原因是因为它是源头,人其实就是资源,事是战略,先有战略再匹配资源。我们内部把SaaS会分为以下几个阶段。基础产品完善期这是打地基的阶段,通常需要花费3-5年的时间。你的目标不是做个平台割韭菜,所以需要满足商家经营的所有关键场景,像我们是做交易服务的,除了正向交易的预约、下单、结算、评价外,还有逆向交易的退款、维权等,其中退款又涉及到全部退还是部分退。同时由于你服务的客户越来越多,客户反过来给你提越来越多的需求,所以你还需要不断的增加功能。慢慢的,你会发现垒功能是这个阶段必须要经历的。行业产品深入期地基打牢后得开始关注重点行业的个性化需求,做更深入的探索,通常这个阶段需要2-3年的时间。为了让客户影响客户,你得开始总结沉淀一些案例,让标杆商家为你展台。生态建设期事实上,每个细分领域、每个商家的经营情况都有些差异。在时间和资源有限的情况下,你可以和行业参与者一起来努力。当然,为了满足更多个性化需求,产品上应该追求“可配置”的价值。想清楚每个阶段的节奏后,具体落地的时候还应该找到一些抓手。比如我们在17年找到的抓手就是小程序,同时我们能够看到一些趋势:电商迎来了以小程序为轴心的增量,同时我们认为经营在线化是新零售的前提。所以产品侧我们投入了很多资源在小程序上,商家也有比较明确的诉求——拥有一个好看的小程序。当我们把商家的诉求基于场景分析后,其实就是这两个部分:1.在有赞的后台提交开通小程序的资料、2.无需开发像搭积木一样拼装成小程序。后面这个看起来简单, 实际背后对应的需求是很复杂的。商家可能想给某个商品带来更多的曝光,可以拖拽个图片广告放在首页,为了带来更多的成交可以在下面再放一个多人拼团的活动,同时为了增强互动可以在左侧再放一个客服入口,最后为了让页面整体更有层次感,可以在上下两个模块之间增加一条辅助线。由于我们处在的行业,商家极度关注自己的品牌调性,所以小程序好看是非常重要的,在实际跑的过程中,我们发现很多商家不具备设计banner、图标、图片的能力,所以我们干脆给我们的标杆商家提供免费的设计服务,起初由我们内部的UI同学业余时间来支持,慢慢量越来越大,索性找了几个设计工作室和我们一起做。由于使用我们小程序的商家越来越多,他们不断地影响了其他商家,很快我们的价值亮点显得格外突出:用有赞美业的解决方案可以生成一个免费又好看的小程序。人事想好了,接下来就是找到合适的人来匹配这些事,坦率的说,过去的一年最让我捉襟见肘的就是人,我之前看过一篇报道,说小米的雷总在创业初期有一半的时间都是在招人。我是深有体会的,因为我这样的阶段都需要为人绞尽脑汁,何况他那么大的业务。在人这里我一直坚持的原则就是:找到合适的人,并摧毁他的认知。为什么要摧毁,我后面会讲。我们先来看看过去的十年,产品经理年龄和行业的分布情况。首先,我们来看下产品经理的年龄分布,大家能够看到其中有接近一半的产品经理是90后,其实最老的90后目前应该也就五六年的工作经验,我长说做产品经理来得早不如来得巧,为什么?我们试着把时间倒推到六年前,这帮最老的90后产品经理刚毕业就迎来了智能手机和移动互联网的爆发,小米卖了400万部碉堡了的手机,美团带来了千团大战,滴滴打车开始上线,这些产品深深地影响了一批人。另外一方面,我们再来看看目前市面上产品经理都分布在哪些行业,这是人人都是产品经理社区和起点学院在17年做的统计数据,互金、电商、教育是比例最高的前3名,他们接近占了一半,当然眼下互金应该没这么高的比例。他们中绝大多数所在的领域,套用个现在比较时髦的词是,消费互联网。近10年来,中国诞生了很多优秀的产品经理,准确的说是消费互联网型的产品经理,他们原来的经验适不适用我们在做的产业互联网?我用了两个模型来跟大家阐述『消费互联网』和『产业互联网』之间的差别,消费互联网的用户是零散存在的“点”状,决策群体就是那一个人,所以决策路径短,产品经理的思维方式通常是在一个点上做到极致,甚至他们还总结了一套心法口诀——极致、口碑、快。比如原来我们做浏览器的时候,最核心的目标就是打开网页的速度,几十几百号人都在围绕这个目标展开工作。最重要的一点,产品经理通常就是目标用户,所以他能天然进入使用者的角度考虑场景。而产业互联网的用户虽然大面上还是那波人,但往往是集中存在的“环”状,决策群体是一群人,所以决策路径长,长到什么程度呢,比如你要卖一套解决方案给他们,首先需要通过业务负责人的选型,然后他跟老板汇报,老板拍板后终于开始走内部的一系列流程,最后到财务那边审核打款。由于这里面涉及的角色众多,所以你得在多个场景上做到及格,原来的单点突破不再适用。当然,最最重要的,产品经理几乎不可能是目标用户,所以很难站在使用者的角度考虑问题。优秀的消费互联网型产品经理遍地都是,优秀的产业互联网型产品经理不可多得。我们的做法是找到原来行业里最优秀的那波人,然后摧毁他们的认知,建立属于产业互联网的产品思维。通常来说,人的认知会分为这几个阶段:不知道自己不知道、知道自己不知道、知道自己知道、不知道自己知道。由于我们招聘的要求格外高,进入我们公司的小伙伴在原来的岗位都是表现非常优秀的那波人,所以他们在加入的初期自信心是极度爆棚的,脑袋很大但腿短小,简称叫巨婴。我的做法是,第一步:制造冲突,让他们开始接受大量的信息。包括跟着运营的同事处理商家反馈的问题、去商家门店实习,过程中时不时丢一些负面的信息。等他意识到原来的思维方式不一定适用的时候再去和他一起复盘总结,所以这是第二步:启发并总结。后面这一步是重点,不能光打击,否则几次下来人心态都崩了。今年9月份我们这个行业有一个展会,持续大概3天的时间,会有几十万的商家和同行出现在这个展会,所以我们公司的销售全员出动并在现场布置有展台。而对我来说,这是一次千载难逢的打击小伙伴的机会,当即决定所有产品经理一起出发去广州,目的是了解上下游、同行,最重要的是跟我们的商家多一些交流。临走前还列了一个OKR,其中一个KR是每人每天获取8条销售线索,采取的Action是在人流量大的地方发传单。到了现场大家都傻眼了,从来没发过传单啊,既拉不下面子又不知道怎么宣传,本来说好我们每人负责一个区域,一不留神其中几个人就汇总到了一个区域,我当然知道那是因为没有安全感。至今还记得,有个小伙伴站在路口看着从面前走过的人群,左脚刚准备迈出去又缩回来了,拿在手里的传单拽得皱巴巴地。一天下来,每个人感慨万千。了解我们的朋友都知道我们在杭州总部开了一家主营水果和餐食的综合店,店里的员工都是我们自己的小伙伴,产品和技术会轮流去店里轮岗。当然,店里使用的系统也是我们的解决方案之一。如果非要用一个词总结我们招人最看重的特质,那就是:反脆弱性,因为这个行业太苦太累了,而且没有太多的成功经验可以借鉴,都不知道明天会遇到什么事情。但需要的是有那么一群人可以在不确定性中找到一条路径,把产品价值打磨的足够好。思维事和人都搞定了,为了提高效率,我们需要和所有的小伙伴建立属于自己的思维方式。以我过往的经验来看,很多产品经理想到一个idea的时候会立刻着手画原型,然后内部评审,接着推进开发。而在有赞,我们会要求所有的产品经理先回到产品定义部分,先全局考虑好场景和价值,然后再推进产品设计,往细了说就是任务、功能和界面,接着推进研发,最后是运营迭代。我们经常看到两个产品经理争论的面红耳赤,谁也不服谁,最后你发现俩人说的其实是两回事,背后的原因其实就是对场景的定义和理解不一致。在有赞,我们对场景的定义是:什么样的用户,在什么样的环境下,产生了什么样的动机,带着什么样的目标,采取了什么样的动作,和什么样的介质进行交互,完成了什么样的任务。为了保证需求生命周期的顺畅和容错,我们也有一系列的评审环节,第一个环节是产品委员会的评审,主要是我、业务方、PO等组成,这个环节会花费大量的时间去扣每个需求的产品定义,甚至刻意要求小伙伴把已经画好的『原型』收起来。设计按照这个方法论,我们会要求每个产品经理在启动原型之前,写类似下面的场景清单。最后在座的有朋友可能不理解为什么我的标题会用“解决方案”这个词,这得回到我们这家公司追求的目标上,我们是面向客户成功的服务体系,所以终极目标是“客户成功”,准确来说,是每一个客户成功。但想要客户成功不仅仅是一套经营系统,你还需要和商家一起探索如何帮他获取更多的流量和订单,行业变化太快了,很多商家内部员工的素质跟不上,他们也不知道如何培养员工,所以我们干脆做了一个有赞学院帮助商家培养他的员工。此外,我们在各地还形成了标杆商家的联盟,大家会一起探讨、交流经营思路。所以有赞追求的一直是最具竞争力的SaaS解决方案。以上内容来自程功夫老师的分享。声明:本文是由壹佰案例原创,转载请联系 meixu.feng@msup.com.cn

December 29, 2018 · 1 min · jiezi

10种方法实现一个tips带有描边的小箭头

转载:10种方法实现一个tips带有描边的小箭头我们在网页开发中实现一个tips时会有一个小箭头,实现这种方法的文章网上已经泛滥了,但有时实现这个小箭头不止只有单纯的三角它还有描边,今天我们就借那些现有的文章在深入一点来说说如何给tips小箭头描边,本章不涉及svg/canvas,没必要因为我讲的是css。主体样式:<div class=“dui-tips”><a href=“http://www.w3cbest.com”>w3cbest我是一个tips</a></div> .dui-tips{ position: relative; padding: 10px; text-align: center; border: 1px solid #f60; border-radius: 5px; background-color: #fff; }第一种border描边双层覆盖:就是大家常用的border,实现原理就是给其中一条边设置颜色宽度及样式,我这里使用了两个伪类进行折叠,将一个白色的覆盖在有颜色的伪类上面,再偏移1px来模拟实现1px的描边效果,代码如下:.dui-tips { &:before, &:after { position: absolute; left: 50%; display: table; width: 0; height: 0; content: ‘’; transform: translate(-50%, 0); border-width: 10px 10px 0 10px; border-style: solid; } &:before { z-index: 0; bottom: -10px; border-color: #f60 transparent transparent transparent; } &:after { z-index: 1; bottom: -8px; border-color: #fff transparent transparent transparent; }}第二种border描边结合滤镜drop-shadow属性:第二种是第一种的延伸,使用滤镜filter的drop-shadow描边来实现,box-shadow和drop-shadow实现不规则投影.dui-tips { &:after { position: absolute; left: 50%; display: table; width: 0; height: 0; content: ‘’; transform: translate(-50%, 0); border-width: 10px 10px 0 10px; border-style: solid; } &:after { bottom: -9px; border-color: #fff transparent transparent transparent; filter: drop-shadow(0px 2px 0px #f60); }}第三种通过特殊符号"◆“字体双层覆盖第三种方法和第一种类似,通过两层颜色叠加在有层级的偏移来实现.dui-tips { &:before, &:after { font-size: 24px; line-height: 18px; position: absolute; left: 50%; display: table; content: ‘◆’; transform: translate(-50%, 0); text-align: center; } &:before { z-index: 0; bottom: -10px; color: #f60; } &:after { z-index: 1; bottom: -8px; color: #fff; }}第四种通过text-shadow实现这种放发通过给文子设置1px的阴影来显描边效果.dui-tips { &:after { font-size: 24px; line-height: 18px; position: absolute; left: 50%; display: table; content: ‘◆’; transform: translate(-50%, 0); text-align: center; } &:after { z-index: 1; bottom: -8px; color: #fff; text-shadow: 0 2px 0 #f60; }}第五种 background双层覆盖这种方式设置两个宽度和高度分别为10px的方块背景,再给两层背景分别设置不同的颜色,再通过两层背景颜色叠加,经过层级偏移再有transform的rotate属性旋转角度,来实现箭头的朝向。.dui-tips { &:before, &:after { position: absolute; left: 50%; display: table; width: 10px; height: 10px; content: ‘’; margin-left: -5px; transform: rotate(-45deg); } &:before { z-index: 0; bottom: -6px; background-color: #f60; } &:after { z-index: 1; bottom: -5px; background-color: #fff; }}第六种background和border背景描边旋转此方法就是设置一个宽度和高度分别为10px的方块背景,然后背景相邻的两条边描边再有transform的rotate属性旋转角度,来实现箭头的朝向。.dui-tips { &:after { position: absolute; left: 50%; display: table; width: 10px; height: 10px; margin-left: -5px; content: ‘’; transform: rotate(-45deg); } &:after { z-index: 1; bottom: -6px; border-bottom: 1px solid #f60; border-left: 1px solid #f60; background-color: #fff; }}第七种background和box-shadow.dui-tips { &:after { position: absolute; left: 50%; display: table; width: 10px; height: 10px; content: ‘’; margin-left: -5px; transform: rotate(-45deg); } &:after { z-index: 1; bottom: -5px; background-color: #fff; box-shadow: -1px 1px 0 #f60; }}第八种linear-gradient.dui-tips{ &:before, &:after{ position: absolute; left: 50%; display: table; width: 10px; height: 10px; content: ‘’; margin-left: -5px; transform: rotate(-135deg); } &:before { z-index: 0; bottom: -6px; background: linear-gradient(-45deg, transparent 7px, #f60 0); } &:after { z-index: 1; bottom: -5px; background: linear-gradient(-45deg, transparent 7px, #fff 0); }}第九种linear-gradient和box-shadow.dui-tips{ &:after{ position: absolute; left: 50%; display: table; width: 10px; height: 10px; content: ‘’; margin-left: -5px; transform: rotate(-135deg); } &:after { z-index: 1; bottom: -5px; background: linear-gradient(-45deg, transparent 7px, #fff 0); box-shadow: -1px -1px 0 #f60 }}第十种linear-gradient和border.dui-tips{ &:after{ position: absolute; left: 50%; display: table; width: 10px; height: 10px; content: ‘’; margin-left: -5px; transform: rotate(-135deg); } &:after { z-index: 1; bottom: -6px; background: linear-gradient(-45deg, transparent 7px, #fff 0); border-top: 1px solid #f60; border-left: 1px solid #f60; }}转载:10种方法实现一个tips带有描边的小箭头 ...

December 25, 2018 · 2 min · jiezi

Vue2.0 + ElementUI 手写权限管理系统后台模板(二)——权限管理

权限验证页面级别权限路由:默认挂载不需要权限的路由,例如:登录、主页。需要权限的页面通过 router.addRoutes(点击查看官方文档) 动态添加更多的路由规则,404拦截页面需要放在路由表的最后,否则 /404 后面的路由会被404拦截,通过路由元信息meta(点击查看官方文档)记录路由需要的权限。为了菜单列表可以被翻译,路由表的 name 属性值通过 i18n 的英文对照表来获取,也可以直接写英文名称,如 name: routeNmae.builtInIcon 可以直接写成 name: “builtInIcon”,凭个人喜好// src/router/index.jsimport en from ‘../i18n/lang/en’ // 路由名字 name import Vue from ‘vue’import Router from ‘vue-router’import CommerViews from ‘@/views/commerViews’import Login from ‘@/views/login/index’import Layout from ‘@/views/layout/layout’import HomeMain from ‘@/views/index/mainIndex’// 不是必须加载的组件使用懒加载const Icon = () => import(’@/views/icon/index’)const Upload = () => import(’@/views/upload/upload’)const Markdown = () => import(’@/views/markdown/markdownView’)const NotFound = () => import(’@/page404’)Vue.use(Router)let routeNmae = en.routeNmae// 不需要权限的路由let defaultRouter = [ { path: ‘/’, redirect: ‘/index’, hidden: true, children: [] }, { path: ‘/login’, component: Login, name: ‘’, hidden: true, children: [] }, { path: ‘/index’, iconCls: ‘fa fa-dashboard’, // 菜单图标,直接填写字体图标的 class name: routeNmae.home, component: Layout, alone: true, children: [ { path: ‘/index’, iconCls: ‘fa fa-dashboard’, name: ‘主页’, component: HomeMain, children: [] } ] }, { path: ‘/404’, component: NotFound, name: ‘404’, hidden: true, children: [] },]// 需要 addRouters 动态加载的路由 let addRouter = [ { path: ‘/’, iconCls: ‘fa fa-server’, name: routeNmae.multiDirectory, component: Layout, children: [ { path: ‘/erji1’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu2-1’], component: Erji, children: [] }, { path: ‘/erji3’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu2-3’], component: CommerViews, // 无限极菜单的容器 超过三级菜单父级容器需要使用 CommerViews children: [ { path: ‘/sanji2’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu3-2’], component: Sanji2, children: [] }, { path: ‘/sanji3’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu3-3’], component: CommerViews, children: [ { path: ‘/siji’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu4-1’], component: Siji, children: [] }, { path: ‘/siji1’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu4-2’], component: CommerViews, children: [ { path: ‘/wuji’, iconCls: ‘fa fa-server’, name: routeNmae[‘menu5-1’], component: Wuji, children: [] } ] } ] } ] } ] }, { path: ‘/’, iconCls: ’el-icon-edit’, // 图标样式class name: routeNmae.editor, component: Layout, meta: {role: [‘superAdmin’, ‘admin’]}, // 需要权限 ‘superAdmin’, ‘admin’。meta属性可以放在父级,验证父级和所有子菜单,也可以放在子级单独验证某一个子菜单 children: [ { path: ‘/markdown’, iconCls: ‘fa fa-file-code-o’, // 图标样式class name: routeNmae.markdown, component: Markdown, children: [] } ] }, { path: ‘*’, redirect: ‘/404’, hidden: true, children: [] },]export default new Router({ routes: defaultRouter})export {defaultRouter, addRouter}然后通过 token 获取当前登录用户的个人信息,在router被挂载到Vue之前和需要权限的路由表做对比,筛选出当前角色的动态路由表,// main.js// 获取角色信息,根据用户权限动态加载路由router.beforeEach((to, from, next) => { if (store.getters.token) { // 查看 token 是否存在 store.dispatch(‘setToken’, store.getters.token) // 每次操作都重新写入 token,延长有效会话时间 if (to.path === ‘/login’) { next({path: ‘/’}) } else { if (!store.getters.info.role) { // 查看是否有当前用户角色,如果没有则获取角色信息 !async function getAddRouters () { await store.dispatch(‘getInfo’, store.getters.token) // 通过token获取角色信息 await store.dispatch(’newRoutes’, store.getters.info.role) // 通过权限筛选新路由表 await router.addRoutes(store.getters.addRouters) // 动态加载新路由表 next({path: ‘/index’}) }() } else { let is404 = to.matched.some(record => { // 404页面拦截 if(record.meta.role){ // 没有权限的页面,跳转的404页面 return record.meta.role.indexOf(store.getters.info.role) === -1 } }) if(is404){ next({path: ‘/404’}) return false } next() } } } else { if (to.path === ‘/login’) { next() } next({path: ‘/login’}) }})actions: getInfo// src/vuex/modules/role.jsstate: { info: ’’ // 每次刷新都要通过token请求个人信息来筛选动态路由 }, mutations: { getInfo (state, token) { // 省略 axios 请求代码 通过 token 向后台请求用户权限等信息,这里用假数据赋值 state.info = { role: ‘superAdmin’, permissions: ‘超级管理员’ } // 将 info 存储在 sessionStorage里, 按钮指令权限将会用到 sessionStorage.setItem(‘info’, JSON.stringify(store.getters.info)) }, setRole (state, options) { // 切换角色,测试权限管理 state.info = { role: options.role, permissions: options.permissions } sessionStorage.setItem(‘info’, JSON.stringify(store.getters.info)); // 权限切换后要根据新权限重新获取新路由,再走一遍流程 store.dispatch(’newRoutes’, options.role) router.addRoutes(store.getters.addRouters) } }, actions: { getInfo ({commit}, token) { commit(‘getInfo’, token) }, setRole ({commit}, options){// 切换角色,测试权限管理,不需要可以删除 commit(‘setRole’, options) } }actions: newRoutes// src/vuex/modules/routerData.jsimport {defaultRouter, addRouter} from ‘@/router/index’const routerData = {state: { routers: [], addRouters: [] }, mutations: { setRouters: (state, routers) => { state.addRouters = routers // 保存动态路由用来addRouter state.routers = defaultRouter.concat(routers) // 所有有权限的路由表,用来生成菜单列表 } }, actions: { newRoutes ({commit}, role) { // 通过递归路由表,删除掉没有权限的路由 function eachSelect (routers, userRole) { for (let j = 0; j < routers.length; j++) { if (routers[j].meta && routers[j].meta.role.length && routers[j].meta.role.indexOf(userRole) === -1) { // 如果没有权限就删除该路由,如果是父级路由没权限,所有子菜单就更没权限了,所以一并删除 routers.splice(j, 1) j = j !== 0 ? j - 1 : j // 删除掉没有权限的路由后,下标应该停止 +1,保持不变,如果下标是 0的话删除之后依然等于0 } if (routers[j].children && routers[j].children.length) { // 如果包含子元素就递归执行 eachSelect(routers[j].children, userRole) } } } // 拷贝这个数组是因为做权限测试的时候可以从低级切回到高级角色,仅限演示,正式开发时省略这步直接使用 addRouter // 仅限演示 let newArr = […addRouter] eachSelect(newArr, role) commit(‘setRouters’, newArr) // 正式开发 // eachSelect(addRouter, role) // commit(‘setRouters’, addRouter) } }}export default routerData按钮级别权限验证通过自定义指令获取当前按钮所需的有哪些权限,然后和当前用户的权限对比,如果没有权限则删除按钮// btnPermission.jsimport Vue from ‘vue’Vue.directive(‘roleBtn’,{ bind:function (el,binding) { let roleArr = binding.value; // 获取按钮所需权限 let userRole = JSON.parse(sessionStorage.getItem(‘info’)).role // 获取当前用户权限 if (roleArr && roleArr.indexOf(userRole) !== -1) { return false } else { el.parentNode.removeChild(el); } }})export default Vue使用自定义指令权限<el-button type=“primary” plain size=“medium”>查看</el-button><el-button type=“primary” plain size=“medium” v-role-btn="[‘admin’]">添加</el-button><el-button type=“danger” plain size=“medium” v-role-btn="[‘superAdmin’]">删除</el-button><el-button type=“primary” plain size=“medium” v-role-btn="[‘superAdmin’,‘admin’]">修改</el-button> ...

December 17, 2018 · 4 min · jiezi

css-in-js 探讨

Web开发是需要掌握多种技术。我们习惯于与多种语言密切合作。而且,随着开发Web应用程序变得越来越普遍和差别细微化,我们经常寻找创造性的方法来弥合这些语言之间的差距,从而使我们的开发环境和工作流程更容易,更高效。最常见的示例通常是使用模板语言时。例如,可以使用一种语言来生成更详细的语言(通常是HTML)的代码。这是前端框架的关键作用之一 -操作HTML。这个领域最出名的就是JSX,因为它不是真正的模板语言;它是JavaScript的语法扩展,它使得使用HTML非常简洁。Web应用程序经历了许多状态组合,单独管理状态通常很有挑战性。这就是为什么CSS有时会被淘汰的原因 - 即使通过不同的状态和媒体查询管理样式同样重要且同样具有挑战性。在这个由两部分组成的系列中,我想将CSS放在聚光灯下,并探索弥合它与JavaScript之间的差距。在本系列中,我将假设您正在使用像webpack这样的模块解析器。因此,我将在我的示例中使用React,但相同或类似的原则适用于其他JavaScript框架,包括Vue。CSS领域正朝着多个方向发展,因为要解决许多挑战并且没有“正确”的路径。我一直在花费大量精力尝试各种方法,主要是在个人项目上,所以这个系列的目的只是告知,而不是给你解决方案。CSS的挑战在深入研究代码之前,有必要解释Web应用程序样式化方面最显着的挑战。 我将在本系列中讨论的是范围,条件和动态样式以及可重用性。作用域作用域定是众所周知的CSS挑战,它的目的是编写不会影响到组件外部的样式,从而避免意外的副作用。 我们希望在不影响编码体验的情况下实现功能。条件和动态样式虽然前端应用程序中的状态开始变得越来越先进,但CSS仍然是静态的。 我们只能有条件地应用样式集 - 如果按钮是主要的,我们可能会应用“primary”类并在单独的CSS文件中定义它的样式以应用它在屏幕上的样式。 有几个预定义的按钮变化是可管理的,但如果我们想要有各种按钮,如为Twitter,Facebook,Pinterest定制的特定按钮,可能还会有其他很多种? 我们真正想要做的只是传递颜色并使用CSS定义状态,如悬停,焦点,禁用等。这称为动态样式,因为我们不再在预定义样式之间切换 - 我们不知道接下来会发生什么。 可能会想到内联样式来解决此问题,但它们不支持伪类,属性选择器,媒体查询等。可重用性重用规则集,媒体查询等是我最近很少看到的一个主题,因为它已经被Sass和Less等预处理器解决了。 但是我仍然想在这个系列中再次提起它。我将列出一些处理这些挑战的技术以及它们在本系列的两个部分中的局限性。 没有任何技术优于其他技术,它们甚至不相互排斥; 您可以选择一个或组合它们,具体取决于您的决定是否能改善您的项目质量。开始吧我们将使用名为Photo的示例组件演示不同的样式技术。 我们将呈现可能具有圆角的响应式图像,同时将替代文本显示为标题。 它会像这样使用:<Photo publicId=“balloons” alt=“Hot air balloons!” rounded />在构建实际组件之前,我们将抽象出srcSet属性以保持示例代码简洁。 那么,让我们创建一个带有两个实用程序的utils.js文件,用于使用Cloudinary生成不同宽度的图像:import { Cloudinary } from ‘cloudinary-core’const cl = Cloudinary.new({ cloud_name: ‘demo’, secure: true })export const getSrc = ({ publicId, width }) => cl.url(publicId, { crop: ‘scale’, width })export const getSrcSet = ({ publicId, widths }) => widths .map(width => ${getSrc({ publicId, width })} ${width}w) .join(’, ‘)我们设置Cloudinary实例以使用Cloudinary的演示云名称,以及根据指定选项为图像publicId生成URL的url方法。 我们只对修改此组件的宽度感兴趣。我们将分别将这些实用程序用于src和srcset属性:getSrc({ publicId: ‘balloons’, width: 200 })// => ‘https://res.cloudinary.com/demo/image/upload/c_scale,w_200/balloons'getSrcSet({ publicId: ‘balloons’, widths: [200, 400] })// => ‘https://res.cloudinary.com/demo/image/upload/c_scale,w_200/balloons 200w, https://res.cloudinary.com/demo/image/upload/c_scale,w_400/balloons 400w’如果你不熟悉srcset和sizes属性,我建议先阅读一下有关响应式图像的内容。 这样,您可以更轻松地按照示例进行操作。CSS-in-JSCSS-in-JS是一种样式方法,它将CSS模型抽象到组件级别,而不是文档级别。 这个想法是CSS可以限定为特定组件 - 并且只限于该组件 - 以使这些特定样式不与其他组件共享或泄露到其他组件,并且仅在需要时才调用。 CSS-in-JS库通过在<head>中插入<style>标签在运行时创建样式。使用这个概念的第一个库是JSS。 以下是使用其语法的示例:import React from ‘react’import injectSheet from ‘react-jss’import { getSrc, getSrcSet } from ‘./utils’const styles = { photo: { width: 200, ‘@media (min-width: 30rem)’: { width: 400, }, borderRadius: props => (props.rounded ? ‘1rem’ : 0), },}const Photo = ({ classes, publicId, alt }) => ( <figure> <img className={classes.photo} src={getSrc({ publicId, width: 200 })} srcSet={getSrcSet({ publicId, widths: [200, 400, 800] })} sizes="(min-width: 30rem) 400px, 200px" /> <figcaption>{alt}</figcaption> </figure>)Photo.defaultProps = { rounded: false,}export default injectSheet(styles)(Photo)乍一看,样式对象看起来像用对象表示法编写的CSS,带有附加功能,比如传递一个函数来设置基于props的值。 生成的类是唯一的,因此您永远不必担心它们与其他样式冲突。 换句话说,你可以自由的使用作用域! 这就是大多数CSS-in-JS库的工作方式 - 当然,我们将在功能和语法方面进行一些改进。您可以通过属性看到渲染图像的宽度从200px开始,然后当视口宽度变为至少30rem时,宽度增加到400px宽。 我们生成了额外的800宽度,以覆盖更大的屏幕密度:1x screens 使用 200 and 4002x screens 使用 400 and 800styled-components是另一个CSS-in-JS库,但是使用更熟悉的语法巧妙地使用模板文字而不是对象看起来更像CSS:import React from ‘react’import styled, { css } from ‘styled-components’import { getSrc, getSrcSet } from ‘./utils’const mediaQuery = ‘(min-width: 30rem)‘const roundedStyle = css border-radius: 1rem;const Image = styled.img width: 200px; @media ${mediaQuery} { width: 400px; } ${props =&gt; props.rounded &amp;&amp; roundedStyle}; const Photo = ({ publicId, alt, rounded }) => ( <figure> <Image src={getSrc({ publicId, width: 200 })} srcSet={getSrcSet({ publicId, widths: [200, 400, 800] })} sizes={${mediaQuery} 400px, 200px} rounded={rounded} /> <figcaption>{alt}</figcaption> </figure>)Photo.defaultProps = { rounded: false,}export default Photo我们经常创建语义中性元素,如<div>和<span>,仅用于样式目的。这个库以及许多其他库允许我们在一个动作中创建和设置它们。我最喜欢这种语法的好处是它就像常规的CSS,减去插值。这意味着我们可以更轻松地迁移CSS代码,并且我们可以使用现有的css知识,而不必熟悉在对象语法中编写CSS。请注意,我们可以在我们的样式中插入几乎任何东西。此特定示例演示了如何将媒体查询保存在变量中并在多个位置重用它。响应式图像是一个很好的用例,因为sizes属性基本上包含CSS,所以我们可以使用JavaScript来使代码更简洁。假设我们决定在视觉上隐藏字幕,但仍然可以让屏幕阅读器访问它。我知道实现这一目标的更好方法是使用alt属性,但为了这个例子,让我们使用不同的方式。我们可以使用一个名为polished的样式mixin库 - 它适用于CSS-in-JS库,非常适合我们的示例。这个库包含一个名为hideVisually的mixin,它正是我们想要的,我们可以通过插入它的返回值来使用它:import { hideVisually } from ‘polished’const Caption = styled.figcaption ${hideVisually()};<Caption>{alt}</Caption>即使hideVisually输出一个对象,样式组件库也知道如何将其作为样式进行插值。CSS-in-JS库具有许多高级功能,如主题,供应商前缀甚至内联关键CSS,这使得完全停止编写CSS文件变得容易。 此时,您可以开始了解为什么CSS-in-JS成为一个诱人的概念。缺点和局限CSS-in-JS的明显缺点是它引入了一个运行时:需要通过JavaScript加载,解析和执行样式。 CSS-in-JS库的作者正在添加各种智能优化,如Babel插件,但仍然存在一些运行时成本。同样重要的是要注意PostCSS没有解析这些库,因为PostCSS不是设计用于运行时的。许多人使用stylis作为结果,因为它更快。这意味着我们遗憾的是无法使用PostCSS插件。我要提到的最后一个缺点是工具。 CSS-in-JS正在以非常快的速度发展,文本编辑器扩展,linters,代码格式化等等需要追赶新功能以保持同等水平。例如,人们正在使用VS Code扩展样式组件来表示类似情感的CSS-in-JS库,即使它们并非都具有相同的功能。我甚至看到提议功能的API选择受到保留语法突出显示的目标的影响!未来有两个新的CSS-in-JS库,Linaria和astroturf,它们通过将CSS提取到文件中来管理零运行时。 它们的API类似于样式组件,但它们的功能和目标各不相同。Linaria的目标是通过内置函数(如作用域,嵌套和供应商前缀)来模仿CSS-in-JS库的API,如样式组件。 相反,astroturf是基于CSS模块构建的,具有有限的插值功能,并鼓励使用CSS生态系统而不是使用JavaScript。结论CSS-in-JS是一体化的样式解决方案,用于弥合CSS和JavaScript之间的差距。 它们易于使用,并且包含有用的内置优化 - 但所有这些都需要付出代价。 最值得注意的是,通过使用CSS-in-JS,我们基本上从CSS生态系统中退出并使用JavaScript来解决我们的问题。零运行时解决方案通过恢复CSS工具来缓解一些缺点,这些工具将CSS-in-JS讨论提升到更有趣的水平。 与CSS-in-JS相比,预处理工具的实际限制是什么? 这将在本系列的下一部分中介绍。 ...

December 10, 2018 · 2 min · jiezi

css3实现颤动的动画

需求页面要做一个活动入口,不能太显眼,但是又要用户能一眼就看出来。演示https://jsfiddle.net/vtsxc18q/实现 (部分动画代码)@keyframes chanDong { 5% { -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); } 6%, 8%, 10%, 12% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 10deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 10deg); } 7%, 9%, 11% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -10deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -10deg); } 13% { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } }Github 代码https://github.com/lmxdawn/te…另附一个 vue 搭建的后台管理另附一个 vue 搭建的后台管理 https://segmentfault.com/a/11… ...

October 19, 2018 · 1 min · jiezi