Vue2.0基础学习--- 一个简单的实例学习

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue2.0基础学习--- 一个简单的实例学习相关的知识,希望对你有一定的参考价值。

  看完vue 的官方文档,再做一个简单的实例是最好不过了,既能巩固我们所学的知识,又能学以致用。infoq上推荐了一篇文章,面向重度 jQuery 开发者的 Vue.js 介绍, 它是老外写的,用vue做了一个简单的实例,非常适合学完vue文档来练练手,我这里并没有翻译文档,而是做了几次后,自已的思路。

  首先看一下这个实例长什么样子,有什么功能

技术分享

  上面是一个文本框,用于输入内容,但最多只能输入140个字,所以右下角会有字数提示。当用户进行输入的时候,右下角的数字不断变化,提示用户还剩多少字可以输入。当剩余字数小于20 的时候,它会示浅红色,当剩余字数小于10 的时候,它会显示深红色,通过颜色的变化来做出提醒。当字数小于0的时候,提示超出限制,同时右侧的按钮也会进行相应的变化,当文本框中没有内容时和超出字数时都会禁用。

  当点击下面的照相机图标,会弹出选择图片对话框,选择图片后,文本框的下面就会显示我们选中的图片,同时图片上面有一个×号,用于删除图片, 应用会变成以下显示

技术分享

  由示这个例子比较简单,直接用一个html文件来写就可以了,样式的话,我们用Bootstrap, 首先在文件中引入Bootstrap的css 样式,再引入 vue.min.js,  自己写的样式放到style标签中,js 文件放到script 标签中。大体的框架如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 学习实例</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <style>
        body {
            padding-top: 100px;
        }
        .row {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2 class="text-center">创建你的微博</h2>
        <textarea class="form-control" rows="3"></textarea>
        <div class="row">
            <div class="col-md-10">
                <label class="glyphicon glyphicon-camera" for="xFile"></label>
                <input type="file" id="xFile" style="position:absolute;clip:rect(0 0 0 0);">
            </div>
            <div class="col-md-2">
                <span>30</span>
                <button type="button" class="btn btn-primary">转发</button>
            </div>
        </div>
    </div>
<!--所有js都放在以下script标签中-->
<script>

</script>

  页面中显示内容如下,不是太好看

技术分享

  vue 应用都是通过vue根实例启动的,就是vue的构造函数,它里面有一个el 属性,表示挂载元素,那首先要定义一个挂载元素,一般都是最外层元素,给最外层class=‘container’的最外层元素加一个id, 为weibo. 

  我们先来实现第一个功能,就是输入框中输入内容时,右下角的字数和按钮会发生相应的变化, 由于所有的变化都是基于输入框中的内容,首先我们要获取到输入框中的内容, vue 提供了v-model指令,可以很轻松地实现。获取到内容后,怎么实现更新字数,vue 提供了 computed 属性,可以基于一个变化得到另外的变化。给textarea 加一个v-model=“content” 指令,将用户输入的内容绑定到content变量,再建一个变量 letterRemaining 显示剩余的字数,这时<span>30</span> 就要变成{{letterRemaining}}来动态显示剩于字数,由于剩余字符是基于最大字数限制,所以还要声明一个常量MAX_LETTER_LENGTH =140来表示最大字数。

  html 内容更改如下:

<div class="container" id="weibo"> <!--添加一个id 提供挂载-->
    <h2 class="text-center">创建你的微博</h2>
    <textarea class="form-control" rows="3" v-model="content"></textarea> <!--v-model数据绑定-->
    <div class="row">
        <div class="col-md-10">
            <label class="glyphicon glyphicon-camera" for="xFile"></label>
            <input type="file" id="xFile" style="position:absolute;clip:rect(0 0 0 0);">
        </div>
        <div class="col-md-2">
            <span>{{letterRemaining}}</span> <!--动态显示剩余字数-->
            <button type="button" class="btn btn-primary">转发</button>
        </div>
    </div>
</div>

  script 添加以下内容

<script>
    const MAX_LETTER_LENGTH = 140;  //最大输入字数 140
    new Vue({
        el:"#weibo",
        data: {
            content:‘‘  // 获得用户输入的内容
        },
        computed: {
            // 计算剩余字数
            letterRemaining:function() {
                return MAX_LETTER_LENGTH - this.content.length;
            }
        }
    })
</script>

  最基本的输入和字数变化已经实现了,但还有当剩余字数小于20, 和小于10的时候,给用户以颜色提示。Bootstrap 中有两个样式类,text-warning, text-danger 可以提供相应的样式,也就是说,当字数变化时要动态改变样式,这时想到v-bind:class指令,可以动态绑定。这个指令可以接受一个对象 {text-warning: isWaring}, text-waring 类取决于后面的变量,如果isWaring 取值为ture, 元素就有text-waring类,否则没有。因此我们这里还要新两个变量,表示小于20和小于10, 由于这两个变量也是基于输入的内容,所以它们也是计算属性,变量名分别为under20, under10. html中的span 也要加上v-bind:class指令

  html中的span 加上v-bind:class指令

<!--v-bind指令,动态改变样式-->
<span v-bind:class="{ ‘text-warning‘:under20, ‘text-danger‘: under10}">{{letterRemaining}}</span> 

  script 中的computed属性添加两个新属性

     computed: {
            // 计算剩余字数
            letterRemaining:function() {
                return MAX_LETTER_LENGTH - this.content.length;
            },
            // 小于20个字符
            under20: function(){
                return this.letterRemaining <= 20 && this.letterRemaining > 10;
            },
            // 小于10个字符
            under10: function() {
                return this.letterRemaining <= 10 && this.letterRemaining > 0;
            }
        }

  这时你输入字符的时候,当小于10和小于20时,它会出现颜色的变化,但是当我们一直输入下去的时候,它会显示负数,且可以一直输入下去,和我们的字数限制不符,原来是想用js 解决这个问题的,但一直没有想到更好的办法,突然想到textarea 有一个属性是maxlength ,它就是规定最多输入多少字符,当超过它的限制,不能输入,也就是说,我们的剩余字数提示不会是负数,最小是是0,只不过,当输入到140个字符的时候,要给用户一个提示,这里就用alert 提示一个。

  现在要做两个修改,一个是textarea 增加一个maxlength属性,

<textarea class="form-control" rows="3" v-model="content" maxlength="140"></textarea> <!--增加maxlength属性,最大字数限制-->

  再一个是提示用户 alert 框, 我这里是把 letterRemaining 增加了一个if 条件判断

letterRemaining:function() {
    var remain = MAX_LETTER_LENGTH - this.content.length;
    if(remain == 0){
         alert(‘最多输入140个字符‘)
    }
    return remain;
}

  最后就是按钮的处理,当输入框中没有内容的时候,它是禁用的,只有输入内容后才能使用,它也是跟随输入框中的内容来回切换,正好button 有个disabled属性,取值true 或false, 我们可以把这个disabled属性绑定到一个变量上,而变量的取值也是true or false, 那这个变量还得是计算属性,因为它基于输入框的内容,而true or false 的取值也非常简单,因为只要输入框中有内容就是true, 没有内容就是false .现在再增加一个计算属性 contentIsEmpty,  同时让button 的disabled属性绑定到它上面

<button type="button" class="btn btn-primary" :disabled="contentIsEmpty">转发</button>
computed: {
   ......// 输入框中没有没内容
   contentIsEmpty:function(){
        return this.content.length == 0
    }
}

  应用的第一个功能已经做完了,相对简单

  现在开始第二个功能,当有图片上传时,文本框中下面显示图片,没有图片时,不显示,很明显,这要用v-if指令控制组件的显示和隐藏。其次,我们应用中应该有一个变量来存放图片,从而可以在html模版中进行引用来显示图片。假设可以上传多张图片, 所以我们在data中定义一个变量photos 为一个数组,默认为空数组。数组中的内容怎么才能显示到页面中,这要用到v-for指令。当有图片时,也就是photos.length 大于0 的时候,所以这时还需要一个计算属性来控制显示和隐藏 photoUploaded。根据描述,大体就是能写出这个组件了。

首先是一个div包括着图片和删除按钮,它有一个v-if指令,里面是figure 标签拥有v-for 指令进行循环,在text area下面增加 以下内容,这里还增加了删除功能,remove 方法后面写

 <!--图片显示区域-->
    <div class="row" v-if="photoUploaded">
        <div class="col-md-12">
            <figure v-for="(photo,index) in photos">
                <img :src="photo" class="img-rounded">
                <button type="button" class="close" @click=‘remove(index)‘>&times;</button>
            </figure>
        </div>
    </div>

  现在剩下怎么获得用户选图片,首先,input = file 还可增加一个 multiple 属性才能上传多个图片,其次,上传图片会change事件,我们监听change 事件就可以了, 上传成功后,它会存在input dom 对象中的flies属性中,最后, 我们把这个文件用base64 来进行读取,它们分别是html5 file  API 和fileReader API . 在html中input= file 修改如下:

<input type="file" multiple @change="upload" id="xFile" style="position:absolute;clip:rect(0 0 0 0);">

  js 中增加upload方法,还有上面还说到remove 方法

methods:{
            upload:function(e){
                var that = this;
                var files = Array.from( e.target.files);
                
                files.forEach(function(file) {
                    var fileReader = new FileReader();
                    fileReader.onload = function(evt){
                        that.photos.push(evt.target.result) 
                    }
                    fileReader.readAsDataURL(file)
                });
            },
            remove: function(index){
                this.photos.splice(index,1)
            }
        }

  忘记了,data中还要增加一个photos 变量来存放我们上传的图片

data: {
            content: ‘‘, // 获得用户输入的内容
            photos: []   // 存取用户上传的图片
        },

  这时点击照相机按钮,弹出对话框,选择几张图片,点确定,可以看到输入框下面有图片显示,不过它是竖着显示,不是横向显示,样式有点问题,我就不调整了,点击右上角的关闭按钮,可以删除图片,功能完成了。  

  整个文件内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue 学习实例</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <style>
        body {
            padding-top: 100px;
        }
        .row {
            margin-top: 20px;
        }
    </style>
</head>
<body>
<div class="container" id="weibo"> <!--添加一个id 提供挂载-->
    <h2 class="text-center">创建你的微博</h2>
    <!--输入框区域-->
    <textarea class="form-control" rows="3" v-model="content" maxlength="10"></textarea> <!--增加maxlength属性,最大字数限制 v-model数据绑定-->

    <!--图片显示区域-->
    <div class="row" v-if="photoUploaded">
        <div class="col-md-12">
            <figure v-for="(photo,index) in photos">
                <img :src="photo" class="img-rounded">
                <button type="button" class="close" @click=‘remove(index)‘>&times;</button>
            </figure>
        </div>
    </div>

    <!--照相机按钮和字符数提示-->
    <div class="row">
        <div class="col-md-10">
            <label class="glyphicon glyphicon-camera" for="xFile" ></label>
            <input type="file" multiple @change="upload" id="xFile" style="position:absolute;clip:rect(0 0 0 0);">
        </div>
        <div class="col-md-2">
            <!--v-bind指令,动态改变样式-->
            <span v-bind:class="{ ‘text-warning‘:under20, ‘text-danger‘: under10}">{{letterRemaining}}</span> 
            <button type="button" class="btn btn-primary" :disabled="contentIsEmpty">转发</button>
        </div>
    </div>
</div>
<!--所有js都放在以下script标签中-->
<script>
    const MAX_LETTER_LENGTH = 10;  //最大输入字数 140
    new Vue({
        el:"#weibo",
        data: {
            content: ‘‘, // 获得用户输入的内容
            photos: []   // 获取用户上传的图片
        },
        computed: {
            // 计算剩余字数
            letterRemaining:function() {
                var remain = MAX_LETTER_LENGTH-this.content.length;
                if(remain == 0){
                    alert(最多输入140个字符)
                }
                return remain;
            },
            // 小于20个字符
            under20: function(){
                return this.letterRemaining <= 20 && this.letterRemaining > 10;
            },
            // 小于10个字符
            under10: function() {
                return this.letterRemaining <= 10 && this.letterRemaining > 0;
            },
            // 输入框中有没有内容
            contentIsEmpty:function(){
                return this.content.length == 0
            },
            //有没有上传图片
            photoUploaded:function(){
                return this.photos.length > 0
            }
        },
        methods:{
       // 图片上传处理函数, 用到了h5 File 和FileReader API upload:
function(e){ var that = this; var files = Array.from( e.target.files); files.forEach(function(file) { var fileReader = new FileReader(); fileReader.onload = function(evt){ that.photos.push(evt.target.result) } fileReader.readAsDataURL(file) }); },
       // 删除图片处理函数 remove:
function(index){ this.photos.splice(index,1) } } }) </script> </body> </html>

 




以上是关于Vue2.0基础学习--- 一个简单的实例学习的主要内容,如果未能解决你的问题,请参考以下文章

学习vue2.0

vue2.0学习笔记之webpack-simple模板中的路由简单配置案例

vue2.0学习-实例和内置组件

vue2.0 路由学习笔记

vue2.0学习笔记之生命周期

学习 vue2.0/3.0 中的proxy和Object.defineProperty 小记