睁眼写BUG,闭眼改BUG。

Vue.js 入门

2020.03.02

So interesting !
It's very good !

...

Vue.js

什么是Vue.js

  • Vue.js 是目前最火的一个前端框架,React 是最流行的一个前端框架.都可以进行手机app开发,vue需要借助于Weex
  • vue,angular,react 前端三大主流框架
  • Vue.js 是一套构建用户界面的框架,只关注视图层,容易上手

框架和库的区别

  • 框架: 是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目
  • 库(插件): 提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其他库实现需求

Node(后端) 中的 MVC 与 前端中的 MVVM 之间的区别

  • MVC 是后端的分层开发概念
  • MVVM 是前端视图层的概念主要关注于 视图层分离,也就是说:MVVM把前端的视图层,分为了 三部分Model,View,VM ViewModel

Vue常用指令

var app = new Vue({
    el: '#app',//id为app的'对象'
    data: {
        name: 'A',//'对象'的属性
    }
})
//{{}}用来获取对象值
{{name}}
<script src="../lib/vue.js"></script>
<script src="js/main.js"></script>

1.v-for

var app = new Vue({
    el: '#app',
    data: {
        //foodList: ['葱','姜','蒜'],
        foodList: [
            {
                name: '葱',
                price: 10,
                discount: .8,
            },
            {
                name: '姜',
                price: 100,
                discount: .5,
            },
            {
                name: '蒜',
                price: 105,
                //discount: .6,
            },
        ],
    },
});
<div id="app">
    <ul>
        <li v-for="food in foodList">{{food.name}}:${{food.discount ? food.price * food.discount : food.price}}</li>
    </ul>
</div>

2.v-bind

var app = new Vue({
    el: '#app',
    data: {
        url: 'https://baidu.com',
        klass: 'btn btn-default',
        isActive: true,
    },
});
    <style>
        .active {
            background: red;
        }
    </style>

<div id="app">
    <!-- v-bind:class 相当于 :class-->
    <a v-bind:class="{active: isActive}" v-bind:href="url">点我</a>
</div>

3.v-on

var app = new Vue({
    el: '#app',
    data: {
    },
    methods: {
       onClick: function () {
           console.log('clicked');
       },

       onEnter: function () {
           console.log('mouse enter');
       },

       onOut: function () {
           console.log('mouse leave');
       },

       onSubmit: function () {
           //e.preventDefault();
           console.log('submitted');
       },

        onKeyup: function () {
            //e.preventDefault();
            console.log('key pressed');
        },

        onEnter: function () {
            //e.preventDefault();
            console.log('key enter');
        }
    }
});
<div id="app">
    <button v-on="{mouseenter: onEnter, mouseleave: onOut}" v-on:click="onClick">点我</button>
    <!--<form action="" v-on:submit="onSubmit($event)">-->
    <!--<form action="" v-on:keyup="onKeyup" v-on:submit.prevent="onSubmit()">-->
    <form action="" v-on:keyup.enter="onEnter" v-on:submit.prevent="onSubmit()">
        <!--v-on: 相当于 @-->
        <input type="text">
        <button type="submit">提交</button>
    </form>
</div>

4.v-model

  • 修饰符
var app = new Vue({
    el: '#app',
    data: {
        name: 'whh',
    },
    methods: {
    },

});
<div id="app">
    <input type="text" v-model="name">
    <input type="text" v-model.lazy="name"><!--lazy 懒惰一下,当鼠标拿开更新-->
    <input type="text" v-model.trim="name"><!--trim 去掉数据中所有空格-->
    <input type="text" v-model.number="name"><!--number 输出类型为number-->
    {{name}}
</div>
  • 在其他元素及类型上的用法
var app = new Vue({
    el: '#app',
    data: {
       //sex: 'female',
       //quxiang: ['male'],
        //article: 'Mr. Johnson had never been up in an aerophane before and he had read a lot about air accidents, so one day when a friend offered to take him for a ride in his own small phane, Mr. ',
        from: '',
        dest: '',
    },
    methods: {
    },

});
<div id="app">
    <!--<label>-->
        <!--男-->
        <!--<input v-model="sex" value="male" type="radio">-->
    <!--</label>-->
    <!--<label>-->
        <!--女-->
        <!--<input v-model="sex" value="female" type="radio">-->
    <!--</label><br>-->
    <!--{{sex}}-->
    <!--<br>-->
    <!--<label>-->
        <!--男-->
        <!--<input v-model="quxiang" value="male" type="checkbox">-->
    <!--</label>-->
    <!--<label>-->
        <!--女-->
        <!--<input v-model="quxiang" value="female" type="checkbox">-->
    <!--</label><br>-->
    <!--{{quxiang}}-->
    <!--<textarea v-model="article"></textarea>-->
    <div>你来自哪里?</div>
    <select v-model="from">
        <option value="1">王家沟</option>
        <option value="2">北京</option>
    </select>
    {{from}}
    <div>你要去哪里?</div>
    <select v-model="dest" multiple>
        <option value="1">王家沟</option>
        <option value="2">北京</option>
    </select>
    {{dest}}
</div>

5.v-if //控制流指令



计算属性

var app = new Vue({
    el: '#app',
    data: {
        math: 90,
        physics: 80,
        english: 30,
    },
    methods: {
    },
    computed: {
        sum: function () {
            return parseFloat(this.math + this.physics + this.english);
        },
        average: function () {
            return Math.round(this.sum / 3);
        },
    },
});
<div id="app">
    <table border="1">
        <thead>
        <th>学科</th>
        <th>分数</th>
        </thead>
        <tbody>
        <tr>
            <td>数学</td>
            <!--<td>{{math}}</td>-->
            <td><input type="text" v-model.number="math"></td>
        </tr>
        <tr>
            <td>物理</td>
            <!--<td>{{physics}}</td>-->
            <td><input type="text" v-model.number="physics"></td>
        </tr>
        <tr>
            <td>英语</td>
            <!--<td>{{english}}</td>-->
            <td><input type="text" v-model.number="english"></td>
        </tr>
        <tr>
            <td>总分</td>
            <!--<td>{{math + physics + english}}</td>-->
            <td>{{sum}}</td>
        </tr>
        <tr>
            <td>平均分</td>
            <!--<td>{{Math.round((math + physics + english) / 3)}}</td>-->
            <td>{{average}}</td>
        </tr>
        </tbody>
    </table>
</div>

组件

1.全局及局部组建

//组件
Vue.component('alert',{//01类似全局
    template: '<button @click="on_click">弹弹弹</button>',
    methods:{
        on_click: function () {
            alert('Yo.all');
        }
    }
});

//类似封装
var alert_comonent = {
    template: '<button @click="on_click">弹弹弹</button>',
    methods:{
        on_click: function () {
            alert('Yo.1.1');
        }
    }
}
var app = new Vue({
    el: '#seg1',
    components: {//02类似局部
        //组件
        alert: {
            template: '<button @click="on_click">弹弹弹</button>',
            methods:{
                on_click: function () {
                    alert('Yo.1');
                }
            }
        }
    },
    data: {
        //属性
    },
    methods: {
        //事件
    },
    computed: {
        //计算属性
    },
});
new Vue({
   el: '#seg2',//用的是全局
});
new Vue({
    el: "#seg3",//用的是局部封装
    components: {//02类似局部
        //组件
        alert: alert_comonent,
    },
})

<div id="seg1">
    <alert></alert>
</div>
<div id="seg2">
    <alert></alert>
</div>
<div id="seg3">
    <alert></alert>
</div>

2.配置组建

//两种方案 一种如下注释几行,另一种在html中写
Vue.component('like', {
    // template:
    //     `
    //         <button :class="{liked: liked}" @click="toggle_like()">
    //             👍 {{like_count}}
    //         </button>
    //     `,
    template: '#like_component_tpl',
    data: function () {
        return {
            like_count: 10,
            liked: false,
        }
    },
    methods: {
        toggle_like: function () {
            if (!this.liked){
                this.like_count++;
            }else{
                this.like_count--;
            }
            this.liked = !this.liked;
        }
    }
});

new Vue({
    el: '#app',
});
<div id="app">
    <like></like>
</div>
<template id="like_component_tpl">
    <button :class="{liked: liked}" @click="toggle_like()">
        👍 {{like_count}}
    </button>
</template>

3.组件通信

3.1父子通信

//Vue.component('alert',{
Vue.component('user',{
    //template: '<button @click="on_click">弹弹弹</button>',
    template: '<a :href="\'/user/\'+username">{{username}}</a>',
    //props: ['msg'],
    props: ['username'],
    methods:{
        //on_click: function () {
        //    alert(this.msg);
        //}
    }
});

new Vue({
    el: '#app',
});
<div id="app">
    <!--<alert msg="Yoooooo"></alert>-->
    <user username="whh"></user>
</div>

3.2子父通信*

Vue.component('balance',{
    template:`
        <div>
            <show @show-balance="show_balance"></show>//show_balace() 不加括号 默认传几个参数
            <div v-if="show">
                您的余额:
            </div>
        </div>
    `,
    data: function () {
        return {
            show: false
        };
    },
    methods: {
        show_balance: function (data) {
            this.show = true;
            console.log('data:', data);
        }
    }
});
Vue.component('show',{
    template: '<button @click="on_click()">显示余额</button>',
    methods: {
        on_click() {
            this.$emit('show-balance', {a: 1, b: 2});//这边传的值 相当于 传给data
        }
    }
});

new Vue({
    el: '#app',
});
<div id="app">
    <balance></balance>
</div>

3.3任意及平行组件间通信*

var Event = new Vue();

Vue.component('huahua',{
    template: `
    <div>
        我说:<input @keyup="on_change" v-model="i_said" type="text"/>
    </div>
    `,
    data: function () {
        return {
            i_said: '',
        }
    },
    methods: {
        on_change: function () {
            Event.$emit('huahua-said-something',this.i_said)
        }
    }
});
Vue.component('shuandan',{
    template: `<div>花花说:{{huahua_said}}</div>`,
    data: function () {
        return {
            huahua_said: '',
        }
    },
    mounted: function () {
        var me = this;
        Event.$on('huahua-said-something', function (data) {
            //console.log('data:', data);
            me.huahua_said = data;
        })
    }
});

new Vue({
    el: '#app',
});

过滤器

Vue.filter('meter',function (val,unit) {
    val = val || 0; //如果 val 不为空 显示val
    unit = unit || 'm';
    //return Math.round(val /1000) + unit;
    return (val /1000).toFixed(2) + unit;
});

Vue.filter('currency',function (val,unit) {
    val = val || 0; //如果 val 不为空 显示val
    unit = unit || '元';
    return val+unit;
});

new Vue({
    el: '#app',
    data: {
        price: 10,
        length: 10,
    }
});
<div id="app">
    <div>
        <input v-model="length" type="text">mm
        {{length | meter}}
    </div>
    <hr>
    <div>
        <input v-model="price" type="text">
        {{ price | currency('USD') }}
    </div>
</div>

自定义指令

1.基础配置

Vue.directive('pin', function (el, binding) {
    var pinned = binding.value;
    //console.log(pinned);
    if(pinned){
        el.style.position = 'fixed';
        el.style.top = '10px';
        el.style.left = '10px';
    }else{
        el.style.position = 'static';
    }
});

new Vue({
    el: '#app',
    data: {
        card1: {
            pinned: false,
        },
        card2: {
            pinned: false,
        }
    },
});
<div id="app">
    <div v-pin="card1.pinned" class="card">
        <button @click="card1.pinned = !card1.pinned">钉住/取消</button>
        mwy
    </div>
    <div v-pin="card2.pinned" class="card">
        <a href="#" @click="card2.pinned = !card2.pinned">pin it</a>
        dzz
    </div>
    sksksksdfa sf asf sf asf   
</div>

2.配置传参及修饰符

Vue.directive('pin', function (el, binding) {
    var pinned = binding.value;
    //console.log(pinned);
    var position = binding.modifiers; //modifiers 是用 . 传参
    //console.log(position);
    var warning = binding.arg; //arg 是用 : 传参

    if(pinned){
        el.style.position = 'fixed';

        for(var key in position){
            if(position[key]) {
                el.style[key] = '10px';
            }
        }

        if (warning === 'true') {
            el.style.background = 'yellow';
        }
    }else{
        el.style.position = 'static';
    }
});

new Vue({
    el: '#app',
    data: {
        card1: {
            pinned: false,
        },
        card2: {
            pinned: false,
        }
    },
});
<div id="app">
    <div v-pin:true.bottom.right="card1.pinned" class="card">
        <button @click="card1.pinned = !card1.pinned">钉住/取消</button>
        mwy
    </div>
    <div v-pin.bottom.left="card2.pinned" class="card">
        <a href="#" @click="card2.pinned = !card2.pinned">pin it</a>
        dzz
    </div>
    sksksksdfa sf asf sf asf   sdafasfasfasf 
</div>

混合 mixins

没用minxins时 //很多重复内容

Vue.component('tooltip',{
    //提示框
    template:`
    <div>
        <span @mouseenter="show" @mouseleave="hide">bys</span>
        <div v-if="visible">
        daizhouzhoushilaji dalaji
        </div>
    </div>
    `,
    methods: {
        show: function () {
            this.visible = true;
        },
        hide: function () {
            this.visible = false;
        }
    },
    data: function () {
        return {
            visible: false,
        }
    }
});

Vue.component('popup',{
    //弹出层
    template: `
    <div>
        <button @click="toggle">Popup</button>
        <div v-if="visible">
            <span @click="hide">X</span>
            <h4>title</h4>
            mwy&dzz
        </div>
    </div>
    `,
    methods: {
        toggle: function () {
            this.visible = !this.visible;
        },
        hide: function () {
            this.visible = false;
        }
    },
    data: function () {
        return {
            visible: false,
        }
    },
});
new Vue({
    el: '#app',
    data: {

    },
});
<div id="app">
    <popup></popup>
    <hr>
    <tooltip></tooltip>
</div>

用了之后👇 //自己领悟

var base = {
    methods: {
        show: function () {
            this.visible = true;
        },
        hide: function () {
            this.visible = false;
        },
        toggle: function () {
            this.visible = !this.visible; //每点击一次按钮 值变反
        }
    },
    data: function () {
        return {
            visible: false,
        }
    }
}

Vue.component('tooltip',{
    //提示框
    template:`
    <div>
        <span @mouseenter="show" @mouseleave="hide">bys</span>
        <div v-if="visible">
        daizhouzhoushilaji dalaji
        </div>
    </div>
    `,
    mixins: [base],
    data: function () { //在这边重新定义 visible值 覆盖 mixins中的值 =默认打开
        return {
            visible: true,
        }
    }
});

Vue.component('popup',{
    //弹出层
    template: `
    <div>
        <button @click="toggle">Popup</button>
        <div v-if="visible">
            <span @click="hide">X</span>
            <h4>title</h4>
            mwy&dzz
        </div>
    </div>
    `,
    mixins: [base]
});
new Vue({
    el: '#app',
    data: {

    },
});
<div id="app">
    <popup></popup>
    <hr>
    <tooltip></tooltip>
</div>

插槽 slots

<style>
        .panel{
            max-width: 300px;
            border: 1px solid #999;
            margin-bottom: 15px;
        }

        .panel > * {
            padding:15px;
        }
        .panel .title{
            border-bottom: 1px solid #999;
        }

        .panel .footer{
            border-top: 1px solid #999;
        }
    </style>

Vue.component('panel',{
    template: '#panel-tpl',
});

new Vue({
    el: '#app',
    data: {

    },
});
<div id="app">
    <panel></panel>
</div>
<template id="panel-tpl">
    <div class="panel">
        <div class="title">Yo.</div>
        <div class="content">
            ds sdf sdf<br>
            sdfsf,<br>
            手动阀十分
        </div>
        <div class="footer">more</div>
    </div>
</template>

Vue.component('panel',{
    template: '#panel-tpl',
});

new Vue({
    el: '#app',
    data: {

    },
});
<div id="app">
    <panel>
        <div slot="title">
            Yo.
        </div>
        <div slot="content">
            Young yo yo
        </div>
        <!--<div slot="footer">-->
            <!--&lt;!&ndash;more..&ndash;&gt;-->
        <!--</div>-->
    </panel>
    <panel>Young yo yo1</panel>
</div>
<template id="panel-tpl">
    <div class="panel">
        <div class="title">
            <slot name="title"></slot>
        </div>
        <div class="content">
            <slot name="content"></slot>
        </div>
        <div class="footer">
            <slot name="footer">more..*</slot>
        </div>
    </div>
</template>