咱們研發開源了一款基於 Git 進行技術實戰教程寫做的工具,咱們圖雀社區的全部教程都是用這款工具寫做而成,歡迎 Star 哦若是你想快速瞭解如何使用,歡迎閱讀咱們的 教程文檔 哦css
本文由圖雀社區成員 pftom 寫做而成,歡迎加入 圖雀社區,一塊兒創做精彩的免費技術教程,予力編程行業發展。若是您以爲咱們寫得還不錯,記得 點贊 + 關注 + 評論 三連,鼓勵咱們寫出更好的教程💪html
小程序世界紛爭不斷,巨型 App 都在紛紛構建本身的小程序流量入口,但願在造福商家、用戶的同時,也能鞏固自家流量壁壘,咱們已經熟知了微信小程序、支付寶小程序,咱們可能還知道已經有了頭條小程序,QQ 輕應用等,今天爲你們帶來的是一款新型小程序,是由電商巨頭京東即將發佈的一款小程序,電商巨頭的小程序又會爲中國互聯網帶來怎麼樣的改變了?讓咱們拭目以待吧!而咱們今天將帶你們使用 Taro 來編寫京東小程序,並完成能夠發文章的的多頁面博客小程序。node
咱們將使用同屬於京東凹凸實驗室團隊研發開源的多端統一開發解決方案 -- Taro 來開發咱們的京東小程序。首先咱們來看一看最後的完成效果:git
確保你安裝了 Node 開發環境,沒有請參考圖雀社區另一篇 Node.js 文章,裏面有完善的 Node.js 環境配置。github
安裝了最新的 Node.js 環境以後,咱們使用 Node 安裝時自帶的包管理工具 Npm 來建立一個 Taro 項目,打開終端,運行以下命令:typescript
$ npx @tarojs/cli init jd-mp
運行上面的命令以後,你會看到終端有以下輸出:npm
稍等一會,當終端出現以下字樣時,就表明項目初始化成功啦!編程
yarn install v1.21.1 info No lockfile found. [1/4] Resolving packages... [2/4] Fetching packages... [3/4] Linking dependencies... [4/4] Building fresh packages... success Saved lockfile. Done in 158.43s. 建立項目 jd-mp 成功! 請進入項目目錄 jd-mp 開始工做吧!😝
能夠看到,我用了 158.43s ,因此初始項目的過程可能有點長,請耐心等待,若是最後你沒有看到終端出現如上的字樣,那麼你可能遇到了問題,能夠訪問 Taro 的論壇去尋求解答。json
提示小程序
經過上面的命令初始化項目以後,默認是沒有生成
.gitignore
文件的,這會致使你的版本系統中多了不少node_modules/**
下面的文件,因此咱們須要手動在初始化好的jd-mp
項目根目錄下添加一個.gitignore
文件,並添加對應的規則以下:node_modules # 忽略 `node_modules` 下面的文件 dist # 忽略以後構建項目生成的目錄
若是你安裝了 Node 環境,可是不想或者本身初始化項目是遇到了問題,那麼你能夠 Clone 一下咱們爲你準備的初始項目代碼,以後跟着教程對照着這份初始代碼進行改進就能夠啦!
若是你偏心 Github,那麼能夠運行以下命令來獲取初始代碼:
$ git clone https://github.com/tuture-dev/jd-miniprogram.git
若是你偏心 Gitee,那麼能夠運行以下命令來獲取初始代碼:
$ git clone https://gitee.com/tuture/jd-miniprogram.git
與本身使用命令初始化 Taro 項目不一樣,經過 Clone 咱們爲你準備好的代碼,你須要手動安裝依賴,打開終端,輸入以下命令安裝依賴:
$ cd jd-miniprogram && npm install
好的,經過上面的步驟,咱們就準備好了初始代碼,接下來就須要你實際動手寫代碼了,是否是有點期待呢?咱們立刻就能夠嘗試開發一個京東小程序了!
等等,由於京東小程序纔剛剛出來,尚未正式開始推廣,因此 Taro 初始化項目的腳本里沒有生成京東小程序的開啓依賴,因此咱們須要手動安裝一下對應的開啓依賴,打開命令行,在 jd-mp
項目根目錄下執行以下命令安裝:
$ npm install @tarojs/taro-jd
安裝好以後,咱們還須要在 package.json
中添加以下兩條開啓京東小程序項目的腳本:
{ "name": "jd-mp", "version": "1.0.0", "private": true, "description": "第一個京東小程序", "templateInfo": { "name": "default", "typescript": false, "css": "sass" }, "scripts": { // ... "build:quickapp": "taro build --type quickapp", "build:jd": "taro build --type jd", // ... "dev:quickapp": "npm run build:quickapp -- --watch", "dev:jd": "npm run build:jd -- --watch" }, "author": "", "license": "MIT", "dependencies": { // ... "@tarojs/taro-jd": "^2.1.5", // ... }, // ... }
安裝並添加對應的命令以後,咱們就能夠在終端項目根目錄執行以下命令來運行咱們的京東小程序:
$ npx taro build --type jd --watch
注意要加上 --watch
參數,這樣當咱們在編輯器(如 VSCode)修改內容並保存以後,項目會自動編譯更新,而後刷新開發者工具就能夠查看修改後的效果,上面這條命令會實際運行咱們 package.json
裏面添加的腳本命令:
"dev:jd": "npm run build:jd -- --watch"
當進行了上面的配置以後,並把項目開起來以後,這個時候咱們就須要去註冊一個京東小程序,拿到對應的小程序的 AppId
,你能夠訪問京東小程序官網,根據步驟註冊小程序,並建立項目,而後取到項目的 AppId
,相似以下:
而後下載京東開發者工具,新建一個小程序項目,並輸入拿到的 AppId
:
並在京東開發者裏面點擊上面圓圈圈出的那個文件夾圖標,打開上面建立的 jd-mp
項目,不過請注意,咱們須要選中項目裏面編譯好的 dist
目錄:
這個時候,你的項目運行着,打開以後,你會在京東小程序開發者工具裏面看到以下效果:
固然上面這個指示的效果是我最終寫好的項目,你初次打開應該能夠看到一個 Hello World
🥳🥳🥳
一切準備就緒,能夠開始編寫咱們的京東小程序了!
Taro 小程序 2.x.x
暫時支持 React 來寫小程序,而 Taro 3.x.x
容許 React,Vue 和 Nerve 來寫,以後咱們圖雀社區會出 Taro 3.x.x
的教程,讓 Vue 的讀者也可使用 Taro 來寫小程序。
既然如今只能用 React,那麼就讓咱們新潮一點,使用 React Hooks 來簡化組件編寫,打開 src/pages/index/index.jsx
,將類組件重構成函數式組件,並添加一點發帖相關的內容:
import Taro from "@tarojs/taro"; import { View, Button, Textarea } from "@tarojs/components"; import "./index.scss"; export default function Index() { return ( <View className="index"> <Textarea placeholder="撰寫優質教程..." className="post-input" autoHeight /> <Button className="post-button">發表</Button> </View> ); } Index.config = { navigationBarTitleText: "首頁" };
能夠看到咱們將類組件改爲了函數式組件,並從 @tarojs/components
裏面導入並添加了兩個組件 Textarea
和 Button
,用於帖子表單的內容輸入和發表。
接着,咱們將以前的類屬性 config
移動到 Index.config
上面來定義,這個 config
只在頁面級組件裏面存在,用於定義頁面的一些屬性,好比這個的 navigationBarTitleText
就是此頁面的標題,在小程序裏面表明頂部的標題:
當咱們添加了上面兩個組件以後,組件的原生樣式開起來比較普通,爲了讓咱們的小程序更加專業一點,咱們給其加點樣式,其實使用 Taro 開發京東小程序時,寫樣式和咱們平時開發 Web 應用差很少,這裏咱們使用了 SCSS 來寫樣式,在組件裏面定義了對應的類名並導入了 CSS 文件,以後再 CSS 文件裏面寫樣式。
打開 src/pages/index/index.scss
,在其中添加對應的樣式文件以下:
.index { display: flex; flex-direction: column; align-items: center; } .post-input { margin-top: 24px; background: #fff; width: 80%; min-height: 80px; padding: 16px 30px; border: 1px solid #eee; font-size: 14px; } .post-button { margin-top: 24px; width: calc(80% + 60px); border-radius: 0; background-color: #00bc87; color: white; }
當添加了樣式以後,咱們的應用變成了以下樣子:
怎麼樣,是否是變得有點專業了呢?🤓
在編寫了第一個組件以後,咱們嘗試來處理咱們帖子的內容輸入,這個時候就涉及到事件處理了,咱們須要將以前在 src/pages/index/index.jsx
裏面定義的 TextArea
作成 「受控組件」,咱們使用 React Hooks 提供的 useState
來作到這一點。
打開 src/pages/index/index.jsx
,對其中的內容做出對應的修改以下:
import Taro, { useState } from "@tarojs/taro"; import { View, Button, Textarea } from "@tarojs/components"; import "./index.scss"; export default function Index() { const [post, setPost] = useState(""); function handleChange(e) { setPost(e.target.value); } return ( <View className="index"> <Textarea placeholder="撰寫優質教程..." className="post-input" value={post} onInput={handleChange} autoHeight /> <Button className="post-button">發表</Button> </View> ); } Index.config = { navigationBarTitleText: "首頁" };
能夠看到,上面咱們導入了 useState
鉤子,而後調用生成了一個 post
和 setPost
,接着咱們定義了一個 handleChange
函數來處理 Textarea
的 onInput
事件,接收用戶輸入來設置 post
值,並經過將 post
設置回 Textarea
的 value
來達到 「受控組件」 的目的。
當咱們的內容多起來以後,在一個組件裏面放太多內容會致使邏輯不清晰,因此咱們嘗試新建組件來抽出屬於它的一部分邏輯。接下來咱們立刻要處理帖子發表邏輯,而且還要展現發表以後的效果,因此咱們須要額外新建一個組件來展現帖子邏輯。
在 src
目錄先新建 components
文件夾,而後在裏面新建 PostCard
文件夾,接着在這個文件夾裏面建一個 index.jsx
文件,用於放置組件邏輯和 UI,咱們在這裏組件裏面編寫以下邏輯:
import Taro from "@tarojs/taro"; import { View, Text, Image } from "@tarojs/components"; import "./styles.scss"; export default function PostCard(props) { const { post } = props; return ( <View className="post"> <Text className="post-name">{post}</Text> </View> ); }
能夠看到咱們建立了一個 PostCard
函數式組件,而後渲染了其父組件傳下來的參數 post
,而且導入了一個 styles.scss
文件,咱們將立刻來建立它。
在 src/components/PostCard
文件夾下建立一個 styles.scss
,並編寫以下內容:
.post { width: calc(80% + 60px); margin: 0 auto; padding: 32px 0; border-bottom: 1px solid #eee; } .post-name { font-size: 20px; font-weight: 600; width: 100%; }
當編寫了渲染帖子的組件以後,咱們回到 src/pages/index/index.jsx
組件,來導入咱們寫好的 PostCard
組件,並同時處理帖子發表邏輯:
import Taro, { useState } from "@tarojs/taro"; import { View, Button, Textarea } from "@tarojs/components"; import PostCard from "../../components/PostCard"; import "./index.scss"; export default function Index() { const [post, setPost] = useState(""); const [postList, setPostList] = useState([]); function handleChange(e) { setPost(e.target.value); } function handleSubmit() { console.log("hello world", post); if (!post) { Taro.showToast({ title: "內容不能爲空", icon: "none" }); } else { Taro.showToast({ title: "發表成功", icon: "success" }); setPost(""); setPostList(postList.concat(post)); } } return ( <View className="index"> <Textarea placeholder="撰寫優質教程..." className="post-input" value={post} onInput={handleChange} autoHeight /> <Button className="post-button" onClick={handleSubmit}> 發表 </Button> <View className="post-box"> {postList.map(postItem => ( <PostCard post={postItem} /> ))} </View> </View> ); } Index.config = { navigationBarTitleText: "首頁" };
能夠看到上面咱們使用 useState
鉤子建立了一個新的狀態 postList
,接着咱們在 Button
上定義了一個 onClick
的處理函數 handleSubmit
,在這個函數裏面,咱們判斷輸入的 post
是否爲空,若是爲空提示用戶不能夠發佈,若是有內容,則提示用戶新帖子發佈成功,並將 post
添加到 postList
中,以及置空 post
內容,等待下次輸入。
注意到這裏咱們使用 Taro.showToast
API 來提示用戶,Taro 還有不少方便的 API,好比彈出模態框等,能夠參考文檔。
提示這裏額外的
console
語句能夠忽略,屬於開發時的調試語句。
最後,咱們加一點樣式來讓咱們的界面更加專業,打開 src/pages/index/index.scss
,修改內容以下:
.index { display: flex; flex-direction: column; align-items: center; } .post-input { margin-top: 24px; background: #fff; width: 80%; min-height: 80px; padding: 16px 30px; border: 1px solid #eee; font-size: 14px; } .post-button { margin-top: 24px; width: calc(80% + 60px); border-radius: 0; background-color: #00bc87; color: white; } .post-box { width: 100%; margin-top: 24px; }
大功告成!咱們如今能夠發表帖子並展現效果了,這個時候測試你的京東小程序,應該能夠看到以下效果:
咱們成功的處理了組件的組合,而且在發表帖子的時候使用 Taro 的 API 給與了用戶 UI 反饋。
經過上面的步驟,咱們能夠展現帖子列表,可是咱們都知道,帖子的內容可能很長,因此咱們須要額外的頁面來展現帖子詳情,因此咱們接下來將新建頁面並使用 Taro 提供的 API 進行多頁面的跳轉。
咱們在 src/pages
文件夾下建一個 post
文件夾,並在裏面建一個 post.jsx
文件,並編寫對應的內容以下:
import Taro, { useRouter } from "@tarojs/taro"; import { View, Text } from "@tarojs/components"; import "./post.scss"; export default function Post() { const { params } = useRouter(); const { post = "" } = params; return ( <View className="post"> <Text className="post-name">{post}</Text> </View> ); } Post.config = { navigationBarTitleText: "帖子頁" };
能夠看到上面咱們建立了一個 Post
函數式組件,而後增長了 config
配置,在標題改成 「帖子頁」,接着咱們使用 Taro 提供的 useRouter
鉤子來獲取路由傳遞過來的參數,取到參數裏面的 post
並渲染。
注意通常狀況下,咱們是經過路由傳遞
postId
,而後在帖子詳情裏面發起 HTTP 請求獲取帖子詳情,這裏爲了演示京東小程序的能力,因此簡化了寫法。
當建立了新頁面以後,咱們還要告訴應用咱們建立的這個頁面,也就是在應用註冊這個頁面,打開 src/app.jsx
,在對應 App
組件的 config.pages
屬性裏面添加剛剛建立的帖子詳情頁的路徑以下:
import Taro, { Component } from "@tarojs/taro"; import Index from "./pages/index"; import "./app.scss"; // 若是須要在 h5 環境中開啓 React Devtools // 取消如下注釋: // if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5') { // require('nerv-devtools') // } class App extends Component { componentDidMount() {} componentDidShow() {} componentDidHide() {} componentDidCatchError() {} config = { pages: ["pages/index/index", "pages/post/post"], window: { backgroundTextStyle: "light", navigationBarBackgroundColor: "#fff", navigationBarTitleText: "WeChat", navigationBarTextStyle: "black" } }; // 在 App 類中的 render() 函數沒有實際做用 // 請勿修改此函數 render() { return <Index />; } } Taro.render(<App />, document.getElementById("app"));
建立並註冊了頁面以後,咱們就能夠在 src/components/PostCard/index.jsx
組件裏面處理點擊帖子列表單個帖子的路由跳轉了:
import Taro from "@tarojs/taro"; import { View, Text } from "@tarojs/components"; import "./styles.scss"; export default function PostCard(props) { const { post } = props; function handleClick() { Taro.navigateTo({ url: `/pages/post/post?post=${post}` }); } return ( <View className="post" onClick={handleClick}> <Text className="post-name">{post}</Text> </View> ); }
能夠看到,咱們新增了 onClick
事件的處理方法 handleClick
,並調用 Taro 提供的 navigateTo
API 進行頁面之間的跳轉,更多頁面導航的 API 能夠參考文檔。
如今你能夠在添加帖子以後,點擊單個帖子,你會發現頁面發生跳轉到帖子詳情頁,並展現了帖子的內容:
處理了多頁面的跳轉,一個小程序還存在一些 TarBar 的需求,即底部有幾個按鈕進行多種類型的頁面跳轉,咱們也來發掘一下在京東小程序裏面如何添加 TabBar。
咱們首先來創建 TabBar 須要切換的另一個頁面,通常邏輯裏面是 「個人」 頁面,在 src/pages
目錄下新建 mine
文件夾,而後在裏面建立 mine.jsx
文件,編寫對應的內容以下:
import Taro, { useRouter } from "@tarojs/taro"; import { View, Text, Image } from "@tarojs/components"; import "./mine.scss"; import avatar from "../../images/avatar.png"; export default function Mine() { return ( <View className="mine"> <Image src={avatar} className="mine-avatar" /> <View className="slogan"> <Text className="slogan-name"> 圖雀社區:予力內容創做,加速技術傳播 </Text> </View> </View> ); } Mine.config = { navigationBarTitleText: "個人" };
能夠看到是咱們熟悉的函數式組件,而且 config
咱們設置了 「個人」 的標題,而且還在組件中渲染了一張圖片和標語,圖片能夠在項目中獲取。1)Github 2)Gitee
接着咱們能夠建立對應的樣式文件,在 src/pages/mine/
下建立對應的 mine.scss
文件,並編寫以下的內容:
.mine { padding-top: 40px; display: flex; flex-direction: column; align-items: center; } .mine-avatar { width: 300px; height: 300px; border-radius: 50%; } .slogan { margin-top: 24px; } .slogan-name { font-size: 32px; }
準備好了 TabBar 的第二個頁面以後,咱們在 src/app.jsx
裏面配置京東小程序的 TabBar:
import Taro, { Component } from "@tarojs/taro"; import Index from "./pages/index"; import "./app.scss"; // 若是須要在 h5 環境中開啓 React Devtools // 取消如下注釋: // if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5') { // require('nerv-devtools') // } class App extends Component { componentDidMount() {} componentDidShow() {} componentDidHide() {} componentDidCatchError() {} config = { pages: ["pages/index/index", "pages/post/post", "pages/mine/mine"], window: { backgroundTextStyle: "light", navigationBarBackgroundColor: "#fff", navigationBarTitleText: "WeChat", navigationBarTextStyle: "black" }, tabBar: { list: [ { pagePath: "pages/index/index", text: "首頁", iconPath: "./images/home.png", selectedIconPath: "./images/homeSelected.png" }, { pagePath: "pages/mine/mine", text: "個人", iconPath: "./images/mine.png", selectedIconPath: "./images/mineSelected.png" } ] } }; // 在 App 類中的 render() 函數沒有實際做用 // 請勿修改此函數 render() { return <Index />; } } Taro.render(<App />, document.getElementById("app"));
能夠看到,首先咱們在 config.pages
裏面聲明瞭 pages/mine/mine.jsx
的路徑,而後咱們給 config
額外增長了一個 tabBar
屬性,這個對象裏面是一個 list
屬性,而後在裏面加入了兩個 TabBar 頁面的配置信息:
pagePath
表明當前選中 TabBar 渲染的頁面路徑text
TabBar 的展現標題iconPath
TabBar 未選中時展現的圖標selectedIconPath
TabBar 選中時展現的圖標更多 TabBar 的配置信息能夠參考文檔。用到的圖標文件能夠在項目中獲取:1)Github 2)Gitee。
當配置好上面的內容以後咱們應該能夠在京東小程序開發者界面裏面看到以下效果:
前面全部的都是瞭解小程序本地編寫的一些內容,大多數應用還須要網絡請求獲取遠程數據來進行展現,固然咱們的京東小程序嚐鮮也不能漏掉這一點。
咱們打開 src/pages/index/index.jsx
文件,對其中的內容做出對應的修改以下:
import Taro, { useState, useEffect } from "@tarojs/taro"; import { View, Button, Textarea } from "@tarojs/components"; import PostCard from "../../components/PostCard"; import "./index.scss"; export default function Index() { const [post, setPost] = useState(""); const [postList, setPostList] = useState([]); function handleChange(e) { setPost(e.target.value); } function handleSubmit() { console.log("hello world", post); if (!post) { Taro.showToast({ title: "內容不能爲空", icon: "none" }); } else { Taro.showToast({ title: "發表成功", icon: "success" }); setPost(""); setPostList(postList.concat(post)); } } useEffect(() => { async function getPosts() { try { const res = await Taro.request({ url: "https://9ff4272f-ce60-4be6-9376-f9f462482edc.mock.pstmn.io/articles" }); const postList = res.data.map(item => item.name); setPostList(postList); } catch (err) { console.log("err", err); } } getPosts(); }, []); return ( <View className="index"> <Textarea placeholder="撰寫優質教程..." className="post-input" value={post} onInput={handleChange} autoHeight /> <Button className="post-button" onClick={handleSubmit}> 發表 </Button> <View className="post-box"> {postList.map(postItem => ( <PostCard post={postItem} /> ))} </View> </View> ); } Index.config = { navigationBarTitleText: "首頁" };
能夠看到,咱們導入了 useEffect
鉤子,並在其中定義了一個異步 getPosts
函數,用於獲取初始的帖子列表,接着咱們在這個函數中使用 Taro 的請求 API Taro.request
來發起網絡請求,並將請求到的數據進行處理更新到 postList
中,關於更多請求的 API 請參考 Taro 文檔。
當添加了上面內容以後,咱們能夠收穫以下的效果:
經過這篇教程快速上手京東小程序開發,咱們能夠發現得益於 Taro 的優秀跨端特性,即便是最新剛推出的京東小程序也能夠遊刃有餘的開發咱們須要的功能,這不由讓我想起了 Taro Next 發佈之際,Taro 團隊明確的初心和使命:「下降開發成本,提升開發體驗和開發效率」,不忘初心,牢記使命,這就是 Taro 團隊擁抱變化的方式!
想要學習更多精彩的實戰技術教程?來 圖雀社區逛逛吧。