Ce tutoriel fait partie de la série « Construisez votre startup avec PHP » sur Envato Tuts+. Dans cette série, je vais vous guider tout au long du lancement d'une startup, du concept à la réalité, en utilisant mon application de planification de réunions comme exemple concret. À chaque étape du processus, je publierai le code de Meeting Planner comme exemple open source dont vous pourrez tirer des leçons. J'aborde également les problématiques business liées aux startups qui se posent.
Stratégiquement, il est logique de créer des applications mobiles pour Meeting Planner sur iOS et Android, mais d'un point de vue financier, je n'ai pas encore réuni les ressources nécessaires. Mathew Ingram a récemment écrit dans Fortune qu'avec autant de produits ciblant les utilisateurs mobiles, "statistiquement au moins, personne ne téléchargera votre application". Ainsi, même si je pourrais certainement améliorer l'expérience Meeting Planner avec une application, mais avec mes ressources actuelles. , la possibilité de l'adopter n'avait pas de sens dans l'immédiat.
Cependant, il est important que Meeting Planner offre une excellente expérience Web sur les appareils mobiles.
Dans l'émission d'aujourd'hui, je passerai en revue et discuterai des modifications que nous avons apportées pour y parvenir - essentiellement en faisant en sorte que notre application Web ressemble davantage à un site Web réactif qui peut être utilisé facilement sur les appareils mobiles et les tablettes. Visualisez les résultats (sur votre téléphone ou votre tablette) !
L'un des défis de codage de l'épisode d'aujourd'hui est que je ne suis ni un concepteur ni un codeur CSS. Parfois, j'ai l'impression que je ne devrais même pas coder moi-même ; chez Microsoft, je suis chef de projet d'équipe, ce qui signifie que nous avons des graphistes, un laboratoire d'utilisabilité au complet, que CSS n'existe pas, etc.
Avant de commencer ce travail, j'étais intimidé par l'apprentissage des requêtes multimédias, des points d'arrêt et du CSS spécialisé - ce n'est pas un sujet dans lequel je suis bon et il prend beaucoup de temps et est très minutieux. Cependant, en 48 heures, tout a été fait rapidement et parfaitement. Si vous naviguez jusqu'au bas de l'histoire, vous verrez que tous les changements ont nécessité très peu de lignes de CSS. Soudain, lorsque j'ai commencé à parcourir Meeting Planner sur mon téléphone, j'étais vraiment enthousiasmé par le fonctionnement de la nouvelle expérience Web réactive.
Franchement, cela me donne l’impression qu’une application mobile dédiée n’est pas nécessaire pour le moment. Actuellement, nous pouvons impliquer le public via des expériences Web mobiles, en particulier pendant les phases critiques alpha et bêta à venir.
En attendant, si vous n'avez pas encore essayé le planificateur de réunions, n'hésitez pas et planifiez votre première réunion depuis votre téléphone ou votre tablette. Je participe au fil de commentaires ci-dessous, alors n'hésitez pas à me parler de vos expériences ! Vous pouvez également me joindre sur Twitter @reifman. Je suis toujours intéressé par les demandes de nouvelles fonctionnalités et les suggestions de sujets de didacticiel.
Pour rappel, tout le code de Meeting Planner est écrit à l’aide du framework PHP Yii2. Si vous souhaitez en savoir plus sur Yii2, consultez notre série parallèle « Programmation avec Yii2 ».
Tout d'abord, j'ai parcouru l'état actuel du service Meeting Planner à l'aide de mon téléphone iOS et pris une capture d'écran de l'application initiale. Ce n'est pas terrible, mais ce n'est pas génial non plus. Passons en revue ce que j'ai trouvé.
La page d'accueil a l'air bien, même si d'un point de vue esthétique, j'aurais aimé que le texte du titre "Making Scheduling Easy" soit légèrement différent, c'est-à-dire sur trois lignes de longueur à peu près égale. Cependant, Bootstrap gère bien la liste déroulante et le reste de la page fonctionne bien :
Encore une fois, mis à part la belle mise en page de l'en-tête et la cohérence de la marge gauche, la page d'inscription est fondamentalement fonctionnelle :
Une fois que la personne commence à planifier une réunion, la page d'index actuelle doit être améliorée. Trop de colonnes. Le sujet est écrasé. Peut-être que les informations que je choisis d'afficher ici n'ont pas d'importance en premier lieu. Bien entendu, les options de commande ne sont pas non plus visibles. La page doit être davantage adaptée aux appareils mobiles.
D'autres pages fonctionnent bien, comme les nouvelles demandes de réunion pour un sujet. Cependant, les utilisateurs mobiles ne voudront peut-être pas fournir de champ de zone de texte pour saisir un message plus long présentant la réunion :
Avec l'extension bootstrap que nous utilisons, l'ajout de participants devient également un peu dysfonctionnel :
La vue de planification des lieux et des heures commence à planter. De même, la conception des ordinateurs de bureau offre trop de détails et trop d'options pour les appareils mobiles :
La page Lieux fonctionne bien, mais la disposition des boutons doit être améliorée. Peut-être que les utilisateurs mobiles n'ont pas besoin de cette fonctionnalité.
De même, les onglets du bureau et les mises en page des photos présentent des problèmes sur les appareils mobiles. Encore faut-il reconsidérer :
Bien sûr, le site Web peut encore être amélioré. Certaines zones doivent être reconsidérées pour les appareils mobiles, d'autres doivent être minimisées et d'autres nécessitent des ajustements esthétiques. Mettons-nous au travail.
Lorsque j'ai commencé cette tâche, je n'avais presque aucune expérience des requêtes multimédias et des points d'arrêt. J'avais tergiversé ces derniers jours, craignant de tomber dans un bourbier inconnu. J'ai commencé par pratiquer les requêtes médias pour taquiner mon éditeur :
@media only life and (max-energy-level: 60%) and (-caffeine-ratio: 2) { .editorBossperson { available-to:false; visible-to:false; } }
Jouer aide à briser la glace mentale dans ma tête. Les dieux de l'édition chez Envato peuvent toujours me voir.
J'ai commencé à réfléchir à de nombreux domaines :
Un concept utile que je rencontre sans cesse sur le Web est le « conception axée sur le mobile ». Malheureusement, je suis de la vieille école et je ne fais pas ça. Mais il est utile de repenser chaque page avec le thème suivant : le mobile d’abord.
Par exemple, l'index de réunion avec quatre colonnes de tableau a dû être supprimé et serait désorientant sur un téléphone en mode portrait.
Je me demande comment concevoir toutes mes pages pour une utilisation sur mobile.
Il m'a fallu quelques efforts pour surmonter mon hésitation à me lancer dans CSS. Pour me préparer, j'ai commencé à travailler sur la réduction du menu déroulant et à simplifier la portée de la fonctionnalité mobile.
Pour l'instant, j'ai décidé de créer une requête média de base pour les petits appareils et de l'utiliser sur l'ensemble du site Web. Voici frontend/site.css :
/* ----------- mobile displays ----------- */ @media only screen and (min-device-width: 320px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { /* hides drop down menu items and footer items */ .itemHide,li.menuHide { display:none; visible:false; }
Il s’avère que faire le changement est relativement simple. Pour tout élément de menu que je souhaite masquer sur mobile, j'ajoute simplement une propriété CSS comme 菜单隐藏
.
Voici l'attribut menuHide
ajouté à /frontend/views/layouts/main.php :
$menuItems[] = [ 'label' => 'Account', 'items' => [ [ 'label' => Yii::t('frontend','Places'), 'url' => ['/place/yours'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Friends'), 'url' => ['/friend'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Profile'), 'url' => ['/user-profile'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Contact information'), 'url' => ['/user-contact'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Settings'), 'url' => ['/user-setting'], //'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Reminders'), 'url' => ['/reminder'], 'options'=>['class'=>'menuHide'], ], [ 'label' => Yii::t('frontend','Logout').' (' . \common\components\MiscHelpers::getDisplayName(Yii::$app->user->id) . ')', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post'] ], ], ]; echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => $menuItems, ]);
Du coup, les menus déroulants deviennent moins compliqués :
Petit à petit, j'ai réalisé que simplifier et réduire les fonctionnalités du Web mobile créerait la meilleure expérience. Les utilisateurs peuvent toujours revenir au bureau pour accéder à d’autres fonctionnalités, du moins pour le moment. C’est également l’occasion de recueillir les retours des personnes lors des phases alpha et bêta.
Yii comprend un widget de fil d'Ariane, chargé via Composer et difficile à personnaliser. J'ai essayé d'ajouter du CSS pour masquer le premier élément et le premier séparateur "/" :
Cela a pris un certain temps, mais m'a permis d'approfondir mes connaissances en CSS, comme un nième truc pour enfants, et a renforcé ma confiance :
/* removes home and / from breadcrumb */ ul.breadcrumb li:first-child, li.tabHide { display:none; visible:false; } ul.breadcrumb li:nth-child(2)::before { content:''; }
Je ne savais pas que CSS pouvait modifier le contenu.
Les résultats sont les suivants :
Ensuite, j'ai ajouté CSS pour donner au bouton un remplissage supplémentaire sur les appareils mobiles, réduisant ainsi le risque d'erreurs lorsque j'appuie du bout du doigt. Par exemple, voici les boutons Soumettre et Annuler sur le bureau :
Voici le CSS que j'ai utilisé et que j'ai commencé à ajouter aux différents boutons et icônes cliquables autour du site :
/* fingertip spacing for buttons */ a.icon-pad { padding: 0 5px 0 2px; } .button-pad { padding-left:7px; }
Le formulaire ressemble à ceci sur mobile - notez le nouveau remplissage entre Soumettre et Annuler :
Créer le titre de la page d'accueil « Planification simplifiée » prend en fait plus de temps. Enfin, j'ai ajouté la classe <br />
标签,并在不在移动设备上时默认隐藏它。但我还必须使用 itemHide
au texte pour ajouter un espace dans la balise span.
<h1> <?php echo Yii::t('frontend','Scheduling'); ?> <br class="rwd-break" /> <span class="itemHide"> </span> <?php echo Yii::t('frontend','Made Easy') ?> </h1>
这是 .rwd-break
的 CSS。默认情况下它是隐藏的,并且仅出现在响应式显示中,从而按照我想要的方式破坏标题文本。
.rwd-break { display:none; } /* ----------- mobile displays ----------- */ @media only screen and (min-device-width: 320px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { ... .rwd-break { display:block; } }
如果没有 span 标记空间,文本将在没有正确居中的情况下中断。
随着我越来越认为“移动优先”,我意识到基于手机的用户并不需要我页面上的所有功能。他们不需要所有选项卡,不需要有关会议的数据表,也不需要所有图标按钮选项。事实上,对于会议页面,他们只需要能够打开会议(他们可以从会议视图页面本身取消会议)。
我将主题和参与者列合并为一个垂直列,结果看起来好多了。
在 /frontend/views/meeting/index.php 中,我将 .tabHide
添加到两个四个选项卡中的:
<!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <li class="active"><a href="#planning" role="tab" data-toggle="tab">Planning</a></li> <li ><a href="#upcoming" role="tab" data-toggle="tab">Confirmed</a></li> <li class="tabHide"><a href="#past" role="tab" data-toggle="tab" >Past</a></li> <li class="tabHide"><a href="#canceled" role="tab" data-toggle="tab">Canceled</a></li> </ul>
并且,在 /frontend/views/meeting/_grid.php 中,我重组了该列以合并主题和参与者:
if ($mode =='upcoming' || $mode =='past') { echo GridView::widget([ 'dataProvider' => $dataProvider, //'filterModel' => $searchModel, 'columns' => [ [ 'label'=>'Details', 'attribute' => 'meeting_type', 'format' => 'raw', 'value' => function ($model) { // to do - remove legacy code when subject didn't exist if ($model->subject=='') { return '<div><a href="'.Url::to(['meeting/view', 'id' => $model->id]).'">'.$model->getMeetingHeader().'</a><br /><span class="index-participant">'.$model->getMeetingParticipants($model->id).'</span></div>'; } else { return '<div><a href="'.Url::to(['meeting/view', 'id' => $model->id]).'">'.$model->subject.'</a><br /><span class="index-participant">'.$model->getMeetingParticipants($model->id).'</span></div>'; } }, ],
隐藏 ActionColumn
需要进行一些研究,但看起来像这样:
['class' => 'yii\grid\ActionColumn','header'=>'Options','template'=>'{view} {decline} {cancel}', 'headerOptions' => ['class' => 'itemHide'], 'contentOptions' => ['class' => 'itemHide'], 'buttons'=>[ 'view' => function ($url, $model) { return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, [ 'title' => Yii::t('frontend', 'view'), 'class' => 'icon-pad', ]); }, 'decline' => function ($url, $model) { return ($model->status==$model::STATUS_SENT ) ? Html::a('<span class="glyphicon glyphicon-thumbs-down"></span>', $url, [ 'title' => Yii::t('frontend', 'decline'), 'class' => 'icon-pad', ]) : ''; }, 'cancel' => function ($url, $model) { return ($model->status==$model::STATUS_SENT || $model->status==$model::STATUS_CONFIRMED ) ? Html::a('<span class="glyphicon glyphicon-remove-circle"></span>', $url, [ 'title' => Yii::t('frontend', 'cancel'), 'data-confirm' => Yii::t('frontend', 'Are you sure you want to cancel this meeting?'), 'class' => 'icon-pad', ]) : ''; }, ] ],
最终,这些更改在改进移动设备的过程中简化了桌面界面。
到目前为止,对我来说最具挑战性的任务是针对移动设备调整上面的会议安排页面。手机上的情况一团糟,我很害怕。另外,我一直担心将来如何为多个参与者采用这个界面 - 响应性要求可能只会让这变得更加困难。
我对 Yii 的 Kartik Bootstrap Switch Widget 扩展的使用在修改布局方面有其自身的局限性。将这些元素放置在表格列中效果很好,但使表格列响应式对于媒体查询来说并不那么简单。
当然,正如我在上面的会议列表页面中所示,隐藏列很容易,但修改位置就不那么容易了。
我首先从显示时间和地点选项的水平表格设计转向垂直的纵向风格。而且,显然,表和列有自己的能力,可以在没有媒体查询的情况下使用 HTML5 和 CSS 进行包装。
您可以在此处查看改进后的空白会议计划页面:
每个部分视图都需要额外的 css 列才能使预定义的 Bootstrap 网格布局正常工作,例如左 col-xs4 和右 col-xs-8。这是一个例子:
<div class="panel panel-default"> <!-- Default panel contents --> <div class="panel-heading"> <div class="row"> <div class="col-lg-4 col-md-4 col-xs-4"><h4>What</h4></div> <div class="col-lg-8 col-md-8 col-xs-8"><div style="float:right;"> <?php if ($isOwner) { echo Html::a('', ['update', 'id' => $model->id], ['class' => 'btn btn-primary glyphicon glyphicon-pencil','title'=>'Edit']); } ?> </div> </div> </div> </div>
使地点和时间安排表格具有响应性是最困难的。我进行了实验并最终成功地使用了随着内容窗口(或设备)缩小而自然换行的表列。
我还消除了在其自己的列中显示参与者状态并禁用开关的情况 - 您无法更改它们,那么为什么将它们显示为开关呢?相反,我创建了参与者在地点和时间的状态的文本摘要。以下是 getWhenStatus()
的代码:
public static function getWhenStatus($meeting,$viewer_id) { // get an array of textual status of meeting times for $viewer_id // Acceptable / Rejected / No response: $whenStatus['text'] = []; $whenStatus['style'] = []; foreach ($meeting->meetingTimes as $mt) { // build status for each time $acceptableChoice=[]; $rejectedChoice=[]; $unknownChoice=[]; // to do - add meeting_id to MeetingTimeChoice for sortable queries foreach ($mt->meetingTimeChoices as $mtc) { if ($mtc->user_id == $viewer_id) continue; switch ($mtc->status) { case MeetingTimeChoice::STATUS_UNKNOWN: $unknownChoice[]=$mtc->user_id; break; case MeetingTimeChoice::STATUS_YES: $acceptableChoice[]=$mtc->user_id; break; case MeetingTimeChoice::STATUS_NO: $rejectedChoice[]=$mtc->user_id; break; } } $temp =''; // to do - update for multiple participants // to do - integrate current setting for this user in style setting if (count($acceptableChoice)>0) { $temp.='Acceptable to '.MiscHelpers::getDisplayName($acceptableChoice[0]); $whenStatus['style'][$mt->id]='success'; } else if (count($rejectedChoice)>0) { $temp.='Rejected by '.MiscHelpers::getDisplayName($rejectedChoice[0]); $whenStatus['style'][$mt->id]='danger'; } else if (count($unknownChoice)>0) { $temp.='No response from '.MiscHelpers::getDisplayName($unknownChoice[0]); $whenStatus['style'][$mt->id]='warning'; } $whenStatus['text'][$mt->id]=$temp; } return $whenStatus; }
这是它在桌面上的样子 - 注意文本行和开关的横向布局:
这是移动版本,更加纵向且堆叠,无需媒体查询:
作为示例,以下是我在“时间”面板上对表格列进行编码的 CSS: p>
table.table-list { width:100%; } table.table-list td.table-list-first { float: left; display: inline; width: auto; } table.table-list td.table-switches { width: auto; float: right; display: inline; padding-top: 10px; } .switch-pad { padding-left:7px; } .smallStatus { font-size:90%; color: grey; font-style: italic; }
这是来自 /frontend/views/meeting-time/_list.php 的部分表单的代码:
<?php use yii\helpers\Html; use frontend\models\Meeting; use \kartik\switchinput\SwitchInput; ?> <tr > <!-- panel row --> <td > <table class="table-list"> <!-- list of times --> <tr> <td class="table-list-first"> <!-- time & status --> <?= Meeting::friendlyDateFromTimestamp($model->start,$timezone) ?> <?php if ($whenStatus['text'][$model->id]<>'') { ?> <br /><span class="smallStatus"> <?php echo $whenStatus['text'][$model->id]; ?> </span><br /> <?php } ?> </td> <td class="table-switches"> <!-- col of switches to float right --> <table > <tr> <td > <?php if ($isOwner) { showTimeOwnerStatus($model,$isOwner); } else { showTimeParticipantStatus($model,$isOwner); } ?> </td> <td class="switch-pad"> <?php if ($timeCount>1) { if ($model->status == $model::STATUS_SELECTED) { $value = $model->id; } else { $value = 0; } if ($isOwner || $participant_choose_date_time) { // value has to match for switch to be on echo SwitchInput::widget([ 'type' => SwitchInput::RADIO, 'name' => 'time-chooser', 'items' => [ [ 'value' => $model->id], ], 'value' => $value, 'pluginOptions' => [ 'size' => 'mini','handleWidth'=>60,'onText' => '<i class="glyphicon glyphicon-ok"></i> choose','onColor' => 'success','offText'=>'<i class="glyphicon glyphicon-remove"></i>'], // $whenStatus['style'][$model->id], 'labelOptions' => ['style' => 'font-size: 12px'], ]); } } ?> </td> </tr> </table> </td> <!-- end col with table of switches --> </tr> </table> <!-- end table list of times --> </td> </tr> <!-- end panel row -->
这些会议视图变化的最大好处是,它们将简化未来有许多参与者的会议的用户体验设计挑战。无论参加会议的人数有多少,观点都会与上述基本相同。从本质上讲,这解决了我扩展到多人会议的最大障碍——用户体验设计。
我希望您喜欢跟随我研究响应式网页设计的细节。当网站的代码和视觉变化结合在一起时,我感到非常满意,并且对 CSS 的需要之少印象深刻。综合起来,您可以在这里看到:
.rwd-break { display:none; } table.table-list { width:100%; } table.table-list td.table-list-first { float: left; display: inline; width: auto; } table.table-list td.table-switches { width: auto; float: right; display: inline; padding-top: 10px; } .switch-pad { padding-left:7px; } .smallStatus { font-size:90%; color: grey; font-style: italic; } .setting-label label, #preferences label { font-weight:normal; } /* ----------- mobile displays ----------- */ @media only screen and (min-device-width: 320px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { /* hides drop down menu items and footer items */ .itemHide,li.menuHide { display:none; visible:false; } /* removes home and / from breadcrumb */ ul.breadcrumb li:first-child, li.tabHide { display:none; visible:false; } ul.breadcrumb li:nth-child(2)::before { content:''; } /* fingertip spacing for buttons */ a.icon-pad { padding: 0 5px 0 2px; } .button-pad { padding-left:7px; } .rwd-break { display:block; } }
我未来的设计工作将从“这在移动设备上看起来应该是什么样子?”
如前所述,我目前正在积极准备 Meeting Planner 的 alpha 版本。我主要关注使 alpha 版本顺利发布的关键改进和功能。
我现在正在跟踪 Asana 中的所有内容,我将在另一个教程中对此进行介绍;这非常有帮助。还有一些有趣的新功能仍在开发中。
J'ai également commencé à accorder plus d'attention à mes prochains efforts de collecte d'investissements via Meeting Planner. Je viens de commencer à essayer WeFunder avec la mise en œuvre des nouvelles règles de financement participatif de la SEC. Veuillez envisager de suivre notre profil. J'aborderai également cela en détail dans un prochain tutoriel.
Encore une fois, en attendant d'autres épisodes, planifiez votre première séance (sur votre téléphone !). De plus, je vous serais reconnaissant de partager vos expériences dans les commentaires ci-dessous et je suis toujours intéressé par vos suggestions. Vous pouvez également me contacter directement sur Twitter @reifman. Vous pouvez également les publier sur le site Web d’assistance aux organisateurs de réunions.
Regardez les prochains tutoriels de la série « Construisez votre startup avec PHP ».
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!