完整的MVC

github连接css

LeanCloud介绍

咱们知道前端的JS有倆大功能:DOm操做和Ajax。那么前端若是想要存一个东西怎么办?没有办法存,由于咱们无论存在哪里,用户只要刷新页面或者换一个设备,存的数据就没了。那咱们该如何存数据,才能保证跨设备去保存数据?那就是咱们将数据上传到服务器上,那样即便换了设备,咱们依然能够从服务器上从新获取数据.html

无论什么数据库,咱们都须要一个服务器,将服务器能力免费提供给你用的一个服务LeanCloud,它能作到你想要什么APi就能提供给你什么API,可是本身不能写代码。首先进去建立一个帐号,而后选择应用,建立应用,取个名字,选择开发版,从建立好的应用点击去,而后选择建立class,class就是一个数据库。前端

它是一个自带数据库和增删改查(CRUD)功能的后台系统。node

拥有:git

1.登陆注册、手机验证码功能(收费)github

2.存储任意信息数据库

3.读取任意信息npm

4.搜索任意信息后端

5.删除任意信息api

6.更新任意信息

等功能。

没有见过的知识?

不要慌,使用 Copy-Run-Modify 套路便可。点击帮助,选择快速入门,选择JavaScript为语言

而后是安装SDK

# 存储服务(包括推送)
$ sudo npm install leancloud-storage --save --registry=https://registry.npm.taobao.org
# 即时通信服务
$ sudo npm install leancloud-realtime --save --registry=https://registry.npm.taobao.org
复制代码

而后是引用SDK

<!-- 存储服务 -->
<script src="//cdn.jsdelivr.net/npm/leancloud-storage@3.14.1/dist/av-min.js"></script>
<!-- 即时通信服务 -->
<script src="//cdn.jsdelivr.net/npm/leancloud-realtime@4.3.1/dist/realtime.browser.min.js"></script>
复制代码

而后在项目文件夹中启动http(http-server -c-1),在浏览器中打开 http://127.0.0.1:8081,在控制台输入AV咱们就会发现咱们有一个AV对象了

接下来咱们是作初始化,这里要注意不一样的应用(例子中的应用是咱们刚刚建立的resume-2019-7,应用也就是一个数据库)初始化的时候的APP_ID是不同的,而后复制文档里给的初始化的代码,到目前为止,什么也不用管,什么也不用问,只要抄就行,等把第一个Hello World作出来再说

接下来是验证,ping "o76yo2bd.api.lncld.net"

接下来是测试,在项目文件中写以下代码:

var TestObject = AV.Object.extend('TestObject');
var testObject = new TestObject();
testObject.save({
  words: 'Hello World!'
}).then(function(object) {  // then里面的函数是一个callback
  alert('LeanCloud Rocks!');
})
复制代码

接下来打,开控制台 > 存储 > 数据 > TestObject

咱们会发现多了一个叫TestObject的数据库,数据库里多了一个叫hello world的数据

当咱们用LeanCloud作出了第一个Hell World以后,咱们再回过头来看看咱们作了什么才有了Hello World的数据?

1.建立一个应用 resume-2019.-7

2.引入 av-min.js,获得 window.AV,引入了SDK

3.初始化 AV 对象(代码直接拷),拿到了ID和KEY

4.新建一条数据(代码直接拷),写了一个测试代码

帮助里面有个快速入门,语言选择JavaScript,下面咱们只要用CRM的方法去试就知道了

看下测试的代码它作了:

1.建立了一个叫TestObject的对象

2.实例化这个对象,在表中建立一行数据

3.数据内容是:words: Hello World! 而且保存

4.若是建立而且保存成功了。就弹出 LeanCloud Rocks!

上面咱们作了CRM中的C(copy)R(run)也就是抄和运行,接下来是作CRM中的M(modify)修改,M的厉害之处就是在于咱们在不知道任何原理的状况下去猜到这个代码的这个参数是什么意思

例如以下修改:

// 测试
var ReagenObject = AV.Object.extend('Reagen2019');
var XXX = new ReagenObject();

XXX.save({
  say: '吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮'
}).then(function(object) {
  alert('测试成功');
})

XXX.save({
    jump: '跳进黄河洗不清'
  }).then(function(object) {
    alert('测试成功2');
  })

XXX.save({
    vvv: 'fuck world'
  }).then(function(object) {
    alert('测试成功3');
  })
复制代码

那么这样咱们就有了本身的数据库,基本上咱们就能够想存什么就存什么了,存一些咱们想存的东西

划重点:

咱们这么努力的学习JS,就是为了能看懂代码(各类工具、插件。库文档里的代码),而后去抄它们的代码,而后用CRM的思想去学习前端的不少东西,基础回了以后其余的都是CRM,因此学好JS是前端门槛,若是咱们不懂JS,咱们根本看不懂这些代码,更别说去抄去运行去改了

在简历中加入留言功能

// 初始化
var APP_ID = 'o76YO2bd1s3xSJFBr3GnwzKu-gzGzoHsz';
var APP_KEY = 'wgEnjO9GVghERifYXYM9APy5';

AV.init({
  appId: APP_ID,
  appKey: APP_KEY
});

// 留言
let myForm = document.querySelector('#postMessageForm')
// 应该监听form的submit事件,应为用户回车也算是submit
myForm.addEventListener('submit',function(e){
    e.preventDefault()
    // 拿到用户在输入框中输入的内容
    let content = myForm.querySelector('input[name = content]').value
    // 初始化一个叫Message的数据库
    var Message = AV.Object.extend('Message');
    // 实例化这个数据库对象
    var message= new Message();
    // 在数据库中存数据,key是content,value就是用户在输入框中输入的内容
    message.save({
        'content': content
      }).then(function(object) {
        console.log('数据存入成功')
        console.log(object);
      })
})

复制代码

当在输入框中输入--“我是第一条数据”的时候,名字叫Message的数据库中就多了一条数据,而且控制台中也有了数据存储成功后的响应,http中也发起了一个POST请求

以上只是咱们往数据库里存数据!那么咱们该如何从LeanCloud数据库中读取数据呢?也就是说把全部用户存的数据展现到页面上呢?否则还有什么意义?

从LeanCloud数据库中读取数据(获取历史留言)

咱们该如何把存在LeanCloud数据库中的数据读出来?那就要继续去CRM,继续去文档里面找吧!! 发现再快速入门里面有一个API文档,里面有一个JavaScript数据存储文档,里面有一个使用文档,里面有一个对象,里面有一个批量操做,里面有一批量获取的代码(好像能够Copy),find()就是查找的意思,把Tod改成咱们本身的Message应该就能够了

批量设置 Todo 已经完成:

  var query = new AV.Query('Todo');
  query.find().then(function (todos) {
    todos.forEach(function(todo) {
      todo.set('status', 1);
    });
    return AV.Object.saveAll(todos);
  }).then(function(todos) {
    // 更新成功
  }, function (error) {
    // 异常处理
  });
复制代码

改为:

// 批量获取存储在Message数据库中的数据

  var query = new AV.Query('Message');
  query.find().then(function (messages) {
    console.log(messages)
    console.log(messages[0].attributes)
    console.log(messages[1].attributes)
  }).then(function(messages) {
    // 更新成功
  }, function (error) {
    // 异常处理
  });
复制代码

查看http请求后获得的响应的内容就是咱们以前存在数据库中的数据:

控制台打印出的messages是什么呢?经过控制台发现,咱们存数据不是直接存在这个对象上的,而是存在一个叫attributes的属性上

并且获得的对象是以数组的形式展示的,因此messages[0].attributesmessages[1].attributes就能拿到咱们能够用JS代码把数据渲染到页面的数据了

遍历array的每一项,而且返回每一项的attributes

let array = messages.map( (item)=> item.attributes )

复制代码

最后就是遍历这个每一项带有attributes的array,同时在页面中建立li标签,将li的内容设置为array每一项的content,再把每个li插入到ol中

可是这样作存在一个问题就是:每提交一份数据,就要手动的刷新页面,能不能帮咱们刷新页面?能够,只须要在第二个then的第一个(它的意思是若是存储数据成功了就执行这里的第一个函数)函数里加上window.location.reload()。其中第一个then的第二个函数数处理find失败的。下面是完整的代码

// 初始化
var APP_ID = 'o76YO2bd1s3xSJFBr3GnwzKu-gzGzoHsz';
var APP_KEY = 'wgEnjO9GVghERifYXYM9APy5';

AV.init({
    appId: APP_ID,
    appKey: APP_KEY
});

// 留言
let myForm = document.querySelector('#postMessageForm')
// 应该监听form的submit事件,应为用户回车也算是submit
myForm.addEventListener('submit', function (e) {
    e.preventDefault()
    // 拿到用户在输入框中输入的内容
    let content = myForm.querySelector('input[name = content]').value
    // 初始化一个叫Message的数据库
    var Message = AV.Object.extend('Message');
    // 实例化这个数据库对象
    var message = new Message();
    // 在数据库中存数据,key是content,value就是用户在输入框中输入的内容
    message.save({
        'content': content
    }).then(function (object) {
        window.location.reload()
        console.log('数据存入成功')
        // console.log(object);
    })

})

// 批量获取存储在Message数据库中的数据

var query = new AV.Query('Message');
query.find().then(
    function (messages) {
        let array = messages.map((item) => item.attributes)
        array.forEach((item) => {
            let li = document.createElement('li')
            li.innerText = item.content
            let messageList = document.querySelector('#messageList')
            messageList.appendChild(li)
        })
    },
    function (error) {
      // 异常处理      
    }).then((x)=>{},(error)=>console.log(error))
复制代码

再说一下Promise

说下例子中使用的Promise,其实它就是等价于这种写法:

query.find({success:Fn1,fail: Fn2})

那么Promise说不要这样搞,给你个then你传到then里面,

query.find().then(Fn1,Fn2)它表示若是find成功可就调用Fn1,若是find失败了就调用Fn2,他后面还能够继续的then

query.find()
.then(Fn1,Fn2)
.then(Fn3,Fn4)
复制代码

它表示若是Fn1和Fn2都调用成功了,那么就调用Fn3,若是Fn1和Fn2中间一个调用失败了,就调用Fn4

无刷新留言

既然刷新的做用就是往ol里添加一条数据,为何不直接将这条数据包装成li放到ol里面呢?

message.save({
        'name': name,
        'content': content
    }).then(function (object) {
        let li = document.createElement('li')
        li.innerText = `${object.attributes.name}:\xa0\xa0\xa0\xa0\xa0\xa0${object.attributes..content}`
        let messageList = document.querySelector('#messageList')
        messageList.appendChild(li)
        // window.location.reload()
        // console.log(object)

    })
复制代码

注意,不容许上传 node_modules 到 github !

若是你把 node_modules 目录上传到 github,那么你的项目将变得很是大

请在每一个项目里建立 .gitignore 文件,在文件里写上一行 /node_modules/ ,便可防止 node_modules 目录被提交

若是你已经手贱把 node_modules 提交到了 github,那么请这样来撤销:

1.touch .gitignore

2.echo /node_modules/ >> .gitignore

3.git rm -r --cached node_modules

4.git add . -A

5.git commit -m "remove node_modules"

6.git push

7.npm install 或者 yarn install

MVC的Model

将留言板的message.js连的代码用MVC的思想进行一次封装(必定要当心,函数里面的函数的this,通常用箭头函数,箭头函数的this内外不变,必定要当心addEventListener里面的函数的this是指向被操做的元素):

!function () {
    var view = document.querySelector('#message')
    var controller = {
        view: null,
        messageList: null,
        myForm: null,
        init: function (view) {
            this.view = view
            this.messageList = view.querySelector('#messageList')
            this.myForm = view.querySelector('#postMessageForm')
            this.initAv()
            this.loadMessages()
            this.bindEvents()
        },
        initAv: function () {
            // 初始化
            var APP_ID = 'o76YO2bd1s3xSJFBr3GnwzKu-gzGzoHsz';
            var APP_KEY = 'wgEnjO9GVghERifYXYM9APy5';
            AV.init({ appId: APP_ID, appKey: APP_KEY });
        },
        loadMessages: function () {
            // 批量获取存储在Message数据库中的数据
            var query = new AV.Query('Message');
            query.find().then(
                (messages) => {
                    let array = messages.map((item) => item.attributes)
                    array.forEach((item) => {
                        let li = document.createElement('li')
                        li.innerText = `${item.name}:\xa0\xa0\xa0\xa0\xa0\xa0${item.content}`
                        this.messageList.appendChild(li)
                    })
                },
                function (error) {      // 异常处理 
                    alert('数据提交失败,请稍后再试')
                }).then((x) => { }, (error) => console.log(error))
        },
        bindEvents: function () {       // 留言存储数据
            // 应该监听form的submit事件,应为用户回车也算是submit
            this.myForm.addEventListener('submit',  (e) => {
                e.preventDefault()
                this.saveMessage()
            })
        },
        saveMessage: function () {
            // 拿到用户在输入框中输入的内容
            let myForm = this.myForm
            let content = myForm.querySelector('input[name = content]').value
            let name = myForm.querySelector('input[name = name]').value
            // 初始化一个叫Message的数据库
            var Message = AV.Object.extend('Message');
            // 实例化这个数据库对象
            var message = new Message();
            // 在数据库中存数据,key是content,value就是用户在输入框中输入的内容
            message.save({
                'name': name,
                'content': content
            }).then(function (object) {
                let li = document.createElement('li')
                li.innerText = `${object.attributes.name}:\xa0\xa0\xa0\xa0\xa0\xa0${object.attributes.content}`
                let messageList = this.messageList
                messageList.appendChild(li)
                myForm.querySelector('input[name = content]').value = ''
                myForm.querySelector('input[name = name]').value = ''
                // window.location.reload()
                // console.log('数据存入成功')

            })
        }
    }
    controller.init.call(controller, view)
}.call()

/*
// 测试
var ReagenObject = AV.Object.extend('Reagen2019');
var XXX = new ReagenObject();

XXX.save({
  say: '吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮'
}).then(function(object) {
  alert('测试成功');
})

XXX.save({
    jump: '跳进黄河洗不清'
  }).then(function(object) {
    alert('测试成功2');
  })

XXX.save({
    vvv: 'fuck world'
  }).then(function(object) {
    alert('测试成功3');
  })
*/
复制代码

接下来加入MVC的Model,Model的做用就是获取数据,直接点说就是去写then前面的东西(Promise对象),例子中的find()和save()都是返回一个Promise对象,Model是不会操做任何DOM相关的数据的,不会出现任何的html操做,也不会出现任何的css操做,它只是操做数据库相关的数据(往数据库中存数据,从数据库中取数据);View就是试图层,就是咱们页面中操做的是那一块元素,是在页面中实实在在存在的元素,是用用户能看见可操做的元素;Controller,全部重要的变量都会保存在它本身身上,它将拿到View(前端-页面中的元素)和Model(数据库相关的数据)进行组装、包装(通常是DOM操做)。

总结:

MVC就是把代码分红3块,View告诉程序,写的代码是页面中的哪一块,Model是告诉程序,对数据(数据库中的数据)有哪些操做是全部对数据相关的操做,例子中是初始化数据、存入数据、读取数据,Controller是控制器负责其余的全部事情。MVC是一种代码的组织形式,它不是任何一张框架,也不是任何一种技术,只是一种组织代码的思想。咱们要作的事情就是把v和m传给c,c去初始化model,对view进行操做。通常都是源于用户对页面(view)的某个动做触发了controller的某个监听事件,而后controller拿到model的数据,对view进行必定的响应而且从新渲染页面,见下图

由上图可知:view和model基本没有交互,server和model交互。Model和controller交互,controller和view交互,以上就是代码的分层,controller不是直接去访问server,而是经过Model专门专一的对server 进行访问,model拿到服务器的数据以后就丢给controller,controller拿到数据后就去更新view;view若是被用户点击了,就会通知controller,controller就会调用model,而后model去请求server(server就是服务器)。用了MVC以后职责分别、逻辑清晰、代码简单。全部的前端在接触MVC以后,都会使用MVC,而不是像以前那样写一坨代码,而后用注释来分割,MVC写的好根本不须要注释,只要英文够好,这就是MVC的好处,把前端工程师和后端工程师达成的整个社区的共识总结出了一个思想叫MVC

最终message.js用MVC组织好的代码:

!function () {
    var view = document.querySelector('#message')

    var model = {
        // 从数据库中读取数据
        fetch: function () {    
             // 批量获取存储在Message数据库中的数据
             var query = new AV.Query('Message');
             return query.find()    // find返回的也是一个Promise对象
        },
        //往数据库中存数据
        save: function (name,content) {
            // 初始化一个叫Message的数据库
            var Message = AV.Object.extend('Message');
            // 实例化这个数据库对象
            var message = new Message();
            // 在数据库中存数据,key是content,value就是用户在输入框中输入的内容
            return message.save({   //save返回的是一个Promise对象
                'name': name,
                'content': content
            })
        },
        initAv: function () {
            // 初始化
            var APP_ID = 'o76YO2bd1s3xSJFBr3GnwzKu-gzGzoHsz';
            var APP_KEY = 'wgEnjO9GVghERifYXYM9APy5';
            AV.init({ appId: APP_ID, appKey: APP_KEY });
        }
    }
    var controller = {
        view: null,
        model: null,
        messageList: null,
        myForm: null,
        init: function (view,model) {
            this.view = view
            this.model = model
            
            this.messageList = view.querySelector('#messageList')
            this.myForm = view.querySelector('#postMessageForm')
            this.model.initAv()
            this.loadMessages()
            this.bindEvents()
        },
        loadMessages: function () {
           this.model.fetch().then(
                (messages) => {
                    let array = messages.map((item) => item.attributes)
                    array.forEach((item) => {
                        let li = document.createElement('li')
                        li.innerText = `${item.name}:\xa0\xa0\xa0\xa0\xa0\xa0${item.content}`
                        this.messageList.appendChild(li)
                    })
                },
                function (error) {      // 异常处理 
                    alert('数据提交失败,请稍后再试')
                }).then((x) => { }, (error) => console.log(error))
        },
        bindEvents: function () {       // 留言存储数据
            // 应该监听form的submit事件,应为用户回车也算是submit
            this.myForm.addEventListener('submit', (e) => {
                e.preventDefault()
                this.saveMessage()
            })
        },
        saveMessage: function () {
            // 拿到用户在输入框中输入的内容
            let myForm = this.myForm
            let content = myForm.querySelector('input[name = content]').value
            let name = myForm.querySelector('input[name = name]').value
            this.model.save(name,content).then(function (object) {
                let li = document.createElement('li')
                li.innerText = `${object.attributes.name}:\xa0\xa0\xa0\xa0\xa0\xa0${object.attributes.content}`
                let messageList = this.messageList
                messageList.appendChild(li)
                myForm.querySelector('input[name = content]').value = ''
                myForm.querySelector('input[name = name]').value = ''
                // window.location.reload()
                // console.log('数据存入成功')

            })
        }
    }
    controller.init.call(controller, view,model)
}.call()


/*
// 测试
var ReagenObject = AV.Object.extend('Reagen2019');
var XXX = new ReagenObject();

XXX.save({
  say: '吃葡萄不吐葡萄皮,不吃葡萄倒吐葡萄皮'
}).then(function(object) {
  alert('测试成功');
})

XXX.save({
    jump: '跳进黄河洗不清'
  }).then(function(object) {
    alert('测试成功2');
  })

XXX.save({
    vvv: 'fuck world'
  }).then(function(object) {
    alert('测试成功3');
  })
*/

复制代码
相关文章
相关标签/搜索