今天,我们通过 Vue.js,Laravel 以及 Tailwind 构建一个简单的 todo 应用。为了节约时间,我们不提供任何的数据交互。但是不要担心,接下来的第二部分将会更加的精彩。
开发准备
首先,我们通过 Laravel CLI 在需要添加项目的目录中运行 laravel new <自定义工程名>
来构建一个项目。Laravel CLI 可以帮我们完成我们所需的 Laravel 和 Vue 的安装。
对于这样简单的项目来说,我们直接使用默认的welcome.blade.php
文件。我们必须要配置这个模板,以便 Vue 可以挂载到项目并正常工作。首先,将下面的 meta
标签添加到 head
标签内的其他meta
标签下方即可。
<meta name="csrf-token" content="{{ csrf_token() }}">
现在,我们可以删除默认的样式表以及导入的字体,然后来操作 body。在body
标签内,我们可以看到一堆生成的代码。接下来,我们将其替换为如下内容:
<div id="app">
<example-component></example-component>
</div>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}"></script>
运行项目,通过屏幕我们可以看到项目已正常运行。
如你所见,示例组件已正确渲染,可以小小的得意一下。您自己在编写过程中如有任何错误,可随时查看项目的GitHub repo ,按照我的提交来检查。
现在我们开始准备 Tailwind,我假设你已经查看了我较早的一篇文章earlier article 并完成了里面的工作,该项目解释了如何在 Laravel 工程中配置 Tailwind。完成上面所述工作后,让我们在welcome.blade.php
中再增加一行代码,以便我们可以使用 Tailwind 样式。在head
标签内的title
标签下,添加导入这段代码:<link href="{{ asset('css/app.css') }}" target="_blank" rel="external nofollow" rel="stylesheet">
。
最后,我们开始准备开发!
Vue.js 组件
让我们拆开脚手架并通过添加自己的组件来进行 Vue 开发。 在 resources/assets/js/components
目录下, 我们删除 ExampleComponent.vue
, 并且添加命名为 todo.vue
的文件。 现在,在 resources/assets/js/app.js
内部, 我们可以更新组件用来引入我们的 todo 组件,就像下面这样:
Vue.component('todo-component', require('./components/todo.vue'));
在 welcome.blade.php
文件中, 我们可以像下面这样将 Vue 组件换成我们的 todo 组件。
<todo-component></todo-component>
要在浏览器看到它,我们需要运行 Laravel Mix。如果你一直按照我的方法,那么我建议使用npm run watch
,那么编写的代码将会自动编译。在我们的模板文件中,我们可以添加如下所示代码:
<template>
<div>
<div>
<h1>Todo List</h1>
<div>
<input v-model="newTodo" placeholder="Add Todo">
<button @click="add" :disabled="newTodo.length === 0">Add</button>
</div>
</div>
<div>
<div v-for="(todo, index) in todos" :key="todo.id">
<p>{{todo.text}}</p>
<button @click="updateStatus(todo)" v-text="todo.finished ? 'Not Done' : 'Done'"></button>
<button @click="remove(index)">Remove</button>
</div>
</div>
</div>
</template>
如你所见,这是一个非常简单的 Vue 组件。像所有的 Vue 组件一样,我们拥有一个 div
包装器,以及两个子 div
。在第一个 div 区块里面我们有标题,以及新的 todo input
。我们已经 input
绑定到名为 newTodo
的v-model
,并且我们在button
中添加了一个名为add
的方法,用来提交新的 todo。当input
没有输入文本时,该按钮将处于禁用状态,这样保证我们不会提交空的 todo。
在底部的div
中,我们将遍历已添加的每个 todo,并显示text
数据和两个按钮。第一个按钮可以让我们将 todo 标记为已完成或未完成,第二个按钮可以将 todo 完全删除。是不是感觉 So Easy?
接着往下看,这是我们编写的 Vue 组件的其余部分。
<script>
export default{
data(){
return{
todos: [],
newTodo: '',
baseId: 1,
}
},
methods: {
add() {
const t = this;
let todo = {
id: t.baseId,
text: t.newTodo,
finished: false,
}
t.todos.push(todo);
t.newTodo = '';
t.baseId++;
},
updateStatus(todo) {
todo.finished = !todo.finished;
},
remove(index) {
const t = this;
t.todos.splice(index, 1);
}
}
}
</script>
这里我们可以管理 todo 数据,而且我们可以看到上面模板绑定的三个方法。在数据中,我们有一个 todos 数组,可以在其中存储 todo;我们有绑定到input
上的 newTodo,最后,baseId是用来给每个 todo 一个假的『unique』id,以便 Vue 在v-for
遍历时跟踪它们。
在 methods 里,我们有add()
方法,它可以使用 data 中 newTodo 以及 baseId 来创建一个新的 todo 实例,并将其推入到我们的 todo 数组,然后将 input 状态重置为空的递增 baseId。然后我们来看updateStatus()
方法,它可以更新 todo 的完成状态。最后我们再看看remove()
方法,它会传入 todo 的 index 作为参数并将其从 todos 数组中移除。
运行·npm run prod,我们可以在浏览器看到 todo 组件的效果。
使用组件时,可以看到 todo 的添加顺序不正确。好尴尬啊!在add()
方法中,我们使用.unshift()
来替换.push()
。现在,它基本达到了我们的预期。
组件虽然功能齐备,但是看起来还是不太好看。接下来我们将搭配 Tailwind CSS 使其更加友好。
看起来不错
现在,我们的应用程序在 Tailwind 中看起来很好。首先,从 welcome.blade.php
文件开始, 把 todo 组件放置在页面中间。
在拥有应用 id 的 div
上, 我们可以添加以下内容。 class="h-screen flex items-center justify-center"
。这会将我们的组件放置在页面的中间。 然后添加一些背景色和字体用来介绍一些基本样式。 在相同的 div
上添加 .bg-teal-lightest
和 .font-sans
类。 页面看起来更好了。
现在,我们可以将焦点放在我们的组件样式上。让我们从一些基本的组件开始,这样我们就可以看到我们在处理什么。在todo.vue
文件中的div
包装器上,我们可以添加.bg-white
,.rounded
,.shadow
,以及.p-6
class,从而来制作一个漂亮的 card。
有了白色的背景,我们可以在页面上看到div
的显示位置。因此,让我们使用以下类为它提供一个更好的宽度:.m-4
,.w-full
,.lg:w-3/4
,以及.lg:max-w-lg
。如你所见,在移动设备上,我们让 card 占据整个屏幕的宽度,一旦达到了我们的最大断点,我们继续让它增长,直到它达到屏幕的 75% 或者最大宽度。
接下来处理 todo 列表本身,对于包装器div
的 header,我们只需在底部添加一个.mb-4
class,使其与列表项分开。然后在h1
上,我们添加一个.text-grey-darkest
class,这样效果看起来就不是那么紧凑。
现在有趣的部分是我们的新 todo 输入框。对于它的包装器 div
,我们将通过添加.flex
类使它变样 ,并通过 .mt-4
给它和 h1
之间保留间距。 在 input
框和 button
按钮上,我们将添加一大堆这样的类:
<input class="shadow appearance-none border rounded w-full py-2 px-3 mr-4 text-grey-darker" v-model="newTodo" placeholder="Add Todo">
<button class="flex-no-shrink p-2 border-2 rounded text-teal border-teal hover:text-white hover:bg-teal" @click="add" :disabled="newTodo.length === 0">Add</button>
这些内容都很简单,使你困惑的可能是 input
上的 .appearance-none
以及 button
上的 flex-no-shrink
, .appearance-none
是一个重置类,用于从给定元素中删除所有浏览器样式。 而 .flex-no-shrink
是一个 flex 助手, 它将 flex-shrink
设置成0用来防止按钮文字在较小的视图中自动换行。现在,我们有了一个样式精美的标题。
在我们设置样式之前,新的样式看起来会使我们忽视掉空的状态,我们应该让用户知道他们没有任何的 todo。
在第二个 div
组,v-for
的下边, 我们可以添加以下内容:
<div v-show="todos.length === 0">
<p class="w-full text-center text-grey-dark">There are no todos</p>
</div>
现在,我们的用户可以看到 todo 在上面了。
最后,我们仅需给我们的todo添加样式。我们可以忽略外层的div,直接跳到我们的 v-for.再一次,我们将要添加一堆完整的css class.所以,让我们看看完成后的效果然后再仔细检查一遍。
<div class="flex mb-4 items-center" v-for="(todo, index) in todos" :key="todo.id">
<p class="w-full" :class="todo.finished ? 'line-through text-green' : 'text-grey-darkest'">{{todo.text}}</p>
<button class="flex-no-shrink p-2 ml-4 mr-2 border-2 rounded hover:text-white" :class="todo.finished ? 'text-grey border-grey hover:bg-grey' : 'text-green border-green hover:bg-green'" @click="updateStatus(todo)" v-text="todo.finished ? 'Not Done' : 'Done'"></button>
<button class="flex-no-shrink p-2 ml-2 border-2 rounded text-red border-red hover:text-white hover:bg-red" @click="remove(index)">Remove</button>
</div>
都是很简单的东西,但是我们将要做一到两处特别的更改。在"v-for"和"div",我们只是需要让它们变得灵活,跟中间的元素对齐,并且在底部加上一些空白。
"p"标签可能看起来简单,但是我们实际上利用了Vue的动态类来转换我们的css类以达到让我们的用户看到他们已经完成了todo的效果.在未完成的状态下,我们只是用".text-grey-darkset"来给文字上深灰色。但是,在完成的状态时,我们要用".text-green"和".line-through"来转换颜色成绿色并且加上一个删除线。
对于这里的按钮,我们利用了之前添加「add」 按钮的一些类,同时也利用了 Vue 的动态类。接下来,试着自己动手,分析我们到底做了什么。
现在,我们终于完成了我们的想要的样式。
、
总结
嚯!我们在这方面确实做了很多工作,现在才刚刚开始。在本文中,我们创建了Laravel、Vue 和 Tailwind 项目;使用Vue.js 构建了一个 todo 组件,然后用Tailwind 进行样式化。
对于下一篇文章,我们当然还有很多内容要涉及到。我们必须将 todo 持久化到数据库,并且应该可能将一些 Tailwind 类抽取到我们自己的样式表中,这样更方便管理组件。
phper在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家需要的(点击→)我的官方群677079770