国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Router入門0x201: 從 URL 到 SPA

honmaple / 2896人閱讀

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

0x000 概述

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

0x001 URL的概念

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

讓我們做幾個實驗:

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

https://segmentfault.com

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

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

打開一個github項目,并選擇ssh訪問,我們可以得到以下地址:

git@github.com:followWinter/flex-layout.git

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

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

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

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

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

0x002 spa是什么

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

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

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

0x004 SPA和路由有啥關系啊

回答:沒有關系。SPA不一定要使用路由,不使用也沒有關系,但是隨著單頁應用了擴大,將所有的邏輯都卸載一個頁面上,會導致邏輯爆炸,維護痛苦,所以在邏輯上又分為多個頁面,達到好維護的效果。

0x005 路由出現(xiàn)

一開始是沒有路由的,但是做的應用多了,便有了路由。對于路由的需求有兩個:

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

狀態(tài)保存的需求,比如一個SPA,我們有文章和文章詳情頁,有一天我們需要分享一個文章,希望可以通過一個鏈接直接訪問到這篇文章。但是單頁應用是無狀態(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實現(xiàn)比較簡單,但是路由丑陋并且占用了 hash 符,頁面中就不能亂用 hash 符了。方案2好但是需要后端配合,實現(xiàn)也很簡單,不管這個 url 是什么,都返回單頁應用的 html 就好了。

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

架構:

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

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

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

項目初始化:

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

初始化項目及其目錄

+ 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")
       })
   ]
   }

渲染器實現(xiàn)

渲染器的作用起始就是渲染組件而已,而每個組件都有一個render方法,該方法返回一個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(`

這是一個p

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

查看瀏覽器

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

組件

core/Component.js

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

    // dom 掛載上去以后 執(zhí)行該方法, 可以在這個方法上執(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

查看效果

框架完成開始編寫服務

文章獲取服務service/AticleService.js

const articles = [
    {
        id: 1,
        title: "Redux入門0x101: 簡介及`redux`簡單實現(xiàn)",
        summary: "簡介及`redux`簡單實現(xiàn)",
        detail: "詳情1"
    },
    {
        id: 2,
        title: "Redux入門0x102: redux 栗子之 counter",
        summary: "redux 栗子之 counter",
        detail: "詳情2"
    },
    {
        id: 3,
        title: "Redux入門0x103: 拆分多個 reducer",
        summary: "拆分多個 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 總結

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

hash

url

將在下一張講述如何解決

0x008 資源

源碼

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

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

相關文章

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

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

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

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

    dance 評論0 收藏0
  • 頭開始學習vue-router

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

    tommego 評論0 收藏0
  • 頭開始學習vue-router

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

    jhhfft 評論0 收藏0
  • 頭開始學習vue-router

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

    frontoldman 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<