<table>
<tr>
<td>姓名:</td>
<td contentEditable="true"></td>
</tr>
<tr>
<td>密码:</td>
<td contentEditable="true"></td>
</tr>
</table>
作者通过以进度条的设计深入浅出的讲解关于FUI的设计思路。虽然FUI设计看起来很复杂,只要找准规律,从一些作品中总结分析细节,再运用到我们的设计中。想要了解的小伙伴可以尝试一下。
前言
看到上期小伙伴想了解一下 FUI 的设计教程,所以这次再次和大家聊一下关于 FUI 的设计风格,我们以“进度条”的设计教程为例,深入浅出的聊一下关于 FUI 的设计思路,因为主要设计思路的延展,所以不会出现具体的数据参数,小伙伴们要谅解啊。
目录
1.风格介绍
2.设计思路
3.总结
1.风格介绍
关于 FUI 的定义,阅读过我上一篇文章的小伙伴可能对 FUI 的定义有了一个较为清晰的定义,即 FUI 是:虚构的、未来的、幻想的用户界面。
接下来我会向大家简单介绍一下 FUI 主要的两大设计风格:军事风格和机甲风格(也可以叫做机械风格)。
1.军事风格
军事风格的特点在于:“直接明了”。因为在残酷的战争中时间就是生命,士兵必须保证“快速、准确、直接”才能保证战斗的胜利,所以会尽量避免与操作业务无关的。你也可以理解为当下最前沿的的设计理念“less is more。”例如下图,在界面设计中几乎都是利用简单的几何设计语言完成。
2.机甲风格
机甲风格相对于军事风格的最大特点就是:“具有一定的装饰图形元素,或多或少。”机甲风格最大的特点便是具有机械或者机甲风格的装饰元素,其中多为异形元素。其灵感来源于工业设计,从机械和机甲的工业设计语言中提取图形元素,在运用到界面设计上。如下图,异形的机甲风格让机器人的头部设计显得更加统一,如果换成当前流行的扁平化设计,可能就显得有点奇怪了。
机甲风格的发展归功于科幻题材故事的发展,为人们打开脑洞,畅想更多的可能性。在设计上激发了 FUI 的诞生,无论是赛博朋克、废土题材、还是漫威、DC宇宙中的科幻影视作品中我们都能看到机甲风格的界面设计。
2.设计思路
设计样式 – 军事风格
我们从以上的设计风格中抓去我们需要的关键词进行示例设计,首先我们看军事风格的关键词是“直接明了、快速、准确、直接,”我们转换成我们平时的设计语言就是:“极简风格,”这样是不是更好理解了。例如图例中,页面整体十分统计,利用简洁几何语言进行设计。
接下来我们做一个简单的军事风格的进度条:第一步,找参考!!!这一步很重要,很多同学都很容易就忽视这一点,一心一意的闭门造车,绝不借鉴学习其它优秀作品。这里向大家推荐 HUDS + GUIS 设计公司,这里有我们许多我们耳熟能详的影视作品中的 FUI 设计。
第二步,临摹,临摹可以说是学习他人技巧的最快方式,从中我们可以学习到许多设计中的细节,日后我们可以运用到自己的设计当中。我借鉴临摹了下面的进度条样式。
我们可以放入界面当中感受一下视觉效果:
设计样式 – 机甲风格
我们再来进阶一下,设计一个机甲元素的的进度条。
机甲风格看似装饰图形复杂,设计难度复杂,但其实我们只需要掌握好 – “提炼元素”这项技能就能完美应对机甲风格的设计。
我们再回顾对创意设计的定义:是把再简单不过的东西或想法不断延伸给予的另一种表现方式。这里我们可以理解为将机甲元素进行提炼总结,延伸到弹框设计当中。例如下图,漂亮的小姐姐一秒钟变机械美女,就是通过对机械元素延展到模特身上。
第一步,照一张你喜欢的不错的参考,这里你可以找成熟的界面设计作品,也可以找一张不错的关于机甲风格的参考,以便于自己进行元素提取。这里我们以大家熟悉的高达为例:
我们从中提取我们需要的图形,如下图:
最后我们我们需要仔细思考将图形进行组合,多尝试几次他们的组合方式。这里我对提取的元素进行了二次加工,将图形一和图形四进行了结合,打破固有的组合规律,让图形看起来更加生动。
最后我们可以放入界面当中感受一下视觉效果:
3.总结
FUI 的设计看起来复杂,难以下手,但其实也是有规律可循,我们可以从作品中理性的去分析其中的设计细节,提炼总结,最终再落实到实际的设计作品当中。当然最好你能先了解一下它的设计理念以及发展,就像 FUI 是“虚构的、未来的、幻想的界面设计”一样。
---来自姜正
转载自简书
作者:极创设计
链接:https://www.jianshu.com/p/77665c771153
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
蓝蓝设计( www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 、平面设计服务
<view class="gallery">
<view class="item" wx:for="{{images}}" wx:key="">
<image src="{{item}}" data-src="{{item}}" bindtap="previewImage" mode="aspectFill" />
<!-- 删除按钮 -->
<view class="delete" bindtap="delete" data-index="{{index}}">X</view>
</view>
<view class="item" bindtap="chooseImage">
<view class='addIcon'>+</view>
</view>
</view>
<button type="primary" bindtap="submit">提交</button>
————————————————
/* pages/index/index.wxss */
/*画廊*/
.gallery {
width:630rpx;
margin: 0 auto;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
/*每张图片所占容器*/
.item {
position: relative;
margin:10rpx 5rpx;
width: 200rpx;
height: 200rpx;
}
.item image{
width: 100%;
height: 100%;
}
/*add按钮*/
.item .addIcon{
position:relative;
width:200rpx;
height:200rpx;
text-align:center;
line-height:200rpx;
font-size:80rpx;
background: #f2f2f2;
color: #555;
}
/*删除按钮*/
.delete {
position:absolute;
right:0;
top:0;
/* background:#ccc; */
opacity:1;
height: 36rpx;
font-size:22rpx;
font-weight:700;
padding:0 8rpx 0 10rpx;
}
————————————————
var that;
Page({
data: {
images: [],
uploadedImages: [],
//imageWidth: getApp().screenWidth / 4 - 10
},
onLoad: function (options) {
that = this; var objectId = options.objectId; console.log(objectId);
},
chooseImage: function () {
// 选择图片
wx.chooseImage({
count: 3, // 默认9
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
// 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
var tempFilePaths = res.tempFilePaths;
console.log(tempFilePaths);
that.setData({
images: that.data.images.concat(tempFilePaths)
});
}
})
},
// 图片预览
previewImage: function (e) {
//console.log(this.data.images);
var current = e.target.dataset.src
wx.previewImage({
current: current,
urls: this.data.images
})
},
// submit: function () {
// // 提交图片,事先遍历图集数组
// that.data.images.forEach(function (tempFilePath) {
// new AV.File('file-name', {
// blob: {
// uri: tempFilePath,
// },
// }).save().then(
// // file => console.log(file.url())
// function (file) {
// // 先读取
// var uploadedImages = that.data.uploadedImages;
// uploadedImages.push(file.url());
// // 再写入
// that.setData({
// uploadedImages: uploadedImages
// }); console.log(uploadedImages);
// }
// ).catch(console.error);
// });
// wx.showToast({
// title: '评价成功', success: function () {
// wx.navigateBack();
// }
// });
// },
delete: function (e) {
var index = e.currentTarget.dataset.index; var images = that.data.images;
images.splice(index, 1);
that.setData({
images: images
});
}
})
————————————————
<button data-name="shareBtn" open-type="share" plain="true">转发</button>
添加plain=”true”后button的边框样式可自定义 ↓ ↓
button[plain]{ border:0 }
//转发
onShareAppMessage: function (options) {
var that = this;
// 设置菜单中的转发按钮触发转发事件时的转发内容
var shareObj = {
title: "这是一个标题!", // 默认是小程序的名称(可以写slogan等)
//path: '/page/index/index/user?id=123', // 默认是当前页面,必须是以‘/’开头的完整路径
imageUrl: '../../img/xiaochengxu-share.jpg', //自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径,支持PNG及JPG,不传入 imageUrl 则使用默认截图。显示图片长宽比是 5:4
success: function (res) {
// 转发成功之后的回调
if (res.errMsg == 'shareAppMessage:ok') {
}
},
fail: function (res) {
// 转发失败之后的回调
if (res.errMsg == 'shareAppMessage:fail cancel') {
// 用户取消转发
console.log("用户取消转发");
} else if (res.errMsg == 'shareAppMessage:fail') {
// 转发失败,其中 detail message 为详细失败信息
}
},
complete: function(){
// 转发结束之后的回调(转发成不成功都会执行)
},
};
// 来自页面内的按钮的转发
if(options.from == 'button') {
var eData = options.target.dataset;
console.log(eData.name); // shareBtn
// 此处可以修改 shareObj 中的内容
//shareObj.path = '/pages/btnname/btnname?btn_name=' + eData.name;
}
// 返回shareObj
return shareObj;
————————————————
<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" circular="{{duration}}" current="{{swiperCurrent}}" bindchange="swiperChange" class="swiper">
<block wx:for="{{imgUrls}}" wx:key="unique">
<swiper-item>
<image src="{{item}}" class="img" bindtap="swipclick" />
</swiper-item>
</block>
</swiper>
————————————————
/* swiper {
height: 421.5rpx;
} */
swiper-item image {
width: 100%;
height: 100%;
}
.swiper-container{
width: 100%;
position: relative;
}
.swiper-container .swiper{
height: 300rpx;
}
.swiper-container .swiper .img{
width: 100%;
height: 100%;
}
————————————————
const app = getApp()
Page({
data: {
swiperCurrent: 0,
indicatorDots: true,
autoplay: true,
interval: 3000,//自动切换时间间隔
duration: 800,//滑动动画时长
circular: true,//是否采用衔接滑动
imgUrls: [
'../../img/index/1.jpeg',
'../../img/index/2.jpeg',
'../../img/index/3.jpeg'
]
},
//轮播图的切换事件
swiperChange: function (e) {
this.setData({
swiperCurrent: e.detail.current
})
//console.log(e.detail.current);
},
//点击指示点切换
chuangEvent: function (e) {
this.setData({
swiperCurrent: e.currentTarget.id
})
},
//点击图片触发事件
swipclick: function (e) {
console.log(this.data.swiperCurrent);
wx.switchTab({
url: this.data.links[this.data.swiperCurrent]
})
},
})
————————————————
前提:真机和PC端在同一个局域网内。
1、安装nodejs环境 (node -v 查看版本号)
2、在所在的项目下输入命令:npm install anywhere -g
3、直接输入命令:anywhere,这里浏览器自动打开所有项目的根目录,点击就可以看到,同一网段下,然后手机直接预览这个地址就可以
————————————————
<view class="gallery">
<view class='tipTitle'>
快去上传自己的照片吧
</view>
<view class='item-ot'>
<view class="item">
<!-- 添加按钮 -->
<view class="addIcon" bindtap="chooseImage" wx:if="{{imgBoolean}}">
<view class=''>+</view>
</view>
<!-- 上传的图 -->
<view class='itemImg' >
<image src="{{item}}" data-src="{{item}}" bindtap="previewImage" mode="aspectFill" />
<!-- 删除按钮 -->
<view class="delete" bindtap="deleteImg" data-index="{{index}}">X</view>
</view>
<view class='boxStyle'></view>
</view>
<view class='itemTxt'>正面照</view>
</view>
<view class='uploadFinish'>
<a class="uploadFinishBtn" href="javasctipt:;" bindtap="submit">提 交</a>
</view>
</view>
/*画廊*/
.gallery {
width:100%;
margin: 0 auto;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
background: #fffaf0;
}
/*每张图片所占容器*/
.item-ot{
margin:0 auto;
width: 100%;
height: 100%;
}
.item {
position:relative;
margin:0 auto;
width:370rpx;
height:490rpx;
background:#eee;
border:2rpx solid #f9c4c2;
/* overflow:hidden; */
}
.itemImg{
position: absolute;
left: 0;
top:0;
width: 100%;
height: 100%;
overflow: hidden;
z-index:1;
}
.itemImg image{
width: 100%;
height: 100%;
}
/*add按钮*/
.addIcon{
position:absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
text-align:center;
line-height:490rpx;
font-size:80rpx;
background: #fff;
color: #999;
z-index:2;
}
/*删除按钮*/
.delete {
position:absolute;
right:0;
top:0;
/* background:#ccc; */
opacity:1;
height: 36rpx;
font-size:22rpx;
font-weight:700;
padding:0 8rpx 0 10rpx;
color: #999;
}
.itemTxt{
text-align: center;
font-size: 30rpx;
color: #999;
margin-top: 50rpx;
margin-bottom: 70rpx;
font-weight: 700;
}
.uploadFinish{
width: 100%;
height: 100%;
padding: 0 30rpx;
box-sizing: border-box;
}
.uploadFinishBtn{
background: #ff6666;
color: #fff;
display: block;
width: 100%;
padding: 26rpx 0;
text-align: center;
font-size: 36rpx;
border-radius: 10rpx;
margin-bottom: 40rpx;
}
.tipTitle{
text-align: center;
font-size: 30rpx;
color: #f6a29d;
font-weight: 700;
width: 100%;
margin: 50rpx 0;
}
.boxStyle{
width:300rpx;
height:100rpx;
position:absolute;
bottom:-1rpx;
border-radius:50%;
box-shadow:0rpx 10rpx 100rpx #fddbd9;
margin-left:35rpx;
}
Page({
data: {
uploadedImages: [],
imgBoolean: true,
},
onLoad: function (options) {
var that = this;
},
chooseImage: function () {
var that = this;
// 选择图片
wx.chooseImage({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
var tempFilePaths = res.tempFilePaths
that.setData({
item: tempFilePaths[0],
imgBoolean: false
});
}
})
},
// 图片预览
previewImage: function (e) {
var current = e.target.dataset.src
wx.previewImage({
current: current,
urls: [current]
})
console.log("这是1" + current);
},
//删除图片
deleteImg: function (e) {
var that = this;
var images = that.data.uploadedImages;
that.setData({
uploadedImages: images,
imgBoolean: true
});
},
// submit: function () {
// },
})
],
如果想控制百分比最大到100% 可添加
yAxis : [
{
type : 'value',
max:100,//Y轴最大值 不写的话自动调节
axisLabel:{formatter:'{value} %'}
}
],
> max:100,//Y轴最大值 不写的话自动
<table>
<tr>
<td>姓名:</td>
<td contentEditable="true"></td>
</tr>
<tr>
<td>密码:</td>
<td contentEditable="true"></td>
</tr>
</table>
语言设置
校验消息默认是英文的,定义中文或其他语言的错误提示消息
-
import VeeValidate from 'vee-validate';
-
import Vue from 'vue'
-
Vue.use(VeeValidate)
-
-
var dict = {
-
zh_CN: {
-
messages: {
-
required: function(field){
-
return field + '不能为空!';
-
},
-
between: function(field){
-
return field + '输入不符合设定规则!';
-
},
-
min : function (field,leng) {
-
return field + '长度不能小于'+leng+'位';
-
}
-
}
-
}
-
};
-
-
VeeValidate.Validator.localize('zh_CN', dict.zh_CN);
校验的时候需要设置语言
this.$validator.localize('zh_CN');
错误消息显示
显示指定字段的第一个错误
this.$validator.first('fieldname')
显示所有字段的第一个错误消息
this.$validator.errors.all()
配置
路由拦截配置不需要修改之前的代码,匹配的url请求会直接通过mock而不是请求服务器
-
const handler = req => {
-
return {mock数据};
-
}
-
Mock.mock('url拦截规则,正则表达式',handler)
配置延迟时间
模拟服务器请求的异步特性
-
Mock.setup({
-
timeout:1000
-
})
模块化
多人协作,或者中大型的项目需要把store分为模块
-
const a = {
-
state : {foo:1},
-
mutations : {hello(state)=> {}},
-
modules : {
-
...嵌套
-
}
-
}
-
const b = {}
-
const store = {
-
state : {},
-
mutations : {},
-
actions : {},
-
modules : {
-
module_name_a:a,
-
module_name_b:b
-
}
-
}
在调用的时候,state 有命名空间的,而mutation和actions都与父模块共用同样的命名空间所以不能定义与父模块同名的mutation 或 action
获取模块的state
this.$store.state.module_name_a.foo
调用模块的mutation
this.$store.commit('hello')
namespace
定义了namespace ,mutations 和 action 会带上模块的命名: module_name/muation
-
const store = {
-
modules : {
-
namespace : true,
-
a: {
-
muations : {
-
test(state) => {...}
-
}
-
}
-
}
-
}
这时候调模块内的mutation
this.$store.commit('a/test')
日期选择控件
设置默认值
<datepicker v-model="mydate" </datepicker>
日期格式化
<datepicker :format="'yyyy-MM-dd'"> </datepicker>
语言选择(默认是英文)
导入语言资源文件,然后再设置:language
设置成中文
-
蓝蓝设计的小编 http://www.lanlanwork.com