百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

手把手教你Electron + Vue实战教程(三)

cac55 2024-10-26 08:14 32 浏览 0 评论


作者:Sufen

转发链接:https://mp.weixin.qq.com/s/RkKNMNEaV0Hrp8iQ9MaX0A

目录

手把手教你Electron + Vue实战教程(一)

手把手教你Electron + Vue实战教程(二)

手把手教你Electron + Vue实战教程(三)本篇

手把手教你Electron + Vue实战教程(四)

?

上一篇我们已经完成了左侧菜单栏的基本样式功能,这一篇我们就主要来开发右侧的Markdown编辑区域,即文件编辑组件FileEdit

?

需求分析

有道云笔记截图

我们从截图里可以看到,右侧区域主要是由标题栏和内容编辑区组成,其中标题栏的右侧还包含了一排操作按钮,在这里我们就先把这一排按钮忽略了,先把主要功能开发完毕再考虑迭代优化。

所以我们的最终需要实现的需求其实很简单,就是「标题栏 + Markdown编辑区 = 右侧区域」,标题栏支持修改输入,Markdown区支持编辑操作和预览模式,同时也支持单栏和双栏切换,当然还有必不可少的全屏操作。

FileEdit组件开发

我们先在组件目录components下新建组件FileEdit,组件分为上下两部分:

<!--
 * @Description: 文件编辑组件
 * @Author: sufen
 * @Date: 2020-05-30 16:24:05
 * @LastEditTime: 2020-06-01 15:31:36
 * @LastEditors: sufen
 -->
<template>
  <div class="content-edit">
    // 标题区域
    // 编辑区
  </div>
</template>

<script>export default {
  name: 'FileEdit'
}</script>

<style lang="less" scoped></style>

组件的顶部直接使用element组件el-input,我们需要稍微修改一点样式:

<el-input class="file-title" v-model="currentTitle" placeholder="请输入标题" />
  .file-title {
    padding-left: 5px;
    height: 56px;
    line-height: 56px;
    font-size: 18px;
    font-weight: 500;

    /deep/ .el-input__inner {
      height: inherit;
      line-height: inherit;
      font-weight: inherit;
      border: none;
    }
  }

mavon-editor

Markdown的编辑区,我们可以直接选用第三方的插件包mavon-edito,3.9k star也算是比较火的一个开源Markdown编辑器了,详细说明大家可以看一下官方文档:https://github.com/hinesboy/mavonEditor

这里先来安装引入一下mavon-editor,我习惯使用yarn,大家可以根据自己喜好使用npm也木有任何问题:

yarn add mavon-editor

安装完后在插件目录plugin里新建文件mavonEditor.js引入依赖包:

/*
 * @Description: markdown 编辑器插件
 * @Author: sufen
 * @Date: 2020-05-30 16:31:31
 * @LastEditTime: 2020-06-02 11:01:31
 * @LastEditors: sufen
 */
import Vue from 'vue'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'

Vue.use(mavonEditor)

在main.js中引入我们刚编写好的mavonEditor.js就算完成全部引入了:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/plugin/element-ui'
import '@/plugin/fortawesome'
import '@/plugin/mavonEditor'

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

Attrs 和 Listeners

现在我们可以在组件里引入编辑器了:

<mavon-editor v-bind="$attrs" v-on="$listeners" class="markdown-wrapper" />
.markdown-wrapper {
  height: calc(100vh - 56px);

  &.fullscreen {
    height: 100vh;
  }
}

不知道大家之前有没有使用过$attrs和$listeners,它绝对是二次封装组件、写高阶组件的神器。这两个属性是vue 2.4版本之后提供的,在我们平时写业务的时候免不了需要对一些第三方组件进行二次封装。比如我们现在就需要基于mavon-editor封装一个带有业务特性的组件,添加了el-input输入框,将一些业务逻辑封装在其中。

在mavon-editor的文档中我们可以看到组件支持二三十个配置参数,我们可以适当的挑选几个参数通过props来传递,但如果哪天别人用你的业务组件的时候觉得你的参数少了,那就只能改你封装的组件了,亦或是哪天第三方组件加入了新参数,这个时候你又该怎么办?

其实FileEdit组件就是基于mavon-editor做了一些简单的业务封装,加入了一个标题输入框,它只是一个充当中间人的组件,负责传递数据而已,那么这个时候我们可以使用v-bind="$attrs":传递所有属性、v-on="$listeners"传递所有方法:

最后在Home.vue中使用我们的FileEdit组件:

.sync

这个也是vue 2.3.0+之后新加的一个语法糖,平时在封装组件的时候很好用的一个语法糖,它的实现机制和v-model是一样的。我们可以先看下官方文档:https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A5%B0%E7%AC%A6

“在有些情况下,我们可能需要对一个prop进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。”示例代码:

<file-edit :title.sync="title"/>

会被扩展为:

<file-edit :title="title" @update:title="val => title = val"/>

当子组件需要更新 title 的值时,它需要显式地触发一个更新事件:

this.$emit('update:title', newValue)

单向数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

以上为 vue 官方的对于单向数据流的解释,大家可以在官网详细看看:https://cn.vuejs.org/v2/guide/components-props.html

因为单向数据流的原因,我们组件内的标题栏组件el-input不能直接v-model绑定 props 传递过来的title值,我们需要在 data 中定义一个currentTitle,用以绑定v-model="currentTitle"。

联系上文的.sync,我们还需要监听currentTitle的值,实时更新 props 传递过来的值title:

至此,我们的FileEdit组件就暂时告一段落了,这篇基本都是一些 vue 组件封装的小技巧,希望能够对大家有些许帮助,下面贴出我们组件的完整代码和 Home.vue 页面调用组件代码:

<!--
 * @Description: 文件编辑组件
 * @Author: sufen
 * @Date: 2020-05-30 16:24:05
 * @LastEditTime: 2020-06-02 12:00:49
 * @LastEditors: sufen
 -->
<template>
  <div class="content-edit">
    <el-input class="file-title" v-model="currentTitle" placeholder="请输入标题" />
    <mavon-editor v-bind="$attrs" v-on="$listeners" class="markdown-wrapper" />
  </div>
</template>

<script>export default {
  name: 'FileEdit',
  props: {
    title: String
  },
  data() {
    return {
      currentTitle: this.title
    }
  },
  watch: {
    currentTitle(newValue) {
      this.$emit('update:title', newValue)
    }
  }
}</script>

<style lang="less" scoped>
.content-edit {
  .file-title {
    padding-left: 5px;
    height: 56px;
    line-height: 56px;
    font-size: 18px;
    font-weight: 500;

    /deep/ .el-input__inner {
      height: inherit;
      line-height: inherit;
      font-weight: inherit;
      border: none;
    }
  }

  .markdown-wrapper {
    height: calc(100vh - 56px);

    &.fullscreen {
      height: 100vh;
    }
  }
}
</style>
<template>
  <div class="app-wrapper">
    <div class="sidebar-container">
      <file-search v-model="searchTitle" />
      <file-list :fileList="fileList" />
    </div>
    <div class="main-container">
      <file-edit
        v-model="fileItem.content"
        :title.sync="fileItem.title"
        :boxShadow="false"
        :subfield="false"
        :shortCut="false"
        @change="onSubmit"
      />
    </div>
  </div>
</template>

<script>import FileSearch from '@/components/FileSearch'
import FileList from '@/components/FileList'
import FileEdit from '@/components/FileEdit'

export default {
  name: 'Home',
  components: { FileSearch, FileList, FileEdit },
  data() {
    return {
      searchTitle: '',
      fileList: [
        { id: 1, title: '文件名 1', time: '2020-06-21' },
        { id: 2, title: '文件名 2', time: '2020-06-21' },
        { id: 3, title: '文件名 3', time: '2020-06-21' },
        { id: 4, title: '文件名 4', time: '2020-06-21' },
        { id: 5, title: '文件名 5', time: '2020-06-21' },
        { id: 6, title: '文件名 6', time: '2020-06-21' },
        { id: 1, title: '文件名 1', time: '2020-06-21' },
        { id: 2, title: '文件名 2', time: '2020-06-21' },
        { id: 3, title: '文件名 3', time: '2020-06-21' },
        { id: 4, title: '文件名 4', time: '2020-06-21' },
        { id: 5, title: '文件名 5', time: '2020-06-21' },
        { id: 6, title: '文件名 6', time: '2020-06-21' }
      ],
      fileItem: {
        title: '手摸手Electron + Vue实战教程(三)',
        content: ''
      }
    }
  },
  methods: {
    onSubmit(value) {
      console.log(value)
      console.log(this.fileItem)
    }
  }
}</script>

<style lang="less" scoped>
.app-wrapper {
  display: flex;
  .sidebar-container {
    width: 300px;
    height: 100vh;
    border-right: 1px solid #eaeefb;
  }
  .main-container {
    flex: 1;
    overflow: hidden;
  }
}
</style>

推荐Vue学习资料文章:

手把手教你Electron + Vue实战教程(二)

手把手教你Electron + Vue实战教程(一)

收集22种开源Vue模板和主题框架「干货」

如何写出优秀后台管理系统?11个经典模版拿去不谢「干货」

手把手教你实现一个Vue自定义指令懒加载

基于 Vue 和高德地图实现地图组件「实践」

一个由 Vue 作者尤雨溪开发的 web 开发工具—vite

是什么让我爱上了Vue.js

1.1万字深入细品Vue3.0源码响应式系统笔记「上」

1.1万字深入细品Vue3.0源码响应式系统笔记「下」

「实践」Vue 数据更新7 种情况汇总及延伸解决总结

尤大大细说Vue3 的诞生之路「译」

提高10倍打包速度工具Snowpack 2.0正式发布,再也不需要打包器

大厂Code Review总结Vue开发规范经验「值得学习」

Vue3 插件开发详解尝鲜版「值得收藏」

带你五步学会Vue SSR

记一次Vue3.0技术干货分享会

Vue 3.x 如何有惊无险地快速入门「进阶篇」

「干货」微信支付前后端流程整理(Vue+Node)

带你了解 vue-next(Vue 3.0)之 炉火纯青「实践」

「干货」Vue+高德地图实现页面点击绘制多边形及多边形切割拆分

「干货」Vue+Element前端导入导出Excel

「实践」Deno bytes 模块全解析

细品pdf.js实践解决含水印、电子签章问题「Vue篇」

基于vue + element的后台管理系统解决方案

Vue仿蘑菇街商城项目(vue+koa+mongodb)

基于 electron-vue 开发的音乐播放器「实践」

「实践」Vue项目中标配编辑器插件Vue-Quill-Editor

基于 Vue 技术栈的微前端方案实践

消息队列助你成为高薪 Node.js 工程师

Node.js 中的 stream 模块详解

「干货」Deno TCP Echo Server 是怎么运行的?

「干货」了不起的 Deno 实战教程

「干货」通俗易懂的Deno 入门教程

Deno 正式发布,彻底弄明白和 node 的区别

「实践」基于Apify+node+react/vue搭建一个有点意思的爬虫平台

「实践」深入对比 Vue 3.0 Composition API 和 React Hooks

前端网红框架的插件机制全梳理(axios、koa、redux、vuex)

深入Vue 必学高阶组件 HOC「进阶篇」

深入学习Vue的data、computed、watch来实现最精简响应式系统

10个实例小练习,快速入门熟练 Vue3 核心新特性(一)

10个实例小练习,快速入门熟练 Vue3 核心新特性(二)

教你部署搭建一个Vue-cli4+Webpack移动端框架「实践」

2020前端就业Vue框架篇「实践」

详解Vue3中 router 带来了哪些变化?

Vue项目部署及性能优化指导篇「实践」

Vue高性能渲染大数据Tree组件「实践」

尤大大细品VuePress搭建技术网站与个人博客「实践」

10个Vue开发技巧「实践」

是什么导致尤大大选择放弃Webpack?【vite 原理解析】

带你了解 vue-next(Vue 3.0)之 小试牛刀【实践】

带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】

实践Vue 3.0做JSX(TSX)风格的组件开发

一篇文章教你并列比较React.js和Vue.js的语法【实践】

手拉手带你开启Vue3世界的鬼斧神工【实践】

深入浅出通过vue-cli3构建一个SSR应用程序【实践】

怎样为你的 Vue.js 单页应用提速

聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总

【新消息】Vue 3.0 Beta 版本发布,你还学的动么?

Vue真是太好了 壹万多字的Vue知识点 超详细!

Vue + Koa从零打造一个H5页面可视化编辑器——Quark-h5

深入浅出Vue3 跟着尤雨溪学 TypeScript 之 Ref 【实践】

手把手教你深入浅出vue-cli3升级vue-cli4的方法

Vue 3.0 Beta 和React 开发者分别杠上了

手把手教你用vue drag chart 实现一个可以拖动 / 缩放的图表组件

Vue3 尝鲜

总结Vue组件的通信

Vue 开源项目 TOP45

2020 年,Vue 受欢迎程度是否会超过 React?

尤雨溪:Vue 3.0的设计原则

使用vue实现HTML页面生成图片

实现全栈收银系统(Node+Vue)(上)

实现全栈收银系统(Node+Vue)(下)

vue引入原生高德地图

Vue合理配置WebSocket并实现群聊

多年vue项目实战经验汇总

vue之将echart封装为组件

基于 Vue 的两层吸顶踩坑总结

Vue插件总结【前端开发必备】

Vue 开发必须知道的 36 个技巧【近1W字】

构建大型 Vue.js 项目的10条建议

深入理解vue中的slot与slot-scope

手把手教你Vue解析pdf(base64)转图片【实践】

使用vue+node搭建前端异常监控系统

推荐 8 个漂亮的 vue.js 进度条组件

基于Vue实现拖拽升级(九宫格拖拽)

手摸手,带你用vue撸后台 系列二(登录权限篇)

手摸手,带你用vue撸后台 系列三(实战篇)

前端框架用vue还是react?清晰对比两者差异

Vue组件间通信几种方式,你用哪种?【实践】

浅析 React / Vue 跨端渲染原理与实现

10个Vue开发技巧助力成为更好的工程师

手把手教你Vue之父子组件间通信实践讲解【props、$ref 、$emit】

1W字长文+多图,带你了解vue的双向数据绑定源码实现

深入浅出Vue3 的响应式和以前的区别到底在哪里?【实践】

干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)

基于Vue/VueRouter/Vuex/Axios登录路由和接口级拦截原理与实现

手把手教你D3.js 实现数据可视化极速上手到Vue应用

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【上】

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【中】

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【下】

Vue3.0权限管理实现流程【实践】

后台管理系统,前端Vue根据角色动态设置菜单栏和路由

作者:Sufen

转发链接:https://mp.weixin.qq.com/s/RkKNMNEaV0Hrp8iQ9MaX0A

相关推荐

Linux :远程访问的 16 个最佳工具(一)

通过远程桌面协议(RDP)可以访问远程Linux桌面计算机,这是Microsoft开发的专有协议。它为用户提供了一个图形界面,可以通过网络连接连接到另一台/远程计算机。FreeRDP是...

Guacamole安装部署_guacamole简单搭建

Guacamole安装部署Guacamole简介Guacamole是提供连接远程桌面的解决方案的开源项目(也可以说是一个远程桌面网关),通过浏览器就能远程操作服务器,适用于Chrome、Firefox...

1-FreeRTOS入门指南_freertos+lwip

本专栏是根据官方提供的文档进行FreeRTOS的各个功能函数的说明,以及函数的使用本专栏不涉及动手操作,只是对原理进行说明,FreeRTOS基础知识篇更新完成会对如何在开发板上进行上手实战操作。这里不...

Windows暂停远程桌面,这些工具可替代

Windows暂停远程桌面,这些工具可替代近日,Windows官方宣布将于2025年5月27日起,在Windows10和Windows11应用商店中下架“Microsoft远程桌面”应用。这一消...

现在做 Web 全景合适吗?_前端全景

作者:前端藏经阁转发链接:https://www.yuque.com/xwifrr/uxqg5v/cgclx0前言Web全景在以前带宽有限的条件下常常用来作为街景和360°全景图片可查看。它可以...

网页直连,MSTSC远程控制Windows新姿势!

不用安装软件,打开浏览器就能远程办公?今天要聊的是一种颠覆传统的远程控制玩法,直接用网页连接Windows电脑,无需下载客户端,手机、平板、Mac甚至Linux都能轻松操作。这可不是吹牛,结合MSTS...

QQ出现大面积盗号,原因已查明,请抓紧改密码

你没有看错,QQ又上了微博热搜,这次比较严重了,QQ出现大面积盗号,多个QQ群出现yellow信息,其次导致多位成员被踢出,并且还被封号处理,到底怎么回事?请继续往下看。在6月26日晚上10点左...

我在淘宝花10块钱,买到了能玩“宝可梦”的Q群机器人

十一月雨|文我是个没事喜欢逛淘宝的人,虽然是个不怎么好的习惯,但总是能够发现一些奇奇怪怪的东西,这次我发现的是一种Q群机器人。Q群机器人,大多是基于腾讯SmartQQ协议实现的一种能自动回复、自定...

Metasploit最实用的攻击模块&quot;Meterpreter&quot;

Meterpreter命令详解Meterpreter是Metasploit渗透测试平台框架中功能最强大的攻击载荷模块,在最新的Metasploitv4.5.0版本中,攻击载荷模块已经达到了25...

手机QQ再更新,上线了一个想让人“无法回避”的新功能

近日,手机QQ更新了V8.2.6.700版本,苹果iOS版和安卓版手机QQ上线了一个新功能:可以实时显示对方的手机电量以及充电状态。开通电量显示也很简单,长按主页左上方的头像,在在线状态中选择我的电量...

「网络安全」常见攻击篇(20)——点击劫持

什么是点击劫持?点击劫持(Clickjacking)技术又称为界面伪装攻击(UIredressattack),是一种视觉上的欺骗手段。通常有两种方式:攻击者使用一个透明的iframe,覆盖...

曾利用驱动人生升级通道传播的木马下载器攻击方法再次升级

一、概述御见威胁情报中心1月25日再次监测到曾利用驱动人生升级通道传播的木马下载器攻击方法再升级。本次升级主要变化在于攻击模块,木马在之前的版本上,新增计划任务“DnsScan”,在其中将永恒之蓝攻击...

QQ飞车手游:点券首个功能性宠物上架,实战稳定触发还不快入手?

随着版本的逐渐更新,点券宠物在道具模式发挥逐渐越来越小,曾经探讨点券宠物在道具是不是真的没有用?直到出现了波斯猫改变了,我对点券宠物在道具模式的看法,如今又一个强势点券宠物来袭,而且特性触发简单,还是...

工单系统设计实战(上):核心配置与效能提升

流程的标准化并非终点,而是研发效能持续革命的基石。当工单系统真正成为研发团队的“神经中枢”,每一次需求的精准流转、每一行代码的受控提交、每一次版本的可靠发布,都将汇聚成驱动产品持续进化的强大动力...

6个编辑PDF文档内容的工具(软件+网站)

在日常办公、学习和生活中,PDF文件因其格式稳定、跨平台兼容性强等特点,被广泛应用。但有时我们拿到PDF文件后,却发现需要修改其中的内容,总感觉有点难搞。其实PDF文档编辑修改也很简单,这里分享6个软...

取消回复欢迎 发表评论: