jrg-project-5
jrg-project-5 copied to clipboard
No Backend!
cp -r step-3 step-4
cd step-4
webpack --watch #然后新开窗口写代码,这个不要关
我们需要一台服务器吗?
上个任务中,我们的数据存在 localStorage 中,这样有很多弊端:
- 如果用户清空缓存,那么 todoList 就没了……
- 如果用户换一台电脑,那么 todoList 也看不见了……
所以,我们是不是应该买一台服务器来存所有用户的数据?
可以,但是服务器是要钱的,我们现在还没必要花这个钱。
No Backend(无后台)
没有服务器能不能存数据呢? 答案是「不能,但是又能」。
说「不能」是因为无论如何,我们都需要一个地方存数据。 说「能」是因为我们不用自己买服务器。
今天我们使用 LeanCloud 的免费服务来存储我们的所有数据。
创建 LeanCloud 账户
你需要去 https://leancloud.cn 创建一个账户。
创建成功后,你需要验证你的邮箱,否则无法创建应用。
创建 resumer 应用
如下图操作:

创建成功后就放在那里,因为接下来我们要按照 LeanCloud 的「JavaScript SDK 文档」来开发登录、注册功能。
登录和注册
首先还是用 HTML 把界面做出来。
页面分区
目前我们的页面的结构是
div#app > div.newTask + ol.todos
我们要改成
div#app
section#signInAndSignUp
section#todo
div.newTask + ol.todos
用一个 section#todo 将原有内容包起来,然后新建一个 section#signInAndSignUp(注意大小写)
最终结果是:
<div id="app">
<section id="signInAndSignUp">
<div>
<label><input type="radio" name="type" value="signUp">注册</label>
<label><input type="radio" name="type" value="login">登入</label>
</div>
<div class="signUp">
<form>
<div class="formRow">
用户名<input type="text">
</div>
<div class="formRow">
密码<input type="password">
</div>
<div class="formActions">
<input type="submit" value="注册">
</div>
</form>
</div>
<div class="login">
<form>
<div class="formRow">
用户名<input type="text">
</div>
<div class="formRow">
密码<input type="password">
</div>
<div class="formActions">
<input type="submit" value="登入">
</div>
</form>
</div>
</section>
<section id="todo">
<div class="newTask">
<input type="text" v-model="newTodo" @keypress.enter="addTodo">
</div>
<ol class="todos">
<li v-for="todo in todoList">
<input type="checkbox" v-model="todo.done"> {{ todo.title }}
<span v-if="todo.done">已完成</span>
<span v-else>未完成</span>
<button @click="removeTodo(todo)">X</button>
</li>
</ol>
</section>
</div>
预览图:

Tab 切换
我们希望
- 用户点击「〇注册」这个 radio button 的时候显示注册表单
- 用户点击「〇登入」这个 radio button 的时候显示登入表单
- 默认显示注册表单
所以我们需要加一个变量,叫做 actionType,它有两个取值:'signUp' 和 'login',都是字符串。
app.js
...
el: '#app',
data: {
actionType: 'signUp',
...
然后将 actionType 与 radio button 绑定(使用 v-model):
<section id="signInAndSignUp">
<div>
<label><input type="radio" name="type" v-model="actionType" value="signUp">注册</label>
<label><input type="radio" name="type" v-model="actionType" value="login">登入</label>
</div>
...
最后让两个表单根据 actionType 来显示和隐藏(注意单引号,为什么要加单引号呢?想想):
<div class="signUp" v-if="actionType=='signUp'">
<form>
<div class="formRow">
用户名<input type="text">
</div>
<div class="formRow">
密码<input type="password">
</div>
<div class="formActions">
<input type="submit" value="注册">
</div>
</form>
</div>
<div class="login" v-if="actionType=='login'">
<form>
<div class="formRow">
用户名<input type="text">
</div>
<div class="formRow">
密码<input type="password">
</div>
<div class="formActions">
<input type="submit" value="登入">
</div>
</form>
</div>
这样一来,用户点击 radio button 时就会改变 actionType 的值,actionType 的值一变,两个表单就会一个隐藏,一个显示。
注册
要实现注册功能,首先我们要用数据来表达表单里的每个字段。
data: {
actionType: 'signUp',
formData: {
username: '',
password: ''
},
然后将 input 与数据绑定起来,另外还要绑定 form 的 submit 事件:
<div class="signUp" v-if="actionType === 'signUp'">
<form @submit.prevent=signUp> <!--👈-->
<div class="formRow">
用户名<input type="text" v-model="formData.username"> <!--👈-->
</div>
<div class="formRow">
密码<input type="password" v-model="formData.password"> <!--👈-->
</div>
<div class="formActions">
<input type="submit" value="注册">
</div>
</form>
</div>
接下来我们来完善 signUp 的逻辑。在写代码之前,我们需要阅读 leanCloud 的文档:
- 安装 LeanCloud SDK
https://leancloud.cn/docs/sdk_setup-js.html
npm install leancloud-storage --save - 初始化
https://leancloud.cn/docs/sdk_setup-js.html#初始化
app.js
import Vue from 'vue' import AV from 'leancloud-storage' var APP_ID = '8axnRtGoxCJhEzsvNPEAHnol-gzGzoHsz'; var APP_KEY = '0YH4XkYflb4CUPfA743TGj8G'; AV.init({ appId: APP_ID, appKey: APP_KEY }); var app = new Vue({ ... - 验证 LeanCloud SDK 安装成功
https://leancloud.cn/docs/sdk_setup-js.html#验证
刷新 page.html 后看到... AV.init({ appId: APP_ID, appKey: APP_KEY }); var TestObject = AV.Object.extend('TestObject'); var testObject = new TestObject(); testObject.save({ words: 'Hello World!' }).then(function(object) { alert('LeanCloud Rocks!'); }) var app = new Vue({ ...
如果可以用 AV 对象了,然后把上面的验证代码删掉。
接下来我们看 LeanCloud 关于注册的文档,如果你看不懂,可以使用我们的「copy-run-modify」套路。按照文档的例子,我们写出这样的代码:
methods: {
addTodo: function(){
...
},
removeTodo: function(todo){
...
},
signUp: function () {
let user = new AV.User();
user.setUsername(this.formData.username);
user.setPassword(this.formData.password);
user.signUp().then(function (loginedUser) {
console.log(loginedUser);
}, function (error) {
});
}
}
刷新页面,我们选择注册,然后用户名填入「123123」,密码填入「123123」,先别急着提交,打开开发者工具,切到 Network,然后提交:

你会看到发了两个请求到 LeanCloud 的服务器,这两个请求就是向 LeanCloud 的服务器存入用户名和密码。 然后再切到 console,你会看到打印出的 loginedUser:

这里我们只关注它的三个属性:attributes, createdAt, id。
其中 attributes 就是我们传给数据库的 username(我们不是还传了一个 password 吗?服务器是不会把 password 传给前端的)
createdAt 是这个数据创建的时间,id 是用户的 id,也是我们区别用户的唯一凭据。
好了,到此为止,我们的注册功能已经做好了。是不是很简单。 目前的代码快照在这里:https://github.com/jirengu-inc/jrg-project-5/blob/a2690c8efe55262e7850ca3e807fa4852198ffd5/step-4/app.js
去数据库看看这个用户
你到 LeanCloud 的 控制面板 点击「存储」,然后点击「_User」就能看到这个用户的数据了:

登入
注册做完了接下来是登入,步骤也差不多。
首先绑定数据,我们复用注册的 formData 这个数据,因为
- 字段相同,都是 username 和 password
- 这样一来用户切换登录注册的时候,已输入的数据就不需要再输入一遍
- 当然你想用另一个数据 formData2 也行
<div class="login" v-if="actionType === 'login'">
<form @submit.prevent="login"> <!--👈-->
<div class="formRow">
用户名<input type="text" v-model="formData.username"> <!--👈-->
</div>
<div class="formRow">
密码<input type="password" v-model="formData.password"> <!--👈-->
</div>
<div class="formActions">
<input type="submit" value="登入">
</div>
</form>
</div>
然后看一下 LeanCloud 文档,这次大家自己找文档,找不到就用 Google 搜,你会找到的。 看懂文档你就可以添加 login 这个方法了:
signUp: function () {
let user = new AV.User();
user.setUsername(this.formData.username);
user.setPassword(this.formData.password);
user.signUp().then(function (loginedUser) {
console.log(loginedUser);
}, function (error) {
});
},
login: function () {
AV.User.logIn(this.formData.username, this.formData.password).then(function (loginedUser) {
console.log(loginedUser);
}, function (error) {
});
}
接下来刷新 page.html,选中「登入」,输入用户名「123123」,密码「123123」。 观察 network 和 console,会得到跟注册类似的结果。
好了,登录功能就完成了。
登录前后
我们希望
- 登录之前,不显示 section#todo,显示 section#signInAndSignUp
- 登录之后,显示 section#todo,不显示 section#signInAndSignUp
那么我们如何判断用户是否已登录。
LeanCloud 文档说 AV.User.current() 可以获取当前登录的用户。那么我们这么做:
app.js
data: {
...
todoList: [],
currentUser: null, // 👈
},
app.js
signUp: function () {
let user = new AV.User();
user.setUsername(this.formData.username);
user.setPassword(this.formData.password);
user.signUp().then((loginedUser) => { // 👈,将 function 改成箭头函数,方便使用 this
this.currentUser = this.getCurrentUser() // 👈
}, (error) => {
alert('注册失败') // 👈
});
},
login: function () {
AV.User.logIn(this.formData.username, this.formData.password).then((loginedUser) => { // 👈
this.currentUser = this.getCurrentUser() // 👈
}, function (error) {
alert('登录失败') // 👈
});
},
getCurrentUser: function () { // 👈
let {id, createdAt, attributes: {username}} = AV.User.current()
// 上面这句话看不懂就得看 MDN 文档了
// 我的《ES 6 新特性列表》里面有链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
return {id, username, createdAt} // 看文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Object_initializer#ECMAScript_6%E6%96%B0%E6%A0%87%E8%AE%B0
}
page.html
<section id="signInAndSignUp" v-if="!currentUser">
...
<section id="todo" v-if="currentUser">
然后刷新 page.html ,登录之后,登录表单就不见啦。
其他功能
后面的功能我写教程写不动了,大家看我的 commit
致饥人谷学员
搞定上面的教程,满足以下功能:
- 可注册
- 可登入
- 可登出
挑战
- 在界面上显示当前用户的 username
- 将 TodoList 存到 User 名下,而不是存到 localStorage。(这是下个任务里我们要做的事情)
预览地址:https://jirengu-inc.github.io/jrg-project-5/step-4/page.html 代码:看本仓库的 step-4 目录
@starlikerain 你加个 bool 干什么,直接双向绑定,谁跟你说 radio button 一定要绑定 bool 呀
效果 ZJY 不知道为什么 我的bundle文件变的特别大..我看了下有两万多行..一打开电脑风扇就转不停,而且webstorm提示这文件有错误,但是运行时 窗口没有报任何错误..
@chaocool BUG1: 每次刷新页面之后,登录的用户就不见了
@FrankFang 已经修复 辛苦方方老师 预览
