整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

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 样式即可:

消息流的每一条消息都是一个单独的组件,此时不需要为了区分不同的视角而去新写一个组件,也不需要改变现有组件的结构布局。

?? 最后

如果你觉得这篇文章对你有帮助,点个「关注/转发」,让更多的人也能看到你的分享!