Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

當耐特發表於2019-04-10

寫在前面

開發小程式,但是:沒有後端!沒有運維!沒有 DBA!沒有域名!沒有證照!沒有錢!沒有時間!沒有精力!

沒有關係,會 javascript 就可以,小程式•雲開發帶你起飛!

開發者可以使用雲開發開發微信小程式、小遊戲,無需搭建伺服器,即可使用雲端能力。雲開發為開發者提供完整的雲端支援,弱化後端和運維概念,無需搭建伺服器,使用平臺提供的 API 進行核心業務開發,即可實現快速上線和迭代,同時這一能力,同開發者已經使用的雲服務相互相容,並不互斥。

目前提供三大基礎能力支援:

  • 雲函式:在雲端執行的程式碼,微信私有協議天然鑑權,開發者只需編寫自身業務邏輯程式碼
  • 資料庫:一個既可在小程式前端操作,也能在雲函式中讀寫的 JSON 資料庫
  • 儲存:在小程式前端直接上傳/下載雲端檔案,在雲開發控制檯視覺化管理

一步一步搭建

本文將一步一步教你使用 小程式•雲開發 + Omip + Comi 搭建一個支援 markdown 和程式碼高亮的小程式內容展示和釋出系統。

預覽:

Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

1.建表

Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

操作路徑: 微信開發者工具→雲開發→資料庫→新增集合

article 集合欄位說明:

欄位 說明
_id 資料的唯一 id,使用者寫入時系統自動生產
_openid 使用者的唯一標識,使用者寫入時系統自動生產
createTime 文章建立時間
md 文章內容
order 文章的順序
title 文章的標題

很明顯,這個表用來儲存所有的文章。然後設定表的讀寫許可權:

Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

因為後續可能支援使用者發表文章,所有設定成第一個。

2.初始化專案目錄

$ npm i omi-cli -g 
$ omi init-cloud my-app     
$ cd my-app          
$ npm start          
複製程式碼
Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

這裡是使用 omip 作為腳手架,也支援 Omi mps-cloud 建立原生小程式的雲開發的腳手架:

$ npm i omi-cli -g              
$ omi init-mps-cloud my-app    
$ cd my-app/miniprogram   
$ npm install
$ npm start               
複製程式碼

3.專案初始化 app.js

import './app.css'
import './pages/list/index'
import { render, WeElement, define } from 'omi'

define('my-app', class extends WeElement {

  config = {
    pages: [
      'pages/list/index',
      'pages/detail/index',
      'pages/import/index'
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#fff',
      navigationBarTitleText: 'Omi Cloud',
      navigationBarTextStyle: 'black'
    }
  }

  install() {
    if (!wx.cloud) {
      console.error('請使用 2.2.3 或以上的基礎庫以使用雲能力')
    } else {
      wx.cloud.init({
        traceUser: true,
      })
      this.globalData.db = wx.cloud.database({
        env: 'test-06eb2e'
      })
    }
  }

  render() {
    return (
      <page-list />
    )
  }
})

render(<my-app />, '#app')
複製程式碼
Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

wx.cloud.database 程式碼引數裡的 env 可以從上面獲取到,一般建立兩個環境,一個使用者測試環境,一個用於生產環境。

  • pages/list/index 文章列表首頁
  • pages/detail/index 文章詳情夜
  • pages/import/index 文章匯入頁(先簡單通過程式碼匯入 markdown,沒提供 UI)

匯入 markdown 資料

import { WeElement, define } from 'omi'
import data from './test.md'

const app = getApp()

define('page-import', class extends WeElement {

  installed() {
    wx.cloud.callFunction({
      name: 'login',
      data: {},
      success: res => {
        app.globalData.openid = res.result.openid
        app.globalData.db.collection('article').add({
          data: {
            md: data.md,
            title: 'test',
            createTime: app.globalData.db.serverDate()
          },
          success: (res) => {
            console.log(res)
          },
          fail: err => {
            console.error('[雲函式] [login] 呼叫失敗', err)
          }
        })
      },
      fail: err => {
        console.error('[雲函式] [login] 呼叫失敗', err)
      }
    })
  }

  ...
  ...
})
複製程式碼

注意三點:

  • 通過 wx.cloud.callFunction 呼叫雲函式進行登陸,且獲取 openid,接著匯入資料會自動帶上提交該 openid。
  • 通過 app.globalData.db.serverDate() 獲取服務端時間,客戶端時間不可靠
  • 文章匯入只由管理員負責

注意 import data from './test.md',這裡通過修改 omip 裡的 scripts 邏輯實現。

這裡解釋下 import markdown 原理:

let code = fs.readFileSync(item).toString()
if (path.extname(item) === '.md') {
  code = `export default { md: \`${code.replace(/`/g, '\\`').replace(/\$/g, '\\$')}\` }`
}
複製程式碼

檢測到 md 字尾的檔案,把檔案裡的 markdown 字串對關鍵字進行轉義然後變成一個 js 模組。

這也算是使用中間編譯的好處之一吧,如果原生的小程式目前沒辦法 import markdown 檔案,當然原生小程式 API 和周邊生態在不斷進化,騰訊 Omi 團隊開發的 mps 框架 就是讓你在原生小程式中使用 jsx 和 less。

上面的詳細程式碼可以點選這裡檢視到。

列表頁

Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

請求 list 資料

 //先展示 loading
 wx.showLoading({
    title: '載入中'
  })
  //呼叫雲函式獲取 openid
  wx.cloud.callFunction({
    name: 'login',
    data: {},
    success: res => {
      app.globalData.openid = res.result.openid
      app.globalData.db.collection('article').field({
        title: true,
        _id: true,
        order: true
      }).get().then(res => {
        this.data.list = res.data.sort(function (a, b) {
          return a.order - b.order
        })
        this.update()
        wx.hideLoading()
      })
    },
    fail: err => {
      console.error('[雲函式] [login] 呼叫失敗', err)
    }
  })
複製程式碼
  • 請求 list,通過 field 方法篩選欄位,畢竟 list 不需要 md 欄位,這樣可以減少資料傳輸,節約頻寬
  • 通過 order 欄位對 list 進行排序(這樣管理員不需要發版本就可以手動調整 order 給 list 排序)

完整的程式碼:

import { WeElement, define } from 'omi'
import './index.css'
import arrowPng from './arrow.png'

//獲取應用例項
const app = getApp()

define('page-about', class extends WeElement {
  config = {
    navigationBarBackgroundColor: '#24292e',
    navigationBarTextStyle: 'white',
    navigationBarTitleText: 'Omi',
    backgroundColor: '#ccc',
    backgroundTextStyle: 'light'
  }

  data = {
    list: []
  }

  installed() {
    wx.showLoading({
      title: '載入中'
    })
    wx.cloud.callFunction({
      name: 'login',
      data: {},
      success: res => {
        console.log('[雲函式] [login] user openid: ', res.result.openid)
        app.globalData.openid = res.result.openid
        app.globalData.db.collection('article').field({
          title: true,
          _id: true,
          order: true
        }).get().then(res => {
          this.data.list = res.data.sort(function (a, b) {
            return a.order - b.order
          })
          this.update()
          wx.hideLoading()
        })
      },
      fail: err => {
        console.error('[雲函式] [login] 呼叫失敗', err)

      }
    })
  }

  gotoDetail = (evt) => {
    wx.navigateTo({
      url: '../detail/index?id=' + evt.currentTarget.dataset.id
    })
  }

  render() {
    return (
      <view class='ctn'>
        {list.map(item => (
          <view class='item' data-id={item._id} bindtap={this.gotoDetail}>
            <text>{item.title}</text>
            <image src={arrowPng}></image>
          </view>
        ))}
      </view>
    )
  }
})
複製程式碼

Omip 可以直接讓你使用 jsx 書寫 wxml 結構。編譯出的 wxml 如下:

<block>
  <view class="ctn">
    <view class="item" data-id="{{item._id}}" bindtap="gotoDetail" wx:for="{{list}}" wx:for-item="item"><text>{{item.title}}</text>
      <image src="{{arrowPng}}"></image>
    </view>
  </view>
</block>
複製程式碼

這裡需要注意,點選每一項跳轉詳情也一定要使用 evt.currentTarget.dataset.id,而不能使用 evt.target.dataset.id。這樣點選到文字或者image 上獲取不到 id。

文章詳情展示

這裡使用 Comi 進行 markdown 渲染! Comi 讀 ['kəʊmɪ],類似中文 科米,是騰訊 Omi 團隊開發的小程式程式碼高亮和 markdown 渲染元件。Comi 是基於下面幾個優秀的社群元件進行二次開發而成。

  • wxParse
  • remarkable
  • html2json
  • htmlparser
  • prism

效果預覽:

Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』
import { WeElement, define } from 'omi'
import './index.css'
import comi from '../../components/comi/comi'

//獲取應用例項
const app = getApp()

define('page-about', class extends WeElement {
  config = {
    navigationBarBackgroundColor: '#24292e',
    navigationBarTextStyle: 'white',
    navigationBarTitleText: ' ',
    backgroundColor: '#eeeeee',
    backgroundTextStyle: 'light'
  }

  install(options) {
    wx.showLoading({
      title: '載入中'
    })
    app.globalData.db.collection('article').doc(options.id).get().then(res=>{
      comi(res.data.md, this.$scope)
      wx.hideLoading()
    }).catch(err => {
      console.error(err)
    })
  }


  render() {
    return (
      <view>
        <include src="../../components/comi/comi.wxml" />
      </view>
    )
  }
})
複製程式碼

除了在 omip 中使用,原生小程式也可以使用 Comi:

先拷貝 此目錄 到你的專案。

js:

const comi = require('../../comi/comi.js');

Page({
  onLoad: function () {
    comi(`你要渲染的 md!`, this)
  }
})
複製程式碼

wxml:

<include src="../../comi/comi.wxml" />
複製程式碼

wxss:

@import "../../comi/comi.wxss";
複製程式碼

大功告成,簡單把!

雲函式與除錯

雲函式即在雲端(伺服器端)執行的函式。在物理設計上,一個雲函式可由多個檔案組成,佔用一定量的 CPU 記憶體等計算資源;各雲函式完全獨立;可分別部署在不同的地區。開發者無需購買、搭建伺服器,只需編寫函式程式碼並部署到雲端即可在小程式端呼叫,同時雲函式之間也可互相呼叫。

一個雲函式的寫法與一個在本地定義的 JavaScript 方法無異,程式碼執行在雲端 Node.js 中。當雲函式被小程式端呼叫時,定義的程式碼會被放在 Node.js 執行環境中執行。我們可以如在 Node.js 環境中使用 JavaScript 一樣在雲函式中進行網路請求等操作,而且我們還可以通過雲函式後端 SDK 搭配使用多種服務,比如使用雲函式 SDK 中提供的資料庫和儲存 API 進行資料庫和儲存的操作,這部分可參考資料庫和儲存後端 API 文件。

雲開發的雲函式的獨特優勢在於與微信登入鑑權的無縫整合。當小程式端呼叫雲函式時,雲函式的傳入引數中會被注入小程式端使用者的 openid,開發者無需校驗 openid 的正確性因為微信已經完成了這部分鑑權,開發者可以直接使用該 openid。

在本文的小程式裡有個 todo 的案例,裡面的 remove 使用了雲函式,用於清空所有已完成的任務。

Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』
const cloud = require('wx-server-sdk')
cloud.init()

const db = cloud.database()
const _ = db.command

exports.main = async (event, context) => {
  try {
    return await db.collection('todo').where({
      done: true
    }).remove()
  } catch (e) {
    console.error(e)
  }
}
複製程式碼
Omi × 雲開發『半天』搞定小程式 『markdown 內容釋出系統』

不過最新的IED,雲函式支援了本地除錯功能,感興趣的可以點選這裡瞭解下。

相關連結

相關文章