vue.js实现会动的简历(包含底部导航功能,编辑功能)

在网上看到一个这样的网站,STRML它的效果看着十分有趣,如下图所示:

这个网站是用 react.js 来写的,于是,我就想着用 vue.js 也来写一版,开始撸代码。

首先要分析打字的原理实现,假设我们定义一个字符串 str ,它等于一长串注释加 CSS 代码,并且我们看到,当 css 代码写完一个分号的时候,它写的样式就会生效。我们知道要想让一段 CSS 代码在页面生效,只需要将其放在一对 <style> 标签对中即可。比如:

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>JS Bin</title>
</head>
<body>
 红色字体
 <style>
 body{
  color:#f00;
 }
 </style>
</body>
</html>

你可以狠狠点击此处 具体示例 查看效果。

当看到打字效果的时候,我们不难想到,这是要使用 间歇调用(定时函数:setInterval()) 或 超时调用(延迟函数:setTimeout()) 加 递归 去模拟实现 间歇调用 。一个包含一长串代码的字符串,它是一个个截取出来,然后分别写入页面中,在这里,我们需要用到字符串的截取方法,如 slice(),substr(),substring() 等,选择用哪个截取看个人,不过需要注意它们之间的区别。好了,让我们来实现一个简单的这样打字的效果,如下:

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>JS Bin</title>
</head>
<body>
 <div id="result"></div>
 <script>
  var r = document.getElementById('result');
  var c = 0;
  var code = 'body{background-color:#f00;color:#fff};'
  var timer = setInterval(function(){
   c++;
   r.innerHTML = code.substr(0,c);
   if(c >= code.length){
   clearTimeout(timer);
   }
  },50)
 </script>
</body>
</html>

你可以狠狠点击此处具体示例查看效果。好的,让我们来分析一下以上代码的原理,首先放一个用于包含代码显示的标签,然后定义一个包含代码的字符串,接着定义一个初始值为 0 的变量,为什么要定义这样一个变量呢?我们从实际效果中看到,它是一个字一个字的写入到页面中的。初始值是没有一个字符的,所以,我们就从第 0 个开始写入, c 一个字一个字的加,然后不停的截取字符串,最后渲染到标签的内容当中去,当 c 的值大于等于了字符串的长度之后,我们需要清除定时器。定时函数看着有些不太好,让我们用超时调用结合递归来实现。

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>JS Bin</title>
</head>
<body>
 <div id="result"></div>
 <script>
  var r = document.getElementById('result');
  var c = 0;
  var code = 'body{background-color:#f00;color:#fff};';
  var timer;
  function write(){
  c++;
  r.innerHTML = code.substr(0,c);
  if(c >= code.length && timer){
   clearTimeout(timer)
  }else{
   setTimeout(write,50);
  }
 }
 write();
 </script>
</body>
</html>

你可以狠狠点击此处具体示例 查看效果。

好了,到此为止,算是实现了第一步,让我们继续,接下来,我们要让代码保持空白和缩进,这可以使用 <pre> 标签来实现,但其实我们还可以使用css代码的 white-space 属性来让一个普通的 div 标签保持这样的效果,为什么要这样做呢,因为我们还要实现一个功能,就是编辑它里面的代码,可以让它生效。更改一下代码,如下:

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>JS Bin</title>
 <style>
 #result{
  white-space:pre-wrap;
  oveflow:auto;
 }
 </style>
</head>
<body>
 <div id="result"></div>
 <script>
  var r = document.getElementById('result');
  var c = 0;
  var code = `
  body{
   background-color:#f00;
   color:#fff;
  }
  `
  var timer;
  function write(){
  c++;
  r.innerHTML = code.substr(0,c);
  if(c >= code.length && timer){
   clearTimeout(timer)
  }else{
   setTimeout(write,50);
  }
 }
 write();
 </script>
</body>
</html>

你可以狠狠点击此处 具体示例查看效果。

接下来,我们还要让样式生效,这很简单,将代码在 style 标签中写一次即可,请看:

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width">
 <title>JS Bin</title>
 <style>
 #result{
  white-space:pre-wrap;
  overflow:auto;
 }
 </style>
</head>
<body>
 <div id="result"></div>
 <style id="myStyle"></style>
 <script>
  var r = document.getElementById('result'),
   t = document.getElementById('myStyle');
  var c = 0;
  var code = `
   body{
   background-color:#f00;
   color:#fff;
   }
  `;
  var timer;
  function write(){
  c++;
  r.innerHTML = code.substr(0,c);
  t.innerHTML = code.substr(0,c);
  if(c >= code.length){
   clearTimeout(timer);
  }else{
   setTimeout(write,50);
  }
  }
  write();
 </script>

</body>
</html>

你可以狠狠点击此处 具体示例 查看效果。

我们看到代码还会有高亮效果,这可以用正则表达式来实现,比如以下一个 demo :

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <meta http-equiv="X-UA-Compatible" content="ie=edge" />
 <title>代码编辑器</title>
 <style>
  * {
   margin: 0;
   padding: 0;
  }

  .ew-code {
   tab-size: 4;
   -moz-tab-size: 4;
   -o-tab-size: 4;
   margin-left: .6em;
   background-color: #345;
   white-space: pre-wrap;
   color: #f2f2f2;
   text-indent: 0;
   margin-right: 1em;
   display: block;
   overflow: auto;
   font-size: 20px;
   border-radius: 5px;
   font-style: normal;
   font-weight: 400;
   line-height: 1.4;
   font-family: Consolas, Monaco, "宋体";
   margin-top: 1em;
  }

  .ew-code span {
   font-weight: bold;
  }
 </style>
</head>

<body>
 <code class="ew-code">
  <div id="app">
   <p>{{ greeting }} world!</p>
  </div>
 </code>
 <code class="ew-code">
  //定义一个javascript对象
  var obj = {
   greeting: "Hello,"
  };
  //创建一个实例
  var vm = new Vue({
   data: obj
  });
  /*将实例挂载到根元素上*/
  vm.$mount(document.getElementById('app'));
 </code>
 <script>
  var lightColorCode = {
   importantObj: ['JSON', 'window', 'document', 'function', 'navigator', 'console', 'screen', 'location'],
   keywords: ['if', 'else if', 'var', 'this', 'alert', 'return', 'typeof', 'default', 'with', 'class', 'export', 'import', 'new'],
   method: ['Vue', 'React', 'html', 'css', 'js', 'webpack', 'babel', 'angular', 'bootstap', 'jquery', 'gulp','dom'],
   // special: ["*", ".", "?", "+", "$", "^", "[", "]", "{", "}", "|", "\\", "(", ")", "/", "%", ":", "=", ';']
  }
  function setHighLight(el) {
   var htmlStr = el.innerHTML;
   //匹配单行和多行注释
   var regxSpace = /(\/\/\s?[^\s]+\s?)|(\/\*(.|\s)*?\*\/)/gm,
    matchStrSpace = htmlStr.match(regxSpace),
    spaceLen;
   //匹配特殊字符
   var regxSpecial = /[`~!@#$%^&.{}()_\-+?|]/gim,
    matchStrSpecial = htmlStr.match(regxSpecial),
    specialLen;
   var flag = false;
   if(!!matchStrSpecial){
     specialLen = matchStrSpecial.length;
    }else{
     specialLen = 0;
     return;
    }
    for(var k = 0;k < specialLen;k++){
     htmlStr = htmlStr.replace(matchStrSpecial[k],'<span style="color:#b9ff01;">' + matchStrSpecial[k] + '</span>');
    }
   for (var key in lightColorCode) {
    if (key === 'keywords') {
     lightColorCode[key].forEach(function (imp) {
      htmlStr = htmlStr.replace(new RegExp(imp, 'gim'), '<span style="color:#00ff78;">' + imp + '</span>')
     })
     flag = true;
    } else if (key === 'importantObj') {
     lightColorCode[key].forEach(function (kw) {
      htmlStr = htmlStr.replace(new RegExp(kw, 'gim'), '<span style="color:#ec1277;">' + kw + '</span>')
     })
     flag = true;
    } else if (key === 'method') {
     lightColorCode[key].forEach(function (mt) {
      htmlStr = htmlStr.replace(new RegExp(mt, 'gim'), '<span style="color:#52eeff;">' + mt + '</span>')
     })
     flag = true;
    }
   }
   if (flag) {
    if (!!matchStrSpace) {
     spaceLen = matchStrSpace.length;
    } else {
     spaceLen = 0;
     return;
    }
    for(var i = 0;i < spaceLen;i++){
     var curFont;
     if(window.innerWidth <= 1200){
      curFont = '12px';
     }else{
      curFont = '14px';
     }
     htmlStr = htmlStr.replace(matchStrSpace[i],'<span style="color:#899;font-size:'+curFont+';">' + matchStrSpace[i] + '</span>');
    }
    el.innerHTML = htmlStr;
   }
  }
  var codes = document.querySelectorAll('.ew-code');
  for (var i = 0, len = codes.length; i < len; i++) {
   setHighLight(codes[i])
  }

 </script>
</body>
</html>

你可以狠狠点击此处 具体示例 查看效果。

不过这里为了方便,我还是使用插件 Prism.js ,另外在这里,我们还要用到将一个普通文本打造成 HTML 网页的插件 marked.js 。

接下来分析如何暂停动画和继续动画,很简单,就是清除定时器,然后重新调用即可。如何让编辑的代码生效呢,这就需要用到自定义事件 .sync 事件修饰符,自行查看官网 vue.js 。

虽然这里用原生 js 也可以实现,但我们用 vue-cli 结合组件的方式来实现,这样更简单一些。好了,让我们开始吧:

新建一个 vue-cli 工程(步骤自行百度):

新建一个 styleEditor.vue 组件,代码如下:

<template>
 <div class="container">
  <div class="code" v-html="codeInstyleTag"></div>
  <div class="styleEditor" ref="container" contenteditable="true" @input="updateCode($event)" v-html="highlightedCode"></div>
 </div>
</template>
<script>
 import Prism from 'prismjs'
 export default {
  name:'Editor',
  props:['code'],
  computed:{
   highlightedCode:function(){
    //代码高亮
    return Prism.highlight(this.code,Prism.languages.css);
   },
   // 让代码生效
   codeInstyleTag:function(){
    return `<style>${this.code}</style>`
   }
  },
  methods:{
   //每次打字到最底部,就要滚动
   goBottom(){
    this.$refs.container.scrollTop = 10000;
   },
   //代码修改之后,可以重新生效
   updateCode(e){
    this.$emit('update:code',e.target.textContent);
   }
  }
 }
</script>
<style scoped>
 .code{
  display:none;
 }
</style>

新建一个 resumeEditor.vue 组件,代码如下:

<template>
 <div class = "resumeEditor" :class="{htmlMode:enableHtml}" ref = "container">
  <div v-if="enableHtml" v-html="result"></div>
  <pre v-else>{{result}}</pre>
 </div>
</template>
<script>
 import marked from 'marked'
 export default {
  props:['markdown','enableHtml'],
  name:'ResumeEditor',
  computed:{
   result:function(){
    return this.enableHtml ? marked(this.markdown) : this.markdown
   }
  },
  methods:{
   goBottom:function(){
    this.$refs.container.scrollTop = 10000
   }
  }
 }
</script>
<style scoped>
 .htmlMode{
  anmation:flip 3s;
 }
 @keyframes flip{
  0%{
   opactiy:0;
  }
  100%{
   opactiy:1;
  }
 }
</style>

新建一个底部导航菜单组件 bottomNav.vue ,代码如下:

<template>
 <div id="bottom">
  <a id="pause" @click="pauseFun">{{ !paused ? '暂停动画' : '继续动画 ||' }}</a>
  <a id="skipAnimation" @click="skipAnimationFun">跳过动画</a>
  <p>
   <span v-for="(url,index) in demourl" :key="index">
    <a :href="url.url" rel="external nofollow" >{{ url.title }}</a>
   </span>
  </p>
  <div id="music" @click="musicPause" :class="playing ? 'rotate' : ''" ref="music"></div>
 </div>
</template>
<script>
 export default{
  name:'bottom',
  data(){
   return{
    demourl:[
     {url:'http://eveningwater.com/',title:'个人网站'},
     {url:'https://github.com/eveningwater',title:'github'}
    ],
    paused:false,//暂停
    playing:false,//播放图标动画
    autoPlaying:false,//播放音频
    audio:''
   }
  },
  mounted(){

  },
  methods:{
   // 播放音乐
   playMusic(){
    this.playing = true;
    this.autoPlaying = true;
    // 创建audio标签
    this.audio = new Audio();
    this.audio.src = "http://eveningwater.com/project/newReact-music-player/audio/%E9%BB%84%E5%9B%BD%E4%BF%8A%20-%20%E7%9C%9F%E7%88%B1%E4%BD%A0%E7%9A%84%E4%BA%91.mp3";
    this.audio.loop = 'loop';
    this.audio.autoplay = 'autoplay';
    this.$refs.music.appendChild(this.audio);
   },
   // 跳过动画
   skipAnimationFun(e){
    e.preventDefault();
    this.$emit('on-skip');
   },
   // 暂停动画
   pauseFun(e){
    e.preventDefault();
    this.paused = !this.paused;
    this.$emit('on-pause',this.paused);
   },
   // 暂停音乐
   musicPause(){
    this.playing = !this.playing;
    if(!this.playing){
     this.audio.pause();
    }else{
     this.audio.play();
    }
   }
  }
 }
</script>
<style scoped>
 #bottom{
  position:fixed;
  bottom:5px;
  left:0;
  right:0;
 }
 #bottom p{
  float:right;
 }
 #bottom a{
  text-decoration: none;
  color: #999;
  cursor:pointer;
  margin-left:5px;
 }
 #bottom a:hover,#bottom a:active{
  color: #010a11;
 }
</style>

接下来是核心 APP.vue 组件代码:

<template>
 <div id="app">
  <div class="main">
   <StyleEditor ref="styleEditor" v-bind.sync="currentStyle"></StyleEditor>
   <ResumeEditor ref="resumeEditor" :markdown = "currentMarkdown" :enableHtml="enableHtml"></ResumeEditor>
  </div>
  <BottomNav ref ="bottomNav" @on-pause="pauseAnimation" @on-skip="skipAnimation"></BottomNav>
 </div>
</template>
<script>
 import ResumeEditor from './components/resumeEditor'
 import StyleEditor from './components/styleEditor'
 import BottomNav from './components/bottomNav'
 import './assets/common.css'
 import fullStyle from './style.js'
 import my from './my.js'
 export default {
  name: 'app',
  components: {
   ResumeEditor,
   StyleEditor,
   BottomNav
  },
  data() {
   return {
    interval: 40,//写入字的速度
    currentStyle: {
     code: ''
    },
    enableHtml: false,//是否打造成HTML网页
    fullStyle: fullStyle,
    currentMarkdown: '',
    fullMarkdown: my,
    timer: null
   }
  },
  created() {
   this.makeResume();
  },
  methods: {
   // 暂停动画
   pauseAnimation(bool) {
    if(bool && this.timer){
     clearTimeout(this.timer);
    }else{
     this.makeResume();
    }
   },
   // 快速跳过动画
   skipAnimation(){
    if(this.timer){
     clearTimeout(this.timer);
    }
    let str = '';
    this.fullStyle.map((f) => {
     str += f;
    })
    setTimeout(() => {
     this.$set(this.currentStyle,'code',str);
    },100)
    this.currentMarkdown = my;
    this.enableHtml = true;
    this.$refs.bottomNav.playMusic();
   },
   // 加载动画
   makeResume: async function() {
    await this.writeShowStyle(0)
    await this.writeShowResume()
    await this.writeShowStyle(1)
    await this.writeShowHtml()
    await this.writeShowStyle(2)
    await this.$nextTick(() => {this.$refs.bottomNav.playMusic()});
   },
   // 打造成HTML网页
   writeShowHtml: function() {
    return new Promise((resolve, reject) => {
     this.enableHtml = true;
     resolve();
    })
   },
   // 写入css代码
   writeShowStyle(n) {
    return new Promise((resolve, reject) => {
     let showStyle = (async function() {
      let style = this.fullStyle[n];
      if (!style) return;
      //计算出数组每一项的长度
      let length = this.fullStyle.filter((f, i) => i <= n).map((it) => it.length).reduce((t, c) => t + c, 0);
      //当前要写入的长度等于数组每一项的长度减去当前正在写的字符串的长度
      let prefixLength = length - style.length;
      if (this.currentStyle.code.length < length) {
       let l = this.currentStyle.code.length - prefixLength;
       let char = style.substring(l, l + 1) || ' ';
       this.currentStyle.code += char;
       if (style.substring(l - 1, l) === '\n' && this.$refs.styleEditor) {
        this.$nextTick(() => {
         this.$refs.styleEditor.goBottom();
        })
       }
       this.timer = setTimeout(showStyle, this.interval);
      } else {
       resolve();
      }
     }).bind(this)
     showStyle();
    })
   },
   // 写入简历
   writeShowResume() {
    return new Promise((resolve, reject) => {
     let length = this.fullMarkdown.length;
     let showResume = () => {
      if (this.currentMarkdown.length < length) {
       this.currentMarkdown = this.fullMarkdown.substring(0, this.currentMarkdown.length + 1);
       let lastChar = this.currentMarkdown[this.currentMarkdown.length - 1];
       let prevChar = this.currentMarkdown[this.currentMarkdown.length - 2];
       if (prevChar === '\n' && this.$refs.resumeEditor) {
        this.$nextTick(() => {
         this.$refs.resumeEditor.goBottom()
        });
       }
       this.timer = setTimeout(showResume, this.interval);
      } else {
       resolve()
      }
     }
     showResume();
    })
   }
  }
 }
</script>
<style scoped>
 #app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
 }

 .main {
  position: relative;
 }

 html {
  min-height: 100vh;
 }

 * {
  transition: all 1.3s;
 }
</style>

到此为止,一个可以快速跳过动画,可以暂停动画,还有音乐播放,还能自由编辑代码的会动的简历已经完成,代码已上传至 git源码 ,欢迎 fork ,也望不吝啬 star 。

在线预览

总结

以上所述是小编给大家介绍的vue.js实现会动的简历(包含底部导航功能,编辑功能),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • vue.js 底部导航栏 一级路由显示 子路由不显示的解决方法

    最近利用vue第三方UI MuseUI开发webapp,然后在导航栏这里出现了问题,我需要在导航栏上的几个路由上显示底部导航栏,在其他路由上不显示,就这个问题,MuseUI的底部导航栏直接加载在app.vue里面,会每个页面都有导航栏,所以这种方式不可行,后来我真的使出了浑身解数,去MuseUI作者GitHub上面提问,无果,去segmentfault上面提问,无果,去vue官方群提问,无果,在提问之前,我都是经过一番搜索,思考的,但是这些都让我崩溃了.可能出错的地方从路由URL,museUI的

  • vue.js给动态绑定的radio列表做批量编辑的方法

    每个题目绑定的题目结构如下json对象,每次动态添加选项就是将其加入了vue实例的某个数组对象中: vm.options.push({ id: "", text: "新选项", checked: false }); 现在对radio或者checkbox集合列表进行批量添加,这里使用到了textarea容器. textare每一行都是一条数据,它的内部是根据回车来区分(break-word自动换行不算),每一行是一个对象,整体就是一个文本数组了,获取如下: var c

  • Vue.js 实现微信公众号菜单编辑器功能(二)

    Vue.js 实现微信公众号菜单编辑器功能(一)上一篇菜单的点击和添加菜单功能已经在模版实现了,接下来实现菜单的编辑功能 实现菜单删除方法 在vue实例中添加删除菜单方法,根据选中的菜单级别和索引来删除. methods: { //删除菜单 delMenu:function(){ //删除主菜单 if(this.selectedMenuLevel()==1&&confirm('删除后菜单下设置的子菜单也将被删除')){ if(this.selectedMenuIndex===0){ thi

  • vue.js做一个简单的编辑菜谱功能

    先给大家展示下效果图,如果感觉不错,请参考实现代码 1.先获取门店下的所有菜品类型.菜品名称.菜品id(list),也就是最大数据量 this.$http.post(ceshiApi+'getCyFoodAndFoodTypeForShopId',{shopId:this.shopId},{emulateJSON:true,credentials: true}).then(function(res){ if(res.data.type=='success'){ this.foodList = r

  • 详解vue.js移动端导航navigationbar的封装

    有几天没更新了,这几天上海天气比较热,天气一热就懒得写了.今天感觉还好,就写下导航部分的封装吧. 关于环境搭建和底部tabbar的封装请参考前面的两篇文章 web app和移动端原生app的构架方式不一样的,页面的切换是对整个页面的重新渲染.所以我们每个页面都有自己的导航条. 下面简单封装下导航条 html部分 此处写的导航的三个部分,分别是左边div.中间的title部分div.右边div.代码如下 <template> <header class="m-header&quo

  • Vue.js 实现微信公众号菜单编辑器功能(一)

    学习一段时间Vue.js,于是想尝试着做一个像微信平台里那样的菜单编辑器,在这里分享下 具体样式代码查看项目github 创建一个vue实例 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="https://cdn.bootcss.com/vue/2.5.9/vue.js"&g

  • Vue.js结合Ueditor富文本编辑器的实例代码

    在前端开发的项目中.难免会遇到需要在页面上集成一个富文本编辑器. 前一段时间公司Vue.js项目需要使用UEditor富文本编辑器,在百度上搜索一圈没有发现详细的说明,决定自己尝试,忙活了一天终于搞定了. 1. 总体思路 1.1 模块化 vue的很大的一个优势在于模块化,我们可以通过模块化实现页面和逻辑的复用.所以可以把Ueditor重新封装成一个.vue的模板文件.其他组件通过引入这个模板实现代码复用. 1.2 数据传输 首先父组件需要设置编辑器的长度.宽度.初始文本,这些数据可以通过prop

  • vue.js实现会动的简历(包含底部导航功能,编辑功能)

    在网上看到一个这样的网站,STRML它的效果看着十分有趣,如下图所示: 这个网站是用 react.js 来写的,于是,我就想着用 vue.js 也来写一版,开始撸代码. 首先要分析打字的原理实现,假设我们定义一个字符串 str ,它等于一长串注释加 CSS 代码,并且我们看到,当 css 代码写完一个分号的时候,它写的样式就会生效.我们知道要想让一段 CSS 代码在页面生效,只需要将其放在一对 <style> 标签对中即可.比如: <!DOCTYPE html> <html&

  • 使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能

    一.写在前面 1. Bootstrap是一个由 Twitter 开发和维护的前端框架,目前很受欢迎,Bootstrap中文网点击这里. 2. Vue.js 是一套构建用户界面的渐进式框架,点这里访问官网. 二.实现效果: 三.页面引入bootstrap.vue资源 <link rel="stylesheet" href="//cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.css" rel="e

  • vue.js使用v-model实现表单元素(input) 双向数据绑定功能示例

    本文实例讲述了vue.js使用v-model实现表单元素(input) 双向数据绑定功能.分享给大家供大家参考,具体如下: v-model 一般表单元素(input) 双向数据绑定 el:'#box',//这里放的是选择器. 不然会不生效 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>www.jb51.net vu

  • vue.js 图片上传并预览及图片更换功能的实现代码

    这里讲解是图片上传和图片预览.主要是围绕我们常用功能的列子做讲解 ,并且没有格外引入其他js 所以你复制过去做简单修改便可以看到效果 效果图: 样式以及效果图一并展示 1.HTML <div class="rz-picter"> <img :src="avatar" class="img-avatar"> <input type="file" name="avatar" id=

  • vue.js 实现图片本地预览 裁剪 压缩 上传功能

    以下代码涉及 Vue 2.0 及 ES6 语法. 目标 纯 javascrpit 实现,兼容ie9及以上浏览器,在本地做好文件格式.长宽.大小的检测,减少浏览器交互. 现实是残酷的,为了兼容Ie9 还是用上了 flash,第二篇来解释解释. 代码结构 <div id="wrap"> <label> 点我上传图片 <input type='file' @change="change" ref="input"> &

  • 详解打造 Vue.js 可复用组件

    Vue.js 是一套构建用户界面的渐进式框架.我们可以使用简单的 API 来实现响应式的数据绑定和组合的视图组件. 从维护视图到维护数据,Vue.js 让我们快速地开发应用.但随着业务代码日益庞大,组件也越来越多,组件逻辑耦合严重,使代码维护变得十分困难. 同时,Vue.js 的接口和语法十分自由,实现同一功能有若干种方法.每个人解决问题的思路不一样,写出来的代码也就不一样,缺乏团队内的规范. 本文旨在从组件开发的不同方面列举出合理的解决方法,作为建立组件规范的一个参考. 构成组件 组件,是一个

  • Vue.js基础指令实例讲解(各种数据绑定、表单渲染大总结)

    Vue.js 是一套构建用户界面的渐进式框架.他自身不是一个全能框架--只聚焦于视图层.因此它非常容易学习,非常容易与其它库或已有项目整合.在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用.他是基于AnjularJs 编写的,所以和前者的语法特别相似,却又使用简洁了很多. 那今天,我就给大家详细的说道说道这个 Vue.js ,以下是我们这次详解的目录,朋友们可以根据自己的情况选择性阅读,所有操作均附有代码实现. 1. Vue.js 如何绑定到页面中,使用他的功能. 2.

  • Vue.js通用应用框架-Nuxt.js的上手教程

    对于React,Vue构建的单页面应用老说,SEO是一个众所周知的问题.服务端渲染(SSR-server Side Render)是目前看来最好的解决办法.React应用有Next.js,对应Vue的解决方案就是Nuxt.js. 1.简介 官网:https://nuxtjs.org/ GitHub:https://github.com/nuxt/nuxt.js Nuxt.js 是什么? Nuxt.js 是一个基于 Vue.js 的通用应用框架. 通过对客户端/服务端基础架构的抽象组织,Nuxt.

  • Vue.js基础指令实例讲解(各种数据绑定、表单渲染大总结)

    Vue.js 是一套构建用户界面的渐进式框架.他自身不是一个全能框架——只聚焦于视图层.因此它非常容易学习,非常容易与其它库或已有项目整合.在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用.他是基于AnjularJs 编写的,所以和前者的语法特别相似,却又使用简洁了很多. 那今天,我就给大家详细的说道说道这个 Vue.js ,以下是我们这次详解的目录,朋友们可以根据自己的情况选择性阅读,所有操作均附有代码实现. 1. Vue.js 如何绑定到页面中,使用他的功能. 2.

  • Vue+Element实现网页版个人简历系统(推荐)

    这篇文章介绍一个使用Vue+Element实现的个人简历系统,主要用到的技术有:vue.element.css3.css定位. 作者在window10进行开发,目前只在chrome上进行过测试,没有大的毛病.但是还有很多小功能还不完善,代码也未进行优化,后续会继续完善功能,优化代码. 声明:项目相对来说就是一个纯静态页面,代码都比较简单,大佬可闭眼绕过,或者看一眼留下宝贵意见也可 一.项目介绍 本项目是一个网页版的个人简历系统,主要使用的技术为vue2+element进行实现. 个人简历系统 主

随机推荐