用electron写个浏览器给自己玩

浏览器这种东西工程量很唬人,但是有了electron+webview我们就相当于只需要干组装的活就可以了,而且产品目标就是给自己玩, 成品的效果 😄本来想写成专业的技术博客,但是发现大家好像对那种密密麻麻,全是代码的技术博客不感兴趣,我就挑重点来写吧。

下载拦截功能

下载逻辑如果不做拦截处理的话,默认就是我们平常写web那种弹窗的方式,既然是浏览器肯定不能是那样的。 electron中可以监听BrowserWindow的页面下载事件,并把拿到的下载状态传给渲染线程,实现类似浏览器的下载器功能。

javascript 复制代码
//这个global.WIN =   global.WIN = new BrowserWindow({ ...})
 global.WIN.webContents.session.on('will-download', (evt, item) => {
 //其他逻辑
       item.on('updated', (evt, state) => {
       //实时的下载进度传递给渲染线程
       })
 })

页面搜索功能

当时做这个功能的时候我就觉得完了,这个玩意看起来太麻烦了,还要有一个的功能这不是头皮发麻啊。

查资料和文档发现这个居然是webview内置的功能,瞬间压力小了很多,我们只需要出来ctrl+f的时候把搜索框弹出来这个UI就可以了,关键字变色和下一个都是内部已经实现好了的。

javascript 复制代码
function toSearch() {
  let timer
  return () => {
    if (timer) {
      clearTimeout(timer)
    }

    timer = setTimeout(() => {
      if (keyword.value) {
        webviewRef.value.findInPage(keyword.value, { findNext: true })
      } else {
        webviewRef.value.stopFindInPage('clearSelection')
      }
    }, 200)
  }
}
  function closeSearch() {
  showSearch.value = false
  webviewRef.value.stopFindInPage('clearSelection')
}

function installFindPage(webview) {
  webviewRef.value = webview
  webviewRef.value.addEventListener('found-in-page', (e) => {
    current.value = e.result.activeMatchOrdinal
    total.value = e.result.matches
  })
}

当前标签页打开功能

就是因为chrome和edge这些浏览器每次使用的时候开非常多的标签,挤在一起,所以我想这个浏览器不能主动开标签,打开了一个标签后强制所有的标签都在当前标签覆盖。

javascript 复制代码
app.on('web-contents-created', (event, contents) => {
  contents.setWindowOpenHandler((info) => {
    global.WIN?.webContents.send('webview-url-is-change')
    if (info.disposition === 'new-window') {
      return { action: 'allow' }
    } else {
      global.WIN?.webContents.send('webview-open-url', info.url)
      return { action: 'deny' }
    }
  })
})

渲染线程监听到webview-open-url后也就是tart="_blank"的情况,强制覆盖当前不打开新窗口

javascript 复制代码
ipcRenderer.on('webview-open-url', (event, url) => {
  try {
    let reg = /http|https/g
    if (webviewRef.value && reg.test(url)) {
      webviewRef.value.src = url
    }
  } catch (err) {
    console.log(err)
  }
})

标签页切换功能

这里的切换是css的显示隐藏,借助了vue-router

这里我们看dom就能清晰的看出来。

地址栏功能

地址栏支持输入url直接访问链接、支持关键字直接打开收藏的网站、还支持关键字搜索。优先级1打开收藏的网页 2访问网站 3关键字搜索

javascript 复制代码
function toSearch(keyword) {
    if (`${keyword}`.length === 0) {
      return false
    }
    // app搜索
    if (`${keyword}`.length < 20) {
      let item = null
      const list = [...deskList.value, ...ALL_DATA]
      for (let i = 0; i < list.length; i++) {
        if (
          list[i].title.toUpperCase().search(keyword.toUpperCase()) !== -1 &&
          list[i].type !== 'mini-component'
        ) {
          item = list[i]
          break
        }
      }
      if (item) {
        goApp(item)
        return false
      }
    }

    // 网页访问
    let url
    if (isUrl(keyword)) {
      if (!/^https?:\/\//i.test(keyword)) {
        url = 'http://' + keyword
      } else {
        url = keyword
      }
      goAppNewTab(url)
      return false
    } else {
      // 关键字搜索
      let searchEngine = localStorage.getItem('searchEngine')
      searchEngine = searchEngine || CONFIG.searchEngine
      url = searchEngine + keyword

      if (!router.hasRoute('search')) {
        router.addRoute({
          name: 'search',
          path: '/search',
          meta: {
            title: '搜索',
            color: 'var(--app-icon-bg)',
            icon: 'search.svg',
            size: 1
          },
          component: WebView
        })
        keepAliveInclude.value.push('search')
      }

      router.push({
        path: '/search',
        query: { url }
      })

      setTimeout(() => {
        Bus.$emit('toSearch', url)
      }, 20)
    }
  }

桌面图标任意位置拖动

这个问题困扰了我很久,因为它不像电脑桌面大小是固定的,浏览器可以全屏也可以小窗口,如果最开始是大窗口然后拖成小窗口,那么图标就看不到了。后来想到我干脆给个中间区域固定大小,就可以解决这个问题了。因为固定大小出来起来就方便多了。这个桌面是上下两层

html 复制代码
//背景格子
    <div v-show="typeActive === 'me'" class="bg-boxs">
      <div
        v-for="(item, i) in 224"  //这里有点不讲究了直接写死了
        :key="item"
        class="bg-box"
        @dragenter="enter($event, { x: (i % 14) + 1, y: Math.floor(i / 14) + 1 })"
        @dragover="over($event)"
        @dragleave="leave($event)"
        @drop="drop($event)"
      ></div>
    </div>
 // 桌面层
 // ...
javascript 复制代码
import { ref, computed } from 'vue'
import useDesk from '@/store/deskList'
import { storeToRefs } from 'pinia'

export default function useDrag() {
  const dragging = ref(null)
  const currentTarget = ref()
  const desk = useDesk()

  const { deskList } = storeToRefs(desk)
  const { setDeskList, updateDeskData } = desk

  function start(e, item) {
    e.target.classList.add('dragging')
    e.dataTransfer.effectAllowed = 'move'
    dragging.value = item
    currentTarget.value = e
    console.log('开始')
  }
  let timer2
  function end(e) {
    dragging.value = null
    e.target.classList.remove('dragging')
    setDeskList(deskList.value)

    if (timer2) {
      clearTimeout(timer2)
    }
    timer2 = setTimeout(() => {
      updateDeskData()
    }, 2000)
  }
  function over(e) {
    e.preventDefault()
  }

  let timer
  function enter(e, item) {
    e.dataTransfer.effectAllowed = 'move'
    if (timer) {
      clearTimeout(timer)
    }

    timer = setTimeout(() => {
      if (item?.x) {
        dragging.value.x = item.x
        dragging.value.y = item.y
      }
    }, 100)
  }
  function leave(e) {}

  function drop(e) {
    e.preventDefault()
  }

  return { start, end, over, enter, leave, drop }
}

东西太多了就先介绍这些了

安装包地址

github.com/jddk/aweb-b...

也可以到官网后aweb123.com 如何进入微软商店下载,mac版本因为文件大于100mb没有传上去所以暂时还用不了。

公众号

aweb浏览器交流群

相关推荐
范文杰3 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪3 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪3 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy4 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom5 小时前
快速开始使用 n8n
后端·面试·github
uhakadotcom5 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom5 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom5 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom5 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom5 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试