亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

Router入門(mén)0x201: 從 URL 到 SPA

honmaple / 2986人閱讀

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

0x000 概述

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

0x001 URL的概念

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

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

打開(kāi)瀏覽器,訪(fǎng)問(wèn)segmentfault的主頁(yè),此時(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

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

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

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

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

協(xié)議類(lèi)型:[//服務(wù)器地址[:端口號(hào)]][/資源層級(jí)UNIX文件路徑]文件名[?查詢(xún)][#片段ID]

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

協(xié)議類(lèi)型:[//[訪(fǎng)問(wèn)資源需要的憑證信息@]服務(wù)器地址[:端口號(hào)]][/資源層級(jí)UNIX文件路徑]文件名[?查詢(xún)][#片段ID]

0x002 spa是什么

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

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

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

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

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

0x005 路由出現(xiàn)

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

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

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

hash:a.com/index.html#detail/1,訪(fǎng)問(wèn) id 為1的文章詳情頁(yè)

url:a.com/index/detail/1,訪(fǎng)問(wèn) id 為1的文章詳情頁(yè)

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

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

架構(gòu):

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

渲染器,將組件渲染到頁(yè)面上。

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

項(xiàng)目初始化:

整個(gè)項(xiàng)目起始沒(méi)有啥特別的,只是支持了es6而已,而整個(gè)項(xiàng)目我們也將會(huì)用es6來(lái)實(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字符串,也就是說(shuō),渲染器的本質(zhì)就是將dom字符串掛載和卸載。

core/LeactDom.js

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

export default LeactDom

測(cè)試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

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

    // dom 掛載上去以后 執(zhí)行該方法, 可以在這個(gè)方法上執(zhí)行 dom 查詢(xún)和事件綁定
    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

查看效果

框架完成開(kāi)始編寫(xiě)服務(wù)

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

const articles = [
    {
        id: 1,
        title: "Redux入門(mén)0x101: 簡(jiǎn)介及`redux`簡(jiǎn)單實(shí)現(xiàn)",
        summary: "簡(jiǎn)介及`redux`簡(jiǎn)單實(shí)現(xiàn)",
        detail: "詳情1"
    },
    {
        id: 2,
        title: "Redux入門(mén)0x102: redux 栗子之 counter",
        summary: "redux 栗子之 counter",
        detail: "詳情2"
    },
    {
        id: 3,
        title: "Redux入門(mén)0x103: 拆分多個(gè) reducer",
        summary: "拆分多個(gè) reducer",
        detail: "詳情3"
    },
    {
        id: 4,
        title: "Redux入門(mén)0x104: Action Creators",
        summary: "Action Creators",
        detail: "詳情4"
    },
    {
        id: 5,
        title: "Redux入門(mén)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

開(kāi)始編寫(xiě)自定義組件

文章列表組件

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

hash

url

將在下一張講述如何解決

0x008 資源

源碼

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/108512.html

相關(guān)文章

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

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

    miya 評(píng)論0 收藏0
  • Router入門(mén)0x202: 自己實(shí)現(xiàn) Router 頁(yè)面調(diào)度和特定頁(yè)面訪(fǎng)問(wèn)

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

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

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

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

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

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

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

    frontoldman 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<