完整的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');
  })
*/

複製代碼
相關文章
相關標籤/搜索