成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Router入門0x201: 從 URL 到 SPA

honmaple / 2917人閱讀

摘要:的全稱是統(tǒng)一資源定位符英文,可以這么說,是一種標(biāo)準(zhǔn),而網(wǎng)址則是符合標(biāo)準(zhǔn)的一種實(shí)現(xiàn)而已。渲染器,將組件渲染到頁面上。

0x000 概述

從這一章開始就進(jìn)入路由章節(jié)了,并不直接從如何使用react-route來講,而是從路由的概念和實(shí)現(xiàn)來講,達(dá)到知道路由的本質(zhì),而不是只知道如何使用react-route庫的目的,畢竟react-route只是一個(gè)庫,是路由的一個(gè)實(shí)現(xiàn)而已,而不是路由本身。

0x001 URL的概念

很多人對url的理解就是網(wǎng)址,我們在瀏覽器地址欄輸入網(wǎng)址,便可以訪問到特定網(wǎng)頁,但其實(shí)url的含義遠(yuǎn)遠(yuǎn)不止是網(wǎng)址。url的全稱是統(tǒng)一資源定位符(英文:Uniform Resource Locator),可以這么說,url是一種標(biāo)準(zhǔn),而網(wǎng)址則是符合url標(biāo)準(zhǔn)的一種實(shí)現(xiàn)而已。

讓我們做幾個(gè)實(shí)驗(yàn):

打開瀏覽器,訪問segmentfault的主頁,此時(shí)地址欄顯示的是:

https://segmentfault.com

桌面新建from-url-to-spa.txt文件,輸入內(nèi)容from url to spa,并拖拽到瀏覽器,此時(shí)瀏覽器顯示的是

file:///Users/FollowWinter/Desktop/from-url-to-spa.txt

打開一個(gè)github項(xiàng)目,并選擇ssh訪問,我們可以得到以下地址:

[email protected]:followWinter/flex-layout.git

說明:其中,1訪問了一個(gè)網(wǎng)頁,2訪問了一個(gè)本地文件,3訪問了一個(gè)開源項(xiàng)目,從以上可以看出,url有多種用途各異的實(shí)現(xiàn),但是我們可以這么歸納,網(wǎng)絡(luò)上(包括本地和遠(yuǎn)程)所有的的東西都看作資源,我們可以通過一種符合某種標(biāo)準(zhǔn)的格式來訪問這種資源,從而忽略設(shè)備類型(服務(wù)器、路由器、硬盤......)、網(wǎng)絡(luò)類型(遠(yuǎn)程、本地......)、資源類型(文本、圖片、音樂、電影......),而這種標(biāo)準(zhǔn)就是url,也就是我對統(tǒng)一資源定位符的理解。

統(tǒng)一資源定位符的標(biāo)準(zhǔn)格式如下:

協(xié)議類型:[//服務(wù)器地址[:端口號]][/資源層級UNIX文件路徑]文件名[?查詢][#片段ID]

統(tǒng)一資源定位符的完整格式如下:

協(xié)議類型:[//[訪問資源需要的憑證信息@]服務(wù)器地址[:端口號]][/資源層級UNIX文件路徑]文件名[?查詢][#片段ID]

0x002 spa是什么

SPA全稱是single page web application,也就是只有一個(gè)頁面的web應(yīng)用程序,我們訪問一個(gè)網(wǎng)頁,能夠在這個(gè)網(wǎng)頁上完成所有的業(yè)務(wù)操作,我們就可以稱之為SPA,是和框架無關(guān)、技術(shù)無關(guān)的一個(gè)概念。并不是說用angular、vue、react實(shí)現(xiàn)的web應(yīng)用才叫SPA,因?yàn)檫@些框架也可以在多頁應(yīng)用中使用。

0x003 如何實(shí)現(xiàn)spa

只要在一個(gè)頁面完成所有業(yè)務(wù)操作,就可以稱之為SPA了,所以實(shí)現(xiàn)所謂的SPA也很簡單,就是將原本多頁的步驟轉(zhuǎn)化為一個(gè)頁面就行了。

0x004 SPA和路由有啥關(guān)系啊

回答:沒有關(guān)系。SPA不一定要使用路由,不使用也沒有關(guān)系,但是隨著單頁應(yīng)用了擴(kuò)大,將所有的邏輯都卸載一個(gè)頁面上,會(huì)導(dǎo)致邏輯爆炸,維護(hù)痛苦,所以在邏輯上又分為多個(gè)頁面,達(dá)到好維護(hù)的效果。

0x005 路由出現(xiàn)

一開始是沒有路由的,但是做的應(yīng)用多了,便有了路由。對于路由的需求有兩個(gè):

維護(hù)上的需求,過多的邏輯寫在一個(gè)頁面上,容易混亂,所以用路由分離多帶帶邏輯和頁面。

狀態(tài)保存的需求,比如一個(gè)SPA,我們有文章和文章詳情頁,有一天我們需要分享一個(gè)文章,希望可以通過一個(gè)鏈接直接訪問到這篇文章。但是單頁應(yīng)用是無狀態(tài)的,而網(wǎng)址又是唯一的,比如a.com/index.html,無法做到直接訪問詳情頁,所以就出現(xiàn)了一些方案:

hash:a.com/index.html#detail/1,訪問 id 為1的文章詳情頁

url:a.com/index/detail/1,訪問 id 為1的文章詳情頁

這樣我們就可以分享一篇文章給其他用戶了,方案1實(shí)現(xiàn)比較簡單,但是路由丑陋并且占用了 hash 符,頁面中就不能亂用 hash 符了。方案2好但是需要后端配合,實(shí)現(xiàn)也很簡單,不管這個(gè) url 是什么,都返回單頁應(yīng)用的 html 就好了。

0x006 實(shí)現(xiàn)簡單的SPA

架構(gòu):

組件,每個(gè)組件都是獨(dú)立的,可以渲染出自己的dom,并且可以綁定事件,擁有生命周期。

渲染器,將組件渲染到頁面上。

服務(wù),做數(shù)據(jù)管理等一些邏輯服務(wù)。

項(xiàng)目初始化:

整個(gè)項(xiàng)目起始沒有啥特別的,只是支持了es6而已,而整個(gè)項(xiàng)目我們也將會(huì)用es6來實(shí)現(xiàn)

初始化項(xiàng)目及其目錄

+ 0x021-spa
    + src 
        + core
        + page
        + services
        - index.html
        - index.js
    - .babelrc
    - package.json
    - webpack.config.js

index.html:




    React Study
    
    


.babelrc

{
  "presets": [
    "env",
    "stage-3"

  ]
}

package.json

{
  "name": "0x021-spa",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "webpack-dev-server --color --process "
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-3": "^6.24.1",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.16.5",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.5"
  }
 
}

webpack.config.js:

const path = require("path")
   var HtmlWebpackPlugin = require("html-webpack-plugin");
   
   module.exports = {
   entry: path.resolve(__dirname, "src/index.js"),
   mode: "development",
   output: {
       path: path.resolve(__dirname, "dist"),
       filename: "bundle.js"
   },
   devServer: {
       open: true
   },
   module: {
       rules: [
           {
               test: /.js$/,
               loader: "babel-loader"
           },
   
       ]
   },
   plugins: [
       new HtmlWebpackPlugin({
           template: path.resolve(__dirname, "src/index.html")
       })
   ]
   }

渲染器實(shí)現(xiàn)

渲染器的作用起始就是渲染組件而已,而每個(gè)組件都有一個(gè)render方法,該方法返回一個(gè)dom字符串,也就是說,渲染器的本質(zhì)就是將dom字符串掛載和卸載。

core/LeactDom.js

class LeactDom {
    static render(child, parent) {
        parent.innerHTML=child
    }
}

export default LeactDom

測試index.js

import LeactDom from "./core/LeactDom";
import LeactDom from "./core/LeactDom";

LeactDom.render(`

這是一個(gè)p

`, document.getElementById("app")) document.getElementById("p").addEventListener("click", () => { LeactDom.render("這是一個(gè)span", document.getElementById("app")) })

查看瀏覽器

 如圖,我們已經(jīng)實(shí)現(xiàn)了切換了,只需要將之封裝為組件就行了
![圖片描述][1]    

組件

core/Component.js

// 這是組件根類, 所有的組件都繼承這個(gè)根
class Component {
    // 返回 dom 字符串
   render() {
        return ""
    }

    // dom 掛載上去以后 執(zhí)行該方法, 可以在這個(gè)方法上執(zhí)行 dom 查詢和事件綁定
    componentDidMount() {

    }

}

export default Component

自定義組件page/Hello.js

import Component from "../core/Component";

class Hello extends Component {

    render() {
        return `

hello

` } componentDidMount() { document.getElementById("hello").addEventListener("click", () => { alert("hello") }) } } export default Hello

引入Hello組件

import LeactDom from "./core/LeactDom";
import Hello from "./page/Hello";

LeactDom.render(Hello,document.getElementById("app"))

修改LeactDom

class LeactDom {

    static render(child, parent, props={}) {
        if (typeof child === "function") {
            let comp = new child()
            comp.props = props
            parent.innerHTML = comp.render()
            comp.componentDidMount()
        } else {
            parent.innerHTML = child
        }
    }
}

export default LeactDom

查看效果

框架完成開始編寫服務(wù)

文章獲取服務(wù)service/AticleService.js

const articles = [
    {
        id: 1,
        title: "Redux入門0x101: 簡介及`redux`簡單實(shí)現(xiàn)",
        summary: "簡介及`redux`簡單實(shí)現(xiàn)",
        detail: "詳情1"
    },
    {
        id: 2,
        title: "Redux入門0x102: redux 栗子之 counter",
        summary: "redux 栗子之 counter",
        detail: "詳情2"
    },
    {
        id: 3,
        title: "Redux入門0x103: 拆分多個(gè) reducer",
        summary: "拆分多個(gè) reducer",
        detail: "詳情3"
    },
    {
        id: 4,
        title: "Redux入門0x104: Action Creators",
        summary: "Action Creators",
        detail: "詳情4"
    },
    {
        id: 5,
        title: "Redux入門0x105: redux 中間件",
        summary: "redux 中間件",
        detail: "詳情5"
    },

]

class ArticleService {

    static getAll() {
        return articles
    }

    static getById(id) {
        return articles.find((article) => {
            return id == article.id
        })
    }
}

export default ArticleService

開始編寫自定義組件

文章列表組件

import ArticleService from "../services/ArticleService";
import DetailPage from "./DetailPage";
import LeactDom from "../core/LeactDom";

class ArticlePage {
    render() {
        let articlesListString = ArticleService.getAll()
            .map(article => {
                return `
${article.title}

${article.summary}


` }) .reduce((article1, article2) => { return article1 + article2 }) let articleListContrinerString = `

文章列表


${articlesListString}
` return articleListContrinerString } componentDidMount() { let articles = document.getElementsByClassName("article") ;[].forEach.call(articles, article => { article.addEventListener("click", () => { LeactDom.render(new DetailPage({articleId: article.getAttribute("data-id")}), document.getElementById("app")) }) } ) } } export default ArticlePage

文章詳情組件

import ArticleService from "../services/ArticleService";
import Component from "../core/Component";
import LeactDom from "../core/LeactDom";
import ArticlePage from "./ArticlePage";

class DetailPage extends Component {
    constructor(props) {
        super()
        this.article = ArticleService.getById(props.articleId)
    }

    render() {
        const {title, summary, detail} = this.article
        return `

${title}

${summary}


${detail}

` } componentDidMount() { document.getElementById("back").addEventListener("click", () => { LeactDom.render(new ArticlePage(), document.getElementById("app")) }) } } export default DetailPage

加載組件index.js

import LeactDom from "./core/LeactDom";
import ArticlePage from "./page/ArticlePage";

LeactDom.render(new ArticlePage(),document.getElementById("app"))

8 查看最終效果

0x007 總結(jié)

這里要做的只是一個(gè)案例,而不是寫一個(gè)完整的框架,所以在很多地方并沒有完善,只是為了驗(yàn)證實(shí)現(xiàn)SPA的方式,而結(jié)果也確實(shí)驗(yàn)證了。也將一些問題暴露出來了,其他的問題我們不關(guān)心,我們只關(guān)心我們之前提出的問題,只有一個(gè)網(wǎng)址,如何將某個(gè)頁面分享出去,很明顯,做成SPA之后,無法將文章詳情頁面分享給他人。解決 方法也已經(jīng)給出來了:

hash

url

將在下一張講述如何解決

0x008 資源

源碼

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108512.html

相關(guān)文章

  • Vue.js 服務(wù)端渲染業(yè)務(wù)入門實(shí)踐

    摘要:說起,其實(shí)早在出現(xiàn)之前,網(wǎng)頁就是在服務(wù)端渲染的。沒有涉及流式渲染組件緩存對的服務(wù)端渲染有更深一步的認(rèn)識,實(shí)際在生產(chǎn)環(huán)境中的應(yīng)用可能還需要考慮很多因素。選擇的服務(wù)端渲染方案,是情理之中的選擇,不是對新技術(shù)的盲目追捧,而是一切為了需要。 作者:威威(滬江前端開發(fā)工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處。 背景 最近, 產(chǎn)品同學(xué)一如往常笑嘻嘻的遞來需求文檔, 縱使內(nèi)心萬般拒絕, 身體倒是很誠實(shí)...

    miya 評論0 收藏0
  • Router入門0x202: 自己實(shí)現(xiàn) Router 頁面調(diào)度和特定頁面訪問

    摘要:概述上一章講了如何實(shí)現(xiàn)組件頁面切換,這一章講如何解決上一章出現(xiàn)的問題以及如何優(yōu)雅的實(shí)現(xiàn)頁面切換。在中監(jiān)聽了事件,這樣就可以在變化的時(shí)候,需要路由配置并調(diào)用。 0x000 概述 上一章講了SPA如何實(shí)現(xiàn)組件/頁面切換,這一章講如何解決上一章出現(xiàn)的問題以及如何優(yōu)雅的實(shí)現(xiàn)頁面切換。 0x001 問題分析 回顧一下上一章講的頁面切換,我們通過LeactDom.render(new Articl...

    dance 評論0 收藏0
  • 頭開始學(xué)習(xí)vue-router

    摘要:路由模塊的本質(zhì)就是建立起和頁面之間的映射關(guān)系。這時(shí)候我們可以直接利用傳值了使用來匹配路由,然后通過來傳遞參數(shù)跳轉(zhuǎn)對應(yīng)路由配置于是我們可以獲取參數(shù)六配置子路由二級路由實(shí)際生活中的應(yīng)用界面,通常由多層嵌套的組件組合而成。 一、前言 要學(xué)習(xí)vue-router就要先知道這里的路由是什么?為什么我們不能像原來一樣直接用標(biāo)簽編寫鏈接哪?vue-router如何使用?常見路由操作有哪些?等等這些問...

    tommego 評論0 收藏0
  • 頭開始學(xué)習(xí)vue-router

    摘要:路由模塊的本質(zhì)就是建立起和頁面之間的映射關(guān)系。這時(shí)候我們可以直接利用傳值了使用來匹配路由,然后通過來傳遞參數(shù)跳轉(zhuǎn)對應(yīng)路由配置于是我們可以獲取參數(shù)六配置子路由二級路由實(shí)際生活中的應(yīng)用界面,通常由多層嵌套的組件組合而成。 一、前言 要學(xué)習(xí)vue-router就要先知道這里的路由是什么?為什么我們不能像原來一樣直接用標(biāo)簽編寫鏈接哪?vue-router如何使用?常見路由操作有哪些?等等這些問...

    jhhfft 評論0 收藏0
  • 頭開始學(xué)習(xí)vue-router

    摘要:路由模塊的本質(zhì)就是建立起和頁面之間的映射關(guān)系。這時(shí)候我們可以直接利用傳值了使用來匹配路由,然后通過來傳遞參數(shù)跳轉(zhuǎn)對應(yīng)路由配置于是我們可以獲取參數(shù)六配置子路由二級路由實(shí)際生活中的應(yīng)用界面,通常由多層嵌套的組件組合而成。 一、前言 要學(xué)習(xí)vue-router就要先知道這里的路由是什么?為什么我們不能像原來一樣直接用標(biāo)簽編寫鏈接哪?vue-router如何使用?常見路由操作有哪些?等等這些問...

    frontoldman 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<