实现一个在线个人简历编辑器,实现在线编辑,生成简历图片,运用到技术:

1.vue.js
2.webpack
3.muse-ui(https://museui.github.io
4.html2canvas.js(用来将html生成图片);

已经开发好的项目目录如下:

这里写图片描述

然后是我的简历整体效果

这里写图片描述

(利用组件的思想,这里每个模块就是一个组件,有些模块一样,可以进一步改善,这里我暂时没有)

一. 搭建vue项目

首先用vue-cli搭建我们的项目,没用过的同学可以去看我之前的博客,有专门介绍

二. 引入muse-ui

在项目目录下,安装muse-ui

nam install muse-ui --save -dev

在main.js中引入

import MuseUI from 'muse-ui';
import '../static/css/muse-ui.css';
import '../static/css/theme-carbon.css' // 使用 carbon 主题(可更改)
Vue.use(MuseUI)

如果要用到muse-ui自带的图标的话,在index.html引入两个文件:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

这样就可以在muse-ui官网上复制例子玩了,网上很多muse-ui教程讲得比较复杂,这里我用最简单的方法实现,这里不做演示,有兴趣的同学可以去试试。

三. 头像模块HeaderImg.vue
<template>
    <div class="headerImg">
      <img :src="pictureUrl" alt="" />
      <input type="file" class="file-button" @change="onFileChange" />
    </div>
</template>
<style></style>
<script>
    export default{
        data(){
          return {
            images:[],
            pictureUrl:'../../static/img/headerImg.jpg'
          }
        },
        methods:{
            test () {
            var vm = this
            console.log(vm.message)
        },
        onFileChange (e) {
          var files = e.target.files || e.dataTransfer.files
          if (!files.length) return
          var _this = this
          var reader = null
          reader = new window.FileReader()
          reader.readAsDataURL(files[0])
          reader.onload = function (e) {
            _this.pictureUrl = e.target.result
          }
        },
      },
    }
</script>
四.个人信息模块(写在Home.vue)
<div class="baseInfo">
              <mu-text-field hintText="输入年龄" type="type" icon="face" fullWidth :underlineShow="false" />
              <mu-text-field hintText="输入住址" type="type" icon="place" fullWidth :underlineShow="false"/>
              <mu-text-field hintText="输入电话号码" type="type" icon="phone" fullWidth :underlineShow="false"/>
              <mu-text-field hintText="输入邮箱" type="type" icon="mail" fullWidth :underlineShow="false"/>
          </div>
五. 技能特点模块
<template>
<div class="skills">
  <div class="title">
    <span class="">技能特点</span>
    <a href="javascrpt:;" class="add addBtn" @click="openSkills">
      <mu-icon value="add" color="#fff" />
    </a>
  </div>

  <div>
    <mu-dialog :open="skillsDialog" title="技能特点" @close="closeSkills">
      <mu-text-field label="掌握的技术" labelFloat fullWidth v-model="skill.name"/>
      <mu-row gutter>
        <mu-col width="60" table="60" desktop="80">
          <mu-slider v-model="skill.value" class="demo-slider" :min=0 :max=100 :step="5" />
        </mu-col>
        <mu-col width="60" table="60" desktop="20">
            <span>{{skill.value}}</span>
            <span>/</span>
            <span>100</span>
        </mu-col>
      </mu-row>

      <mu-flat-button slot="actions" @click="closeSkills" primary label="取消"/>
      <mu-flat-button slot="actions" primary label="确定" @click="skillData" />
    </mu-dialog>
  </div>

  <div class="skill-item">
      <div v-if="skillEmpty" class="empty">请先添加技能特点</div>
      <div v-for="(item,index) in skills" class="list" v-else>
        <p>
          <span>{{item.name}}</span>
          <a href="javascript:;" class="delete" @click="deleteSkill(index)">
            <mu-icon value="delete" />
          </a>
        </p>
        <mu-linear-progress mode="determinate" :value="item.value"/>
      </div>
  </div>
</div>
</template>
<style></style>
<script>
export default {
  data () {
    return {
      value: 20,
      skillsDialog:false, 
      skill:{
        name:"",
        value:0
      },
      skills:[], 
      skillEmpty:true,   
    }
  },
  methods: {
    openSkills () { 
      this.skillsDialog = true
    },
    closeSkills () {
      this.skillsDialog = false
    },
    skillData(){
        this.skills.push(this.skill);
        this.skill={
          name:"",
          value:0
        };
        this.skillsDialog = false;
        this.skillEmpty = false;
        console.log(this.skills)
    },
    deleteSkill(index){
      this.skills.splice(index,1);
      if(this.interests==0){
          this.interestEmpty = true;
      }
    }
  }
}
</script>

这里写图片描述

这里写图片描述

六. 教育背景模块(Education.vue)
<template>
    <div class="education">
        <div class="title">
            <mu-icon value="school" color="#1d3653" /> 
        <span>教育背景</span>
        </div>
        <mu-float-button icon="add" mini class="demo-float-button educationBtn" @click="openEducation" />
          <mu-dialog :open="educationDialog" title="教育背景" @close="closeEducation">
              <mu-row gutter>
                <mu-col width="50" table="30" desktop="20">
                  <mu-date-picker mode="landscape" hintText="开始时间" fullWidth v-model="edu.startTime" />
                </mu-col>
                <mu-col width="50" table="30" desktop="20">
                  <mu-date-picker mode="landscape" hintText="结束时间" fullWidth v-model="edu.endTime" />
                </mu-col>
                <mu-col width="50" table="30" desktop="35">
                  <mu-text-field hintText="毕业学校" fullWidth v-model="edu.school" />
                </mu-col>
                <mu-col width="50" table="30" desktop="25">
                  <mu-text-field hintText="专业技能" fullWidth v-model="edu.professional" />
                </mu-col>
              </mu-row>
              <mu-row gutter>
                <mu-col width="100" table="100" desktop="100">
                  <mu-text-field hintText="输入教育背景详情"  multiLine :rows="1" :rowsMax="5" fullWidth v-model="edu.content" />
                </mu-col>
              </mu-row>
            <mu-flat-button slot="actions" @click="closeEducation" primary label="关闭"/>
            <mu-flat-button slot="actions" primary  label="确定" @click="eduData" />
          </mu-dialog>

          <div class="education-content lists">
              <div v-if="empty" class="empty">请添加教育背景</div>
              <div v-for="(item,index) in edus" class="list" v-else>
                  <mu-row gutter>
                      <mu-col width="50" table="30" desktop="30">
                        <span class="title-font">{{item.startTime}}</span>
                        <span class="title-font">--</span>
                        <span class="title-font">{{item.endTime}}</span>
                      </mu-col>
                      <mu-col width="50" table="30" desktop="30">
                        <span class="title-font">{{item.school}}</span>
                      </mu-col>
                      <mu-col width="50" table="30" desktop="30">
                        <span class="title-font">{{item.professional}}</span>
                      </mu-col>
                      <mu-col width="50" table="5" desktop="10">
                        <a href="javascript:;" class="deleteBtn" @click="deleteData(index)">
                            <mu-icon value="delete" color="#fff" />
                        </a>
                      </mu-col>
                    </mu-row>
                    <mu-row gutter>
                    <mu-col width="100" table="100" desktop="100">
                      <span class="content-font">{{item.content}}</span>
                    </mu-col>
                </mu-row>
              </div>
          </div>
      </div>
</template>
<style></style>
<script>
    export default{
        data(){
            return {
                educationDialog:false,
                empty:true,
                edu:{
                    startTime:"",
                    endTime:"",
                    school:"",
                    professional:"",
                    content:"",
                },
                edus:[],
            }
        },
        methods: {
            openEducation () {
              this.educationDialog = true
            },
            closeEducation () {
              this.educationDialog = false
            },
            eduData(){
              this.edus.push(this.edu);
              this.edu = {
                startTime:"",
                endTime:"",
                school:"",
                professional:"",
                content:"",
              };
              this.educationDialog = false;
              this.empty = false;
            },
            deleteData(index){
              this.edus.splice(index,1);
              if(this.edus.length==0){
                  this.empty = true;
              }
            },
        },
    }
</script>

这里写图片描述

这里写图片描述

这里写图片描述

其他的模块功能实现都差不多,有兴趣的同学可以自己去试试,最后我们再生成简历,这里要借助html2canvas,不清楚的可以百度查查该插件的使用方法
在Home.vue中引入

import Html2canvas from '../../static/js/html2canvas';

<script>
import HeaderImg from './HeaderImg';
import Skills from './Skills';
import Interest from './Interest';
import Education from './Education';
import Work from './Work';
import Award from './Award';
import Assessment from './Assessment';
import Html2canvas from '../../static/js/html2canvas';

export default{
  data(){
      return{
        url:"",
        resumeImg:"../../static/img/headerImg.jpg",
        readResume:false
      }
  },
  methods:{
        createImg(){
        var canvas = document.querySelector("canvas");
        var ctx = canvas.getContext("2d");
        var _this = this;
        Html2canvas(document.querySelector("#app"), {
            onrendered: function(canvas){
                var img = canvas.toDataURL();
                _this.url = img;
                _this.resumeImg = img;
                _this.readResume = true;
            },
        });
    },
    closeResume(){
      this.readResume = false;
    },
  },
  components:{
    Skills,
    Interest,
    Education,
    Work,
    Award,
    Assessment,
    HeaderImg
  }
}
</script>

这里写图片描述

点击下载简历,会下载该简历图片,

这里写图片描述

这里下载的图片可能有点模糊,具体原因我也没去深究,也是边学边做,有清楚的同学可以交流交流。
GitHub地址:https://github.com/antkonw/vue_resume 记得关注,给星哈
好了,在线简历就这样做好了,等我搭建好服务器,可以放在线上让大家玩玩。

Logo

前往低代码交流专区

更多推荐