整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          HTML-30年的故事

          HTML-30年的故事

          /韓作

          以前,我們曾經將HTML代碼作為資源填充到CGI應用程序中。前端開發是每個人都會做的事情。 — 90 年代的匿名程序員

          被稱為“HTML”的超文本標記語言將迎來 30 年的歷史。在 1992 年 6 月 發布其第一個版本后,它走過了很長的路,也取得了長足的進步。

          盡管在 1993 年發布,但HTML和萬維網卻經歷了相當長的時間才獲得一些關注。直到 1995 年末,萬維網才開始騰飛。

          那時候“上網”是一種痛苦的過程,需要相當長的時間和耐心來進行相關設置。

          建立網站也并不是一件容易的事情,如果想建立商業應用程序,仍然要在Web、法國的Minitel或德國的BTX之間做出選擇。

          90年代-建立網站

          90 年代中期,如果你想建立網站,第一個難題就是找人托管您的網站。注冊域名在當時是完全不敢想象的事情。

          當然如果你有自己的服務器那就另當別論了。

          話說回來,當時如果找到某人來托管你的網站,他們可能只會讓你通過FTP訪問一臺Unix 機器,該機器將存儲你的HTML和一些漂亮的GIF圖像以供需要它的任何人使用。

          相繼而出的HTML1.0、2.0 直到 3.2也都是很基本、很基礎的。

          JavaScript在1995年才問世,并花了一些時間被當時的兩種瀏覽器(主要是網景和ie瀏覽器)所采用。

          1994年推出的HTTPcookie也是如此。這造就了現在幾乎所有瀏覽器都會提示用戶必須接受的 cookie 消息的局面。

          話說,如果你想建立一個有意義的交互式網站,用戶不僅可以瀏覽,還可以與聊天等網站進行實際互動——你最終幾乎都會使用CGI(“通用網關界面”)或建立你自己的web服務器軟件。

          在過去,建立自己的web服務器并不罕見。然而,大多數人都偏向于使用CGI。

          CGI本質上做的是將HTTP請求轉發到應用程序,應用程序將返回頭信息和HTML代碼或它提供的任何內容。

          Perl、C和C++是為web服務器構建CGI應用程序的最常見的語言。但是它非常麻煩,基本上任何交互式操作都必須在服務器上完成。

          由于沒有cookie,會話處理和會話管理,大多是通過URL的路徑組件都會使用每個用戶或會話的唯一標識符來完成的。

          考慮到90年代中期計算機的性能,CPU時鐘速度在25到180Mhz之間,運行交互式web服務器是非常昂貴的。

          升陽公司的SPARCcpu及其系統也用于這一目的,并且在當時也并不便宜。

          繁榮的95、96年

          95 年和 96 年可以看成是互聯網的里程碑。

          從雅虎 GeoCities 等免費網絡托管商、eBay 等拍賣平臺和 Amazon.com 等在線商店開始,互聯網得到了蓬勃的發展。

          特別是像Microsoft Frontpage、來自Sierra的WWW Artist和其他許多類似軟件的軟件,讓構建自己的HTML頁面并用FTP上傳它們變得更容易。

          新的編程語言,如PHP,Internet Information Server 的 Microsoft Active Server Pages,使構建萬維網應用程序變得更容易。

          Cookie和JavaScript還允許添加更多的交互性,當然瀏覽器很快就被執行JavaScript代碼淹沒,崩潰也是常有的事。

          1995年發布Java小程序、1996年發布的宏媒體中流行的Flash播放器。

          同樣在1996年發布的還有層疊樣式表(CSS)。

          然而,當時建立網站仍然使用的是表格布局。所有的東西都被安置在大量的大表格和小表格中。

          互聯網更新并不是一件多難的事,所以遇到相當過時的網絡瀏覽器并不罕見。從95年到98年的瀏覽器戰爭,導致了跨瀏覽器支持這一個令人頭疼的問題,所以使用表格是最安全的方法。

          如果你想搭建自己獨特風格的網站,那你最終也還是會使用圖像、圖像映射和“裝在”表格中的圖像,你基本上還是整天都在擺弄表格。

          考慮到95-98年大多數連接的超慢速度,即56k或7千節每秒,加載圖像也需要很長時間。

          所以即便用一些很棒的動畫gif,每個也都需要2秒來加載。等待30秒鐘的網站出現也很常見。

          在當時,內容傳遞并不會增加用戶體驗,減少延遲才是。

          1997 到 2000 年

          在這段時間,來自舊金山的一家名為 Macromedia 的小型公司的軟件產品,包括 Dreamweaver、Fireworks 和 Flash,迅速成為許多專業網站管理員的首選解決方案。

          網站管理員成為了一種職業。隨著CSS、JavaScript、PHP和許多其他純粹專注于Web的編程語言的興起,構建網站成為了一項純粹的軟件開發或工程工作。

          然而,直到21世紀初,許多網站仍然是表格布局,經常出現像IE3.0這樣的瀏覽器也并不少見。

          多年的發展,網站變得越來越互動,媒體內容也越來越豐富。對于構建者和用戶來說,這意味著要擺弄諸如Flash、Java小程序或真正的播放器插件。對于用戶來說,這意味著必須永久地更新插件和安裝新的插件。

          遺憾的是,當時的下載速度仍然遠低于一個可接受的水平。

          第一個視頻和音樂流媒體服務出現在90 年代后期,可就論質量來說,盡管是每秒超過 1 兆比特的“寬帶”用戶也幾乎無法體驗任何東西。

          但至少他打開了一個新世界的大門。

          1998年的 WML——移動網絡的誕生和消亡

          無線應用協議 (WAP) 使用無線標記語言 (WML),可以在一組卡片中組織不同的頁面(稱為“卡片式布局”)。

          因為可以一次將多個頁面傳輸到客戶端,減少了傳輸的數據量,有點像今天的前端框架。鑒于移動網絡運營商的高定價,以及幾秒鐘內產生巨額賬單,WAP 和移動瀏覽器并沒有帶來多好的體驗。

          用戶并不喜歡它。

          隨后,WAP 和 WML 迅速消亡。

          盡管在技術上可圈可點,但它們所處的商業環境最終導致了它們的消亡。

          功能更強大的移動瀏覽器代替了WAP。

          2002 年—Windows XP、IE6和Firefox

          2002年互聯網領域最具代表性的事件就是 Internet Explorer 6 的 Firefox 和 Windows XP 的誕生。

          在 2000 年的互聯網泡沫之后,Internet 和 Web相繼到了發展成熟階段。在線商店、酒店和航班預訂網站等商業網絡服務開始萌芽。

          隨著 JavaScript、CSS 和 HTML 4.01 的成熟,Web 正在朝著被定義為“Web 2.0”的方向發展。瀏覽器也能夠呈現和操作相對復雜的用戶界面組件,如日歷、自動完成文本框、交互式表格、地圖等等。

          隨著谷歌地圖等應用程序的出現,現代“Web 2.0”展示了其部署的全面應用程序的能力,而這些應用程序以前僅能作為桌面應用程序。維基百科作為一個交互式百科全書的誕生,也標志著服務器群也有了足夠的數據庫、存儲和計算能力來運行大規模的交互式網站。

          一夜之間,JavaScript突然能夠操縱整個DOM,瀏覽器在后臺有了足夠的能力來呈現復雜的頁面,CSS讓應用程序的樣式也更加舒適。

          以前存在于桌面上的電子郵件應用程序已經基本上全部基于 了Web,并具有采用更具交互性的電子郵件客戶端設計,電子郵件服務也變成了免費的。

          隨著 HTML、CSS 和 JavaScript 的每一次改進,Web也變得更加接近桌面應用程序的功能。

          2008 年——移動網絡的重生

          移動網絡自從 90 年代中期誕生以來,一直存在兩個重大問題,阻礙了它的發展和普及。

          • 移動網絡運營商的高定價
          • 未針對小屏幕和胖手指優化的網站

          Apple與移動網絡運營商達成協議,Wi-Fi成為移動設備的主流。

          隨著這些事情的變化,越來越多的網站管理員和開發人員開始構建移動網站。在移動互聯網的早期,移動設備通常會被重定向到精簡的移動網站。

          那些保留WAP服務并慢慢過渡到新的移動網絡(比如CNN),通常都會在wap.xxxxx.com這樣的域名下。

          諾基亞無法做到的事情,最終被蘋果和谷歌掌握了:將移動網絡帶給大眾

          2012年,當CSS媒體查詢被引入后,“移動網站”開始能夠使網站能夠適應各種屏幕大小、設備和形式,最早的“移動網站”開始慢慢的消失了。移動瀏覽器變得更加強大,同時變得強大和先進的還有他們的底層設備。

          當然,包括 JavaScript。

          2020、2021、2022 年及以后

          2020 年初,網絡和網絡瀏覽器解決了過去幾十年的幾乎所有挑戰。

          瀏覽器現在可以流式傳輸視頻、處理圖像和視頻、適應任何類型的設備并在瀏覽器中運行基本上任何完整的應用程序。到目前為止,瀏覽器也可以運行已經移植到web匯編程序中的整個操作系統。

          HTML、CSS、JavaScript、WebAssembly 和大量原創API,是當今現代應用程序的主要組件。HTML也已經遠遠超越了Web 瀏覽器,同時它也成為桌面應用程序和移動應用程序的通用標準,具有 React Native、Electron 和許多其他實現等框架。

          瀏覽器也越來越多地集成到 ChromeOS、Android、iOS 和 Windows 等操作系統中。與此同時,越來越多的應用程序大量使用 Web 和 HTML 來顯示內容和提供服務。

          隨著軟件服務的興起,現代企業應用程序也正在迅速過渡到瀏覽器,從而減輕了用戶的安裝負擔和難搞的許可。

          挑戰仍然存在

          回望過去,瀏覽器測試至今依然是一件很痛苦事。

          盡管 Internet Explorer 已成為過去,但移動設備的多樣性、不同的外形尺寸以及對HTML5或Web API的不同支持仍然是一個挑戰。

          好在,現代開發環境還是可以很輕松跟上時代的。對于Chrome、Safari 和 Firefox,這些瀏覽器在桌面和移動設備上的差異并不像早期的 Internet Explorer 和 Netscape Navigator 那樣嚴重。

          當今的 Web 應用程序必須處理移動網絡、跨多個網絡漫游的設備以及由于網絡覆蓋范圍丟失而可能突然斷開的連接。因此,網絡的挑戰仍然以某種形式存在著。

          z-index 操作的引入也帶來了彈出窗口。居中的圖層阻止用戶訪問網站的實際內容。

          隨著 HTML、CSS 和 JavaScript 復雜性的增加,新的軟件開發人員也越來越難以進入 Web 開發世界并跟上Web應用程序標準的標準,例如 Lighthouse 測試等性能測試。

          而且,今天的一些網站很容易超過 5 兆字節甚至更多。過去的性能問題今天仍然沒有得到解決。

          回顧與展望

          W3C的web路線圖還有很多東西,W3C 繼續證明它有能力解決標準化方面非常復雜的挑戰。構建 Web 應用程序從未像現在這樣靈活和復雜。

          今天有些人傾向于區分前端和后端,而 Web 的歷史已經證明這是一種有缺陷的方法。過去,因為 HTML 經常在服務器端生成,而今天,過去駐留在服務器上的許多操作(如視頻和圖像編輯)卻在現在迅速地轉移到了瀏覽器端。

          使用像 React 這樣的框架,構建好的 Web 應用程序也從未如此簡單。你可以假設像 JSX、JavaScript 語法擴展這樣的 React 元素也會進入瀏覽器的標準。就像 Flash 一樣,許多其他被 W3C 標準取代的技術。

          “那些不能從歷史中吸取教訓的人注定要重蹈覆轍。”
          ——溫斯頓·丘吉爾爵士


          (如果你感興趣,可以關注我,查看以往的作品,希望能和大家共同成長)

          #互聯網#

          vue3.x越來越穩定及vite2.0的快速迭代推出,加上很多大廠相繼推出了vue3的UI組件庫,在2021年必然受到開發者的再一次熱捧。

          Vue3迭代更新頻繁,目前star高達20.2K+

          // 官網地址
          https://v3.vuejs.org/

          Vitejs目前的star達到15.7K+

          // 官網地址
          https://vitejs.dev/

          項目介紹

          vue3-webchat 基于vue3.x+vuex4+vue-router4+element-plus+v3layer+v3scroll等技術架構的仿微信PC端界面聊天實例。

          以上是仿制微信界面聊天效果,同樣也支持QQ皮膚。

          技術棧

          • 使用技術:vue3.0+vuex4+vue-router4
          • UI組件庫:element-plus(餓了么Vue3 pc端組件庫)
          • 彈窗組件:V3Layer(基于Vue3自定義桌面端彈窗)
          • 滾動條組件:V3Scroll(基于Vue3自定義虛擬美化滾動條)
          • iconfont圖標:阿里字體圖標庫

          Vue3.x自定義彈窗組件

          大家看到的所有彈窗功能,均是自己開發的vue3.0自定義彈窗V3Layer組件。

          前段時間有過一篇詳細的分享,這里就不作介紹了。感興趣的話可以去看看。

          vue3.0系列:Vue3自定義PC端彈窗組件V3Layer

          Vue3.x自定義美化滾動條組件

          為了使得項目效果一致,所有頁面的滾動條均是采用vue3.0自定義組件實現。

          v3scroll 一款輕量級的pc桌面端模擬滾動條組件。支持是否原生滾動條、自動隱藏、滾動條大小/層疊/顏色等功能。

          大家感興趣的話,可以去看看這篇分享。

          Vue3.0系列:vue3定制美化滾動條組件v3scroll

          vue.config.js項目配置

          /**
           * Vue3.0項目配置
           */
          
          const path=require('path')
          
          module.exports={
              // 基本路徑
              // publicPath: '/',
          
              // 輸出文件目錄
              // outputDir: 'dist',
          
              // assetsDir: '',
          
              // 環境配置
              devServer: {
                  // host: 'localhost',
                  // port: 8080,
                  // 是否開啟https
                  https: false,
                  // 編譯完是否打開網頁
                  open: false,
                  
                  // 代理配置
                  // proxy: {
                  //     '^/api': {
                  //         target: '<url>',
                  //         ws: true,
                  //         changeOrigin: true
                  //     },
                  //     '^/foo': {
                  //         target: '<other_url>'
                  //     }
                  // }
              },
          
              // webpack配置
              chainWebpack: config=> {
                  // 配置路徑別名
                  config.resolve.alias
                      .set('@', path.join(__dirname, 'src'))
                      .set('@assets', path.join(__dirname, 'src/assets'))
                      .set('@components', path.join(__dirname, 'src/components'))
                      .set('@layouts', path.join(__dirname, 'src/layouts'))
                      .set('@views', path.join(__dirname, 'src/views'))
              }
          }

          Vue3引入/注冊公共組件

          // 引入餓了么ElementPlus組件庫
          import ElementPlus from 'element-plus'
          import 'element-plus/lib/theme-chalk/index.css'
          
          // 引入vue3彈窗組件v3layer
          import V3Layer from '../components/v3layer'
          
          // 引入vue3滾動條組件v3scroll
          import V3Scroll from '@components/v3scroll'
          
          // 引入公共組件
          import WinBar from '../layouts/winbar.vue'
          import SideBar from '../layouts/sidebar'
          import Middle from '../layouts/middle'
          
          import Utils from './utils'
          
          const Plugins=app=> {
              app.use(ElementPlus)
              app.use(V3Layer)
              app.use(V3Scroll)
          
              // 注冊公共組件
              app.component('WinBar', WinBar)
              app.component('SideBar', SideBar)
              app.component('Middle', Middle)
          
              app.provide('utils', Utils)
          }
          
          export default Plugins

          項目中主面板毛玻璃效果(虛化背景)

          <!-- //虛化背景(毛玻璃) -->
          <div class="vui__bgblur">
              <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" class="blur-svg" viewBox="0 0 1920 875" preserveAspectRatio="none">
              <filter id="blur_mkvvpnf"><feGaussianBlur in="SourceGraphic" stdDeviation="50"></feGaussianBlur></filter>
              <image :xlink:href="store.state.skin" x="0" y="0" width="100%" height="100%" externalResourcesRequired="true" xmlns:xlink="http://www.w3.org/1999/xlink" style="filter:url(#blur_mkvvpnf)" preserveAspectRatio="none"></image>
              </svg>
              <div class="blur-cover"></div>
          </div>

          Vue3攔截登錄狀態

          vue3.0中使用全局路由鉤子攔截登錄狀態。

          router.beforeEach((to, from, next)=> {
              const token=store.state.token
          
              // 判斷當前路由地址是否需要登錄權限
              if(to.meta.requireAuth) {
                  if(token) {
                      next()
                  }else {
                      // 未登錄授權
                      V3Layer({
                          content: '還未登錄授權!', position: 'top', layerStyle: 'background:#fa5151', time: 2,
                          onEnd: ()=> {
                              next({ path: '/login' })
                          }
                      })
                  }
              }else {
                  next()
              }
          })

          Vue3.x聊天模塊

          如上圖:聊天編輯框部分支持文字+emoj表情、在光標處插入表情、多行文本內容。

          編輯器抽離了一個公共的Editor.vue組件。

          <template>
              <div
                  ref="editorRef"
                  class="editor"
                  contentEditable="true"
                  v-html="editorText"
                  @click="handleClick"
                  @input="handleInput"
                  @focus="handleFocus"
                  @blur="handleBlur"
                  style="user-select:text;-webkit-user-select:text;">
              </div>
          </template>

          另外還支持粘貼截圖發送,通過監聽paste事件,判斷是否是圖片類型,從而發送截圖。

          editorRef.value.addEventListener('paste', function(e) {
              let cbd=e.clipboardData
              let ua=window.navigator.userAgent
              if(!(e.clipboardData && e.clipboardData.items)) return
          
              if(cbd.items && cbd.items.length===2 && cbd.items[0].kind==="string" && cbd.items[1].kind==="file" &&
                  cbd.types && cbd.types.length===2 && cbd.types[0]==="text/plain" && cbd.types[1]==="Files" &&
                  ua.match(/Macintosh/i) && Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49){
                  return;
              }
              for(var i=0; i < cbd.items.length; i++) {
                  var item=cbd.items[i]
                  // console.log(item)
                  // console.log(item.kind)
                  if(item.kind=='file') {
                      var blob=item.getAsFile()
                      if(blob.size===0) return
                      // 讀取圖片記錄
                      var reader=new FileReader()
                      reader.readAsDataURL(blob)
                      reader.onload=function() {
                          var _img=this.result
          
                          // 返回圖片給父組件
                          emit('pasteFn', _img)
                      }
                  }
              }
          })

          還支持拖拽圖片至聊天區域進行發送。

          <div class="ntMain__cont" @dragenter="handleDragEnter" @dragover="handleDragOver" @drop="handleDrop">
              // ...
          </div>
          const handleDragEnter=(e)=> {
              e.stopPropagation()
              e.preventDefault()
          }
          const handleDragOver=(e)=> {
              e.stopPropagation()
              e.preventDefault()
          }
          const handleDrop=(e)=> {
              e.stopPropagation()
              e.preventDefault()
              // console.log(e.dataTransfer)
          
              handleFileList(e.dataTransfer)
          }
          // 獲取拖拽文件列表
          const handleFileList=(filelist)=> {
              let files=filelist.files
              if(files.length >=2) {
                  v3layer.message({icon: 'error', content: '暫時支持拖拽一張圖片', shade: true, layerStyle: {background:'#ffefe6',color:'#ff3838'}})
                  return false
              }
              for(let i=0; i < files.length; i++) {
                  if(files[i].type !='') {
                      handleFileAdd(files[i])
                  }else {
                      v3layer.message({icon: 'error', content: '目前不支持文件夾拖拽功能', shade: true, layerStyle: {background:'#ffefe6',color:'#ff3838'}})
                  }
              }
          }

          大家如果感興趣可以自己去試試哈。

          ok,基于vue3+element-plus開發仿微信/QQ聊天實戰項目就分享到這里。

          基于vue3.0+vant3移動端聊天實戰|vue3聊天模板實例

          日常工作中,如下圖的聊天場景是不是很熟悉,沒錯就是我們再熟悉不過的 QQ 和微信,一個正常的聊天界面大致上是長這個樣子的:

          這種聊天窗口的消息流有兩個明顯的特點:

          • 最新的消息和滾動條初始位置需要在列表的最底部
          • 下拉加載歷史消息要在當前消息列表頂部進行銜接

          一般來說要實現這樣的功能,對于前端開發來說都不是難事,只要兩步就可以了:

          1. 在第一屏消息渲染完之后設置容器的 scrollTop 為一個極大值,這樣就把最新消息和滾動條初始位置定位到了最底部;
          2. 當滾動到頂部時渲染第二屏數據,接著設置容器的 scrollTop 為銜接的位置(也就是第二屏的總高度),這樣就實現了前后兩屏消息的銜接。

          這樣的 demo 只需要隨手擼二三十行代碼就實現了:

          一開始渲染消息 1~20,滾到頂部后渲染第二屏消息 ABCDEFGHIJK,看上去前后兩屏消息的銜接很平滑很流暢。目前開源社區中也有很多現成的用 React 和 Vue 開發的聊天組件或者示例,他們基本也是用上面提到的思路或者借助 iScroll 實現的。

          用上面這種思路跑在 Web 中是沒有任何問題的,但是在小程序中的表現卻大失所望,看一下用同樣的方式應用到小程序后的實際效果:

          從第一段視頻(左)可以看到從列表進入到聊天頁面后設置滾動條位置到底部發生了明顯的跳動,先看到停留在頂部然后瞬間再去到底部;

          第二段視頻(右)滾動到頂部加載后,下一屏消息與當前消息的銜接出現了一個明顯的跳動,也是先看到在頂部然后才去到預期的位置。

          為什么這個思路在 Web 端體驗這么好,到了小程序上體驗就如此糟糕呢?原因其實很簡單,這是由于小程序底層通信邏輯和視圖更新機制造成的:

          由于小程序跨線程通信和異步更新的特點,內容的渲染和滾動位置的設置無法保證完成的先后順序,所以必然會先看到上一個位置一閃而過的畫面。

          既然是底層的問題,那么這種聊天場景在小程序中難道就玩不了了嗎?當然也有嘗試過用 opacity 過渡和滾動動畫去緩解這種跳動,但都無法從根本上解決這兩個體驗問題。

          當各種常規方案嘗試都不盡滿意的時候,那就換個思路:從本質上來說,聊天窗口的消息流實際上是一個 “反自然” 的列表,因為在計算機的 “自然界” 和人們習以為常的使用方式上,列表的初始位置都是在最頂部,想要瀏覽列表更多的內容需要向下滾動,而聊天場景的特點是完全反常規的!

          再回到這兩個體驗問題:為什么需要手動設置最新消息和滾動條到最底部,為什么不讓它一開始就在底部?為什么需要要在列表頂部追加數據,為什么不讓它在底部追加數據?所以有沒有可能顛倒常規,做一個 “反向渲染” 的滾動列表呢?答案是肯定的!

          首先像常規的列表一樣去渲染,不需要做任何處理,第一條最新消息和滾動條的初始位置是自然地在最上面:

          然后把整個列表區域的包裹容器用 CSS 旋轉 180°,這樣第一條最新消息和滾動條初始位置就在最下面下了:

          不過此時整個列表是倒置渲染的,最后再把每一條消息組件用同樣的方式旋轉 180° 使它們顯示回正常的視角,這樣就實現了一個 “反向渲染” 的列表:

          雖然是 “反向渲染”,但視覺上和正常的一模一樣。此時頂部就變成了底部,向上追加數據變成了向下追加數據。最后看一下聊天列表使用 “反向渲染” 之后的體驗效果:

          可以看到,下拉加載消息與當前消息的銜接非常平滑沒有任何的跳動,實際上這個時候歷史消息是在底部渲染的,只不過反向渲染讓它看上去是在頂部渲染的;此外,頁面一進來最新消息和滾動條位置無需任何處理自然地停留在最底部,接近原生體驗。

          這種 “反向渲染” 的思路用最少的代碼就解決了消息場景在小程序上這種幾乎無解的問題,并且達到了最優的體驗,而實際上核心代碼只有兩行 CSS:

          transform: rotate(180deg);
          direction: rtl;

          整個過程無需任何手動設置滾動位置和計算第二屏總高度(實際上都不用關心它們),同樣這種思路用在 Web 上也是 OK 的。當然用了反向渲染也有一些犧牲,比如 iOS 雙擊頂部欄回到頂部這個特點就不能用了,但總體來說獲得體驗上的優化是更多的。

          此外,聊天場景中的消息流通常也有這樣的布局:

          如果視覺上需要將自己和別人的消息方向分別位列兩邊對齊,那么利用這種 “反向渲染” 的思路,實現起來也非常容易,只需要對消息組件應用不同的 CSS 樣式即可:

          消息流的每一條消息都是一個單獨的組件,此時不需要為了區分不同的視角而去新寫一個組件,也不需要改變現有組件的結構布局。

          ?? 最后

          如果你覺得這篇文章對你有幫助,點個「關注/轉發」,讓更多的人也能看到你的分享!


          主站蜘蛛池模板: 视频一区二区三区人妻系列| 国产SUV精品一区二区88| 久久se精品一区二区国产| 久久精品国产第一区二区| 肉色超薄丝袜脚交一区二区| 日本韩国一区二区三区| 国产精品视频一区二区三区经| 国产第一区二区三区在线观看| 少妇精品无码一区二区三区| 亚洲国产精品第一区二区三区| 久久精品免费一区二区喷潮| 亚洲一区二区三区高清| 国产一区二区三区不卡观| 国产激情无码一区二区三区| 精品国产福利在线观看一区| 无码人妻一区二区三区免费手机| 久久久91精品国产一区二区| 国产亚洲情侣一区二区无码AV| 日韩一区二区精品观看| 波多野结衣中文一区二区免费| 在线免费一区二区| 中文字幕日韩欧美一区二区三区 | 中文字幕aⅴ人妻一区二区| 精品无人乱码一区二区三区| 中文字幕AV一区二区三区 | 中文国产成人精品久久一区| 国产av一区二区精品久久凹凸| 国精产品一区一区三区MBA下载 | 国产成人av一区二区三区在线 | 亚洲一区二区在线视频| 久久亚洲国产精品一区二区| 国产一区二区三区久久| 99久久精品国产一区二区成人 | 亚洲日本精品一区二区| 日韩精品乱码AV一区二区| 无码AV中文一区二区三区| 日韩av无码一区二区三区| 中文字幕精品一区二区2021年| 无码视频一区二区三区| 一区二区三区四区在线观看视频 | 日本一区二区三区高清|