Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No Backend! #4

Open
FrankFang opened this issue Jan 20, 2017 · 51 comments
Open

No Backend! #4

FrankFang opened this issue Jan 20, 2017 · 51 comments
Labels

Comments

@FrankFang
Copy link
Contributor

FrankFang commented Jan 20, 2017

cp -r step-3 step-4
cd step-4
webpack --watch #然后新开窗口写代码,这个不要关

我们需要一台服务器吗?

上个任务中,我们的数据存在 localStorage 中,这样有很多弊端:

  1. 如果用户清空缓存,那么 todoList 就没了……
  2. 如果用户换一台电脑,那么 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 切换

我们希望

  1. 用户点击「〇注册」这个 radio button 的时候显示注册表单
  2. 用户点击「〇登入」这个 radio button 的时候显示登入表单
  3. 默认显示注册表单

所以我们需要加一个变量,叫做 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 的文档:

  1. 安装 LeanCloud SDK
    https://leancloud.cn/docs/sdk_setup-js.html
    npm install leancloud-storage --save
  2. 初始化
    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({  ...
    
  3. 验证 LeanCloud SDK 安装成功
    https://leancloud.cn/docs/sdk_setup-js.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({ ...
    
    刷新 page.html 后看到
    如果可以用 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 这个数据,因为

  1. 字段相同,都是 username 和 password
  2. 这样一来用户切换登录注册的时候,已输入的数据就不需要再输入一遍
  3. 当然你想用另一个数据 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

添加登出功能
如果用户已经登入,就直接展示 todo

致饥人谷学员

搞定上面的教程,满足以下功能:

  1. 可注册
  2. 可登入
  3. 可登出

挑战

  1. 在界面上显示当前用户的 username
  2. 将 TodoList 存到 User 名下,而不是存到 localStorage。(这是下个任务里我们要做的事情)

预览地址:https://jirengu-inc.github.io/jrg-project-5/step-4/page.html
代码:看本仓库的 step-4 目录

@starlikerain
Copy link

starlikerain commented Jan 20, 2017

@FrankFang
Copy link
Contributor Author

FrankFang commented Jan 20, 2017

@starlikerain 你加个 bool 干什么,直接双向绑定,谁跟你说 radio button 一定要绑定 bool 呀

@hungryYang
Copy link

page
code
YCR

@TerenYeung
Copy link

yjl for v-o-r task-04
source
demo
蟹蟹方方老师,这部分学到很多新知识

@zhangjiuyi
Copy link

效果 ZJY
不知道为什么 我的bundle文件变的特别大..我看了下有两万多行..一打开电脑风扇就转不停,而且webstorm提示这文件有错误,但是运行时 窗口没有报任何错误..

@ReedSun
Copy link

ReedSun commented Jan 22, 2017

完成咯
演示
代码仓库
期待下一个任务~

@whiteblank
Copy link

代码
预览
GJC

@lzm320856
Copy link

预览
代码
LZM,搞定了但这玩意用的不熟,存储数据用的很蠢的办法,等下一期方方揭晓标准答案

@0xjeso
Copy link

0xjeso commented Jan 22, 2017

预览
代码
SJ 还没挑战把数据存到User名下,好饿,趁着还没黑天,我先把早饭吃了···

@yukui630
Copy link

预览
代码
老师辛苦了。

@lightbuild
Copy link

预览
代码
RL,方方老师辛苦了。

@mimi3824ku
Copy link

mimi3824ku commented Jan 22, 2017

预览
代码
LWE

@ab690257072
Copy link

ab690257072 commented Jan 23, 2017

预览
代码
ZLQ存储到User还是没搞明白,方老师辛苦啦

@LisaLi85
Copy link

预览
代码 LLL

@Zegendary
Copy link

page
code
ZXW

@Rice-F
Copy link

Rice-F commented Jan 23, 2017

预览
代码
SJ,辛苦啦

@JaeJiang
Copy link

预览
代码
当个反面教材把😐

@Hsyneve
Copy link

Hsyneve commented Jan 24, 2017

源码
预览
hsy

@baixiaoji
Copy link

演示
代码
ZLJ @FrankFang

@WangXiaoyugg
Copy link

代码
预览
WXY 方方老师辛苦了

@muxi7
Copy link

muxi7 commented Jan 25, 2017

代码
预览
zw 挑战2还没摸索出来,今天回家了,回家在做

@wlf1112
Copy link

wlf1112 commented Jan 28, 2017

代码
预览
WLF 方方老师新年快乐!

@batman-1
Copy link

代码
预览

方方老师 新年快乐!

@Panda-HJN
Copy link

Panda-HJN commented Feb 4, 2017

过个年,胖五斤 - - |||
代码
浏览

HJN

@have-not-BUG
Copy link

预览地址
代码
by:LC
方方老师辛苦了~

@candy252324
Copy link

预览
代码地址
CJH

@code-zhangrui
Copy link

预览
代码

任务10班 张睿

@chaocool
Copy link

预览
代码
CJC

@FrankFang
Copy link
Contributor Author

@chaocool BUG1: 每次刷新页面之后,登录的用户就不见了

@chaocool
Copy link

@FrankFang 已经修复 辛苦方方老师
预览

@JayChenFE
Copy link

JayChenFE commented Feb 23, 2017

预览
代码
任务3 陈捷

@JeromeYangtao
Copy link

代码
预览

@superDCF
Copy link

superDCF commented May 5, 2017

预览

@MasterGaoJin
Copy link

preview
code

@n313893254
Copy link

预览
代码

@success-cg
Copy link

陈功-task4
demo
老师辛苦了

@kumabearplus
Copy link

预览
代码

@boloog
Copy link

boloog commented Jun 14, 2017

预览 boloog

@selectyang
Copy link

代码
预览

@jamesXiao-coder
Copy link

代码

@jettzhang95
Copy link

Preview
Code

@robbchan
Copy link

预览
代码

@zhaipanyu
Copy link

预览
代码

@imgwho
Copy link

imgwho commented Jul 17, 2017

预览
仓库
1705 郭文华

@forsuccess
Copy link

预览

@tcitds1
Copy link

tcitds1 commented Jul 25, 2017

预览

@HuangHongRui
Copy link

Code
Show

@andreaxiang
Copy link

demo预览

@huoguozhang
Copy link

任务4

@ZhyCong
Copy link

ZhyCong commented Aug 3, 2017

任务4
源码

@nciilin
Copy link

nciilin commented Dec 25, 2017

代码
预览

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests