如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
图片三个网站的图片搜索结果进行爬取和下载。
首先通过爬虫过程中遇到的问题,总结如下:
1、一次页面加载的图片数量各个网站是不定的,每翻一页就会刷新一次,对于数据量大的爬虫几乎都需要用到翻页功能,有如下两种方式:
1)通过网站上的网址进行刷新,例如必应图片:
url = 'http://cn.bing.com/images/async?q={0}&first={1}&count=35&relp=35&lostate=r
&mmasync=1&dgState=x*175_y*848_h*199_c*1_i*106_r*0'
2)通过selenium来实现模拟鼠标操作来进行翻页,这一点会在Google图片爬取的时候进行讲解。
2、每个网站应用的图片加载技术都不一样,对于静态加载的网站爬取图片非常容易,因为每张图片的url都直接显示在网页源码中,找到每张图片对应的url即可使用urlretrieve()进行下载。然而对于动态加载的网站就比较复杂,需要具体问题具体分析,例如google图片每次就会加载35张图片(只能得到35张图片的url),当滚动一次后网页并不刷新但是会再次加载一批图片,与前面加载完成的都一起显示在网页源码中。对于动态加载的网站我推荐使用selenium库来爬取。
对于爬取图片的流程基本如下(对于可以通过网址实现翻页或者无需翻页的网站):
1. 找到你需要爬取图片的网站。(以必应为例)
2. 使用google元素检查(其他的没用过不做介绍)来查看网页源码。
3. 使用左上角的元素检查来找到对应图片的代码。
4. 通过观察找到翻页的规律(有些网站的动态加载是完全看不出来的,这种方法不推荐)
从图中可以看到标签div,class=’dgControl hover’中的data-nexturl的内容随着我们滚动页面翻页first会一直改变,q=二进制码即我们关键字的二进制表示形式。加上前缀之后由此我们才得到了我们要用的url。
5. 我们将网页的源码放进BeautifulSoup中,代码如下:
url = 'http://cn.bing.com/images/async?q={0}&first={1}&count=35&relp=35&lostate=r&mmasync=1&dgState=x*175_y*848_h*199_c*1_i*106_r*0' agent = {'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.165063 Safari/537.36 AppEngine-Google."}
page1 = urllib.request.Request(url.format(InputData, i*35+1), headers=agent)
page = urllib.request.urlopen(page1)
soup = BeautifulSoup(page.read(), 'html.parser')
我们得到的soup是一个class ‘bs4.BeautifulSoup’对象,可以直接对其进行操作,具体内容自行查找。
首先选取我们需要的url所在的class,如下图:
波浪线是我们需要的url。
我们由下面的代码得到我们需要的url:
if not os.path.exists("./" + word):#创建文件夹 os.mkdir('./' + word) for StepOne in soup.select('.mimg'):
link=StepOne.attrs['src']#将得到的<class 'bs4.element.Tag'>转化为字典形式并取src对应的value。 count = len(os.listdir('./' + word)) + 1 SaveImage(link,word,count)#调用函数保存得到的图片。
最后调用urlretrieve()函数下载我们得到的图片url,代码如下:
try:
time.sleep(0.2)
urllib.request.urlretrieve(link,'./'+InputData+'/'+str(count)+'.jpg') except urllib.error.HTTPError as urllib_err:
print(urllib_err) except Exception as err:
time.sleep(1)
print(err)
print("产生未知错误,放弃保存") else:
print("图+1,已有" + str(count) + "张图")
这里需要强调是像前面的打开网址和现在的下载图片都需要使用try except进行错误测试,否则出错时程序很容易崩溃,大大浪费了数据采集的时间。
以上就是对单个页面进行数据采集的流程,紧接着改变url中{1}进行翻页操作继续采集下一页。
数据采集结果如下:
有问题请留言。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
如何从众多的设计点中找到一个清晰的设计主线呢?只需从3个方面切入。小明的设计故事:身为设计师的小明,刚刚遇到下发的设计需求,看了半天需求,无从下手。于是疯狂寻找竞品去借鉴,去素材网站寻找素材拼凑。
如果在设计工作中遇到与小明相同的情况:没有设计头绪,大脑一片空白,画着不一定能过审的草稿时,请继续阅读下面的文章,希望大家能从作者的设计总结中有所启发。
目录:
什么是设计点?
设计点是设计师通过设计手段介入设计任务的一个节点,比如:设计目标 、设计风格 、用户行为 、用户情绪 、信息表达等都是设计的切入点,设计点能够影响设计的风格走向和设计师的创作思路。
那如何从众多的设计点中找到一个清晰的设计主线呢?只需从3个方面切入。
下图是阿里巴巴UED 的设计理论,同程序员提倡的「不造重复的轮子」一样,设计理论也没有必要去反复总结类似的。目前阿里的这个设计理论,很好的支持了包含大型项目到中型项目的各个环节,易于理解,且和我们的工作认知贴近,是一个很好的入门方法。
我们通过定义业务目标和聚焦设计目标,来最终实现设计的产出。
下图是平台营销活动的设计5个要义,其核心也是业务目标。
通过几个的设计方法的展示,我们可以看出,处于上游业务目标的重要性。
只有业务目标和设计目标一致的时候,我们的设计工作才有意义。当我们评判我们的设计结果时,除了设计的数据指标外,能快速判断设计方案比迭代之前更优的指标就是是否符合业务目标,是否更贴近用户的诉求。
1. 切入模型
根据工具模型我们从业务目标出发,去定义设计目标从而得出设计方向。
2. 明确业务诉求
3. 得出业务目标
用分享讲义的策略给用户带来学习交流机会和学习成就感,达到拉新和活跃用户目的。
4. 视觉推导
5. 案例
视觉设计师,尤其是运营设计师一定要具有交互思维,作为全链路设计目标的我们,掌握交互思维,能更好的理解产品文档和规避更多的设计错误,从而准确引导用户操作路径。
方法:了解页面中的功能交互流程,梳理用户操作行为路径,可以对行为步骤中的信息内容进行归类分组提供依据。
切入模型:
常见的方法有:情感化、原子化、组件化、游戏化等等。
方法:分解设计需求,归纳设计模块,运用已知的设计类型进行视觉化设计。
1. 提取仪式感设计点-晒成绩项目
仪式感的作用:通过用户在体验过程中由产品功能实现—交互操作—体验心理变化建立,形成对价值观的建立,是给用户带来更高层次的享受。
从四个层面理解仪式感:权威感、尊重存在感、期待感、荣誉感的意义。通过分解设计内容来发现机会点,插入仪式感设计方法。
视觉推导:
案例:
2. 提取情感化设计点
情感化设计3要素:
案例:
3. 提取游戏化设计点
将游戏机制运用于非游戏场景。比如:要想鼓励用户多参与交互,你可以在 APP 加入「挑战」这类的游戏元素,用户可以参与挑战,通过连续抽奖,并获得相应奖赏,从而达到预期目的。
案例:
寻找设计点就是拆解与分析的过程。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
专注于做好一件小事,哪怕是做不好也用心去做,小到搭建一个精美的网格系统,做好一个字体的拐角……先看一下我的往期设计案例。
对于很多刚接触字体设计的同学经常会遇到一种情况那就是想法高大上,结果很悲伤,为什么会造成这样的结果?归根结底是对字体设计本身了解还不够细致就照葫芦画瓢直接上,为了避免这种尴尬的结果,我们应该在开始着手做字体之前要做好各项准备工作,不断去浏览优秀的字体设计从中寻找设计的感觉,确定感觉后建立网格系统,开始逐步设计字体。我在做字体设计的时候会把握几个步骤「建网格」——「选字体」——「拆字体」——「绘笔画」——「绑骨架」——「粗与细」——「取与舍」——「磨细节」——「去感受」。
下面我们就以大家最常见的矩阵字体为例来给大家分享如何制作字体。
1. 建网格
建立网格系统,万丈高楼平地起,要做一款扎实的字体离不开网格系统的规范。
2. 拆字体
以「燃」为例——选取一个默认字体,按照字体结构对笔画进行拆分。
3. 绘笔画
将拆分出的笔画用横线和竖线在网格系统里进行笔画重绘,此时不要做细节,撇、捺和点根据自身走向和结构特点也归属为横竖线。
4. 绑骨架
拆分绘制的字体笔画就是字体的骨骼,笔画间的连接处可以理解成是人体的关节,关节的意义在于保证字体稳固的同时又灵活多变,字体的笔画可以根据视觉需要围绕关节在一定范围内做活动,也可调整长短比例。
5. 粗与细
笔画的粗细与硬度由你想要的字体气质来决定,细笔画与曲笔画柔美气质,粗笔画与直笔画沉稳大气,虽说设计是一种感觉,但是这种感觉对于初学者来说很难把控,所以跟大家共享一下常用的几种笔画的粗细,在1000PX*1000PX画板里采用6px,10px和20px为基础笔画粗细,根据想要的业务气质选取即可。
6. 解与构
常见的字体结构有「上下结构」「上中下结构」「左右结构」「左中右结构」「半包围结构」和「全包围结构」。其中「上下结构」中着重强调占比较小的那部分笔画,进而达到字体本身的平衡,例如「感」字着重设计心字;「上中下结构」中一般会在不影响识别性的前提下去掉中间部分横行笔画,进而达到字体本身的平衡,例如「享」字着重设计口字;左中右结构中在不影响识别性的前提下会简化左边部分笔画,进而达到字体本身的平衡,例如「燃」字着重设计火字。
7. 取与舍
笔画变粗后整个字体笔画间的空间比例会受到一定影响,因此为了字体的美观度和透气性我们会对字体结构进行一些取舍和整合。
8. 磨细节
为了让字体看起来更加舒适,我们将字体的拐角做圆,做圆角的同时也要根据网格系统来调整圆的度数。
9. 去感受
打磨整体字体,继续刻画细节。
注意:在一组字里,每个单字的结构都存在差异,适当调整字体内部的比例,形成感官上舒适的笔势,对保持视觉上大小一致很重要。汉字字体类型繁多,但是如果我们用几何法则来划分字体类型其实大致可以归纳为三种:方形,圆形和三角形,从面积上来看方形和圆形的面积最大,三角形次之,所以我们为了保持字重大小的一致性需要调整他们之间的大小比例,做到大小均匀,笔画一致,结构严谨和间隙适中。
△ 图源:ElethomHunter
为了拉出字体的气质,一般会把字体做的稍微偏瘦长一些。
字体设计的手段是多种多样的,每个设计师都有自己擅长的切入点,最后的结果是自己想要的就好。上述的分享希望能给字体设计初学者一点帮助,也欢迎各位同行大神交流切磋。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
JS页面代码段:
-
const app = getApp()
-
let goodsList = [
-
{ actEndTime: '2018-07-21 21:00:34' },
-
{ actEndTime: '2028-07-17 21:00:37' },
-
{ actEndTime: '2018-09-21 05:00:59' },
-
{ actEndTime: '2018-08-19 07:00:48' },
-
{ actEndTime: '2018-08-28 03:00:11' }
-
]
-
Page({
-
-
data: {
-
countDownList: [],
-
actEndTimeList: []
-
},
-
-
onLoad: function () {
-
let endTimeList = [];
-
// 将活动的结束时间参数提成一个单独的数组,方便操作
-
goodsList.forEach(o => { endTimeList.push(o.actEndTime) })
-
this.setData({ actEndTimeList: endTimeList });
-
// 执行倒计时函数
-
this.countDown();
-
},
-
-
//当时间小于两位数时十位数补零。
-
timeFormat: function (param) {//小于10的格式化函数
-
return param < 10 ? '0' + param : param;
-
},
-
-
//倒计时函数
-
countDown: function () {
-
// 获取当前时间,同时得到活动结束时间数组
-
let newTime = new Date().getTime();//当前时间
-
let endTimeList = this.data.actEndTimeList;//结束时间的数组集合
-
let countDownArr = [];//初始化倒计时数组
-
-
// 对结束时间进行处理渲染到页面
-
endTimeList.forEach(o => {
-
let endTime = new Date(o).getTime();
-
let obj = null;
-
// 如果活动未结束,对时间进行处理
-
if (endTime - newTime > 0) {
-
let time = (endTime - newTime) / 1000;
-
// 获取天、时、分、秒
-
let day = parseInt(time / (60 * 60 * 24));
-
let hou = parseInt(time % (60 * 60 * 24) / 3600);
-
let min = parseInt(time % (60 * 60 * 24) % 3600 / 60);
-
let sec = parseInt(time % (60 * 60 * 24) % 3600 % 60);
-
obj = {
-
day: this.timeFormat(day),
-
hou: this.timeFormat(hou),
-
min: this.timeFormat(min),
-
sec: this.timeFormat(sec)
-
}
-
} else {//活动已结束,全部设置为'00'
-
obj = {
-
day: '00',
-
hou: '00',
-
min: '00',
-
sec: '00'
-
}
-
}
-
countDownArr.push(obj);
-
})
-
//每隔一秒执行一次倒计时函数, 渲染
-
this.setData({ countDownList: countDownArr })
-
setTimeout(this.countDown, 1000);
-
}
-
})
wxml页面代码段
-
<view class='tui-countdown-content' wx:for="{{countDownList}}" wx:key="countDownList">
-
距结束
-
<text class='tui-conutdown-box'>{{item.day}}</text>天
-
<text class='tui-conutdown-box'>{{item.hou}}</text>时
-
<text class='tui-conutdown-box'>{{item.min}}</text>分
-
<text class='tui-conutdown-box tui-countdown-bg'>{{item.sec}}</text>秒
-
</view>
-
wxss页面代码段
-
page{
-
background: #f5f5f5;
-
}
-
.tui-countdown-content{
-
height: 50px;
-
line-height: 50px;
-
text-align: center;
-
background-color: #fff;
-
margin-top: 15px;
-
padding: 0 15px;
-
font-size: 18px;
-
}
-
.tui-conutdown-box{
-
display: inline-block;
-
height: 26px;
-
width: 26px;
-
line-height: 26px;
-
text-align: center;
-
background:#ccc;
-
color: #000;
-
margin: 0 5px;
-
}
-
.tui-countdown-bg{
-
background: red;
-
color: #fff;
-
}
-
-
.container{
-
width: 100%;
-
display: flex;
-
justify-content: center;
-
}
-
.backView{
-
width:690rpx;
-
background: #fff;
-
display: flex;
-
flex-direction: column;
-
margin-bottom: 30rpx;
-
}
-
.createDate
-
{
-
background: #f5f5f5;
-
padding:15rpx 15rpx 10rpx 15rpx;
-
line-height: 50rpx;
-
font-size: 28rpx;
-
color: gainsboro;
-
text-align: center;
-
}
-
.backViewitem1{
-
-
display: flex;
-
flex-direction: row;
-
height: 55rpx;
-
align-items: center;
-
padding:8rpx 40rpx;
-
border-bottom: 2rpx solid #f5f5f5;
-
}
-
.ico
-
{
-
width:35rpx;
-
height:35rpx;
-
}
-
.name
-
{
-
color: #c13176;
-
margin-left: 20rpx;
-
font-size: 28rpx;
-
}
-
-
.details
-
{
-
font-size:24rpx;
-
letter-spacing: 2rpx;
-
-
}
-
.backViewitem2{
-
-
display: flex;
-
flex-direction: row;
-
line-height: 35rpx;
-
min-height: 70rpx;
-
padding: 15rpx 40rpx 10rpx 40rpx;
-
border-bottom: 2rpx solid #f5f5f5;
-
}
-
.details1
-
{
-
color:#888;
-
font-size:23rpx;
-
letter-spacing: 2rpx;
-
-
}
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里
一、什么是跨域访问
举个栗子:在A网站中,我们希望使用Ajax来获得B网站中的特定内容。如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。你可以理解为两个域名之间不能跨过域名来发送请求或者请求数据,否则就是不安全的。跨域访问违反了同源策略,同源策略的详细信息可以点击如下链接:Same-origin_policy;
总而言之,同源策略规定,浏览器的ajax只能访问跟它的HTML页面同源(相同域名或IP)的资源。
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用<script>元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。更具体的原理需要更多篇幅的讲解,小伙伴可以自行去百度。
JQuery Ajax对JSONP进行了很好的封装,我们使用起来很方便。前端示例:
$.ajax({
type:"GET",
url:"http://www.deardull.com:9090/getMySeat", //访问的链接 dataType:"jsonp", //数据格式设置为jsonp jsonp:"callback", //Jquery生成验证参数的名称 success:function(data){ //成功的回调函数 alert(data);
},
error: function (e) { alert("error");
}
});
需要注意的地方是:
后端要配合使用jsonp,那么首先得了解Jquery Ajax jsonp的一个特点:
Jquery在发送一个Ajax jsonp请求时,会在访问链接的后面自动加上一个验证参数,这个参数是Jquery随机生成的,例如链接
http://www.deardull.com:9090/getMySeat?callback=jQuery31106628680598769732_1512186387045&_=1512186387046
中,参数callback=jQuery31106628680598769732_1512186387045&_=1512186387046就是jquery自动添加的。
添加这个参数的目的是唯一标识这次请求。当服务器端接收到该请求时,需要将该参数的值与实际要返回的json值进行构造(如何构造下面讲解),并且返回,而前端会验证这个参数,如果是它之前发出的参数,那么就会接收并解析数据,如果不是这个参数,那么就拒绝接受。
需要特别注意的是这个验证参数的名字(我在这个坑上浪费了2小时),这个名字来源于前端的jsonp参数的值。如果把前端jsonp参数的值改为“aaa”,那么相应的参数就应该是
aaa=jQuery31106628680598769732_1512186387045&_=1512186387046
知道了Jquery Ajax Jsonp的原理,也知道了需要接受的参数,我们就可以来编写服务器端程序了。
为了配合json,服务器端需要做的事情可以概括为两步:
根据与前端Ajax约定的jsonp参数名来接收验证参数,示例如下(使用SpringMVC,其他语言及框架原理类似)
@ResponseBody @RequestMapping("/getJsonp") public String getMySeatSuccess(@RequestParam("callback") String callback){
将接收的的验证参数callback与实际要返回的json数据按“callback(json)”的方式构造:
@ResponseBody
@RequestMapping("/getMySeat") public String getMySeatSuccess(@RequestParam("callback") String callback){
Gson gson=new Gson(); //google的一个json工具库 Map<String,String> map=new HashMap<>(); map.put("seat","1_2_06_12"); return callback+"("+gson.toJson(map)+")"; //构造返回值 }
最终,前后端的相应代码应该是这样的:
前端
$.ajax({
type:"GET",
url:"http://www.deardull.com:9090/getMySeat", //访问的链接 dataType:"jsonp", //数据格式设置为jsonp jsonp:"callback", //Jquery生成验证参数的名称 success:function(data){ //成功的回调函数 alert(data);
},
error: function (e) { alert("error");
}
});
后端
@ResponseBody
@RequestMapping("/getMySeat") public String getMySeatSuccess(@RequestParam("callback") String callback){
Gson gson=new Gson(); Map<String,String> map=new HashMap<>(); map.put("seat","1_2_06_12");
logger.info(callback); return callback+"("+gson.toJson(map)+")";
}
需要注意的是:
完整的示例就是上面两段代码,这里就不提供Github连接了。上面的示例亲测有效,如果有遇到问题的,欢迎留言提问。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务。
对于大部分的射击湿以及设计团队来讲,都会遇到如何提升设计效率的问题;尤其是在创业公司,最浪费时间的莫过于:永远撸不完的图及与开发中的设计反复;接下来我将通过自身的一些设计管理经验,从工具使用提升工作效率的角度,跟大家分享下我解决这两个问题的方法。
撸不完的图-处理各方设计需求
1、设计的需求方在不断增多:产品、运营、市场、地推、策划等等;
对于大部分的射击湿来说,设计的需求都是越来越多的;尤其是中小型公司由于发展的的需要,公司的人员及部门会越来越多;也就导致后期的设计需求慢慢增加;我们公司就是酱紫的,原来只要考虑产品需求的,现在要考虑运营日常海报、活动设计、市场推广素材、线下门店品牌视觉系统、还有老板的PPT等等。
2、需求不清导致变动频繁:没有目的下需求,缺少需求细节;
在日常的工作中,最麻烦的就是跟需求方确认需求;尤其是口述的需求,没有文案、时间节点及具体的需求描述;比如,我要“五彩斑斓的黑”或者“字要大”这种奇葩需求想一出就是一出的随性需求。
3、对接、确认流程不清晰:没有一套完整有效的对接流程,导致双方扯皮;
二、产生的问题?
1、设计效率及产出质量不高:需求方不满意,然后设计反复浪费时间;
2、项目推进速度变缓:有限的时间达不到设计要求拖慢项目进度,影响业务目标;
1、建立和规范有效的需求对接确认流程:从制度层面解决跨部门协调问题;
首先,对内规范接收和分发需求的流程;将原来粗放的接收方式改为协作工具接收分发需求;其次,对外规范需求下方的格式规范。
2、使用“团队协作工具”统一输入/输出需求:运用工具解决需求接收下放问题;
3、规范需求方下需求的格式:需求包含的各项要点:
时间节点:最好提前几天;
需求描述:需要什么样的;
文案描述:传达什么内容。
1、工具不统一,协作较难:PS与Sketch混用;
我刚进公司的时候,设计团队的三个人用的设计工具和设备都不一样;有的用PS,有的用Sketch,这就造成设计协作难而且设计稿输出格式不同意,开发抱怨的情况,工作推进艰难。
2、标注切图耗时太长:页面中的各个元素都要进行大小、颜色、间距及格式的标注;
设计给开发的输出物有三种:视觉稿、标注及安卓、IOS不同尺寸的切图;以上是保证上线效果的关键;但是传统的手动标注和切图是很浪费时间的。
3、IOS、安卓设计规范差异:两个平台系统差异,有时候要输出两套设计素材;
1、统一设计工具:移动端的设计统一Sketch输出;
2、利用第三方工具Zeplin自动标注设计稿:工具代替原来的手动标注;
3、工具zeplin工具的优势:
自动匹配IOS及安卓平台设计单位、颜色及字体大小等;
设计一套搞定,减少设计师工作量;
设计沟通的效率和质量大大提升;
以上就是我在做设计管理过程中摸索的一些的经验,无论是跟需求方的设计沟通还是和开发的协同配合,都非常的和谐;希望通过此次分享能给遇到相同困惑的小伙伴们一些启发~
蓝蓝设计的小编 http://www.lanlanwork.com