Vue.js的学习记录

Vue简介

相关链接

VSCode官网
vue.js官网
axiso官网
axiso下载链接
vue.router官网
vue-router.js下载链接
免费Http请求测试数据链接
animate.css官网
bootstrap官网
bootstrap-4.3.1下载链接
Node.js 安装包及源码下载链接
webpack官网
OpenIconic图标官网
MUI下载链接
码云项目代码托管平台
vee-validate官网
vue-layzload官网
vuejs-dialog官网

Vue开发环境搭建

VSCode与插件安装

  • Express
  • HTML Snippets
  • Bootstrap v4 Snippets
  • One Dark Pro
  • Preview on Web Server
  • TabOut
  • vscode-icons
  • Vue 2 Snippets
  • vue-beautify

Chrome插件安装

  • Vue.js devtools

Node.js及webpack相关安装

  • 下载Node.js 的window安装包并安装
  • 安装完成后打开cmd输入: node --version
  • 安装nrm,cmd输入 : npm install -g nrm
  • 查看镜像,输入: nrm ls
    在这里插入图片描述
  • cmd输入: nrm use cnpm
  • webpack、webpack-cli、webpack-dev-server全局安装,cmd输入:
npm install webpack webpack-cli webpack-dev-server -g
  • 检查安装结果与版本号
    在这里插入图片描述

用户自定义代码段快捷键

  1. 打开设置界面:File -> Preferences ->User Snippets
  2. 选择html.json
  3. 粘贴下面的代码段保存即可
{
	"vh":{
		"prefix": "vh",
		"body": [
			"<!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>Document</title>",
			"    <script src=\"./lib/vue.js\"></script>",
			"</head>",
			"",
			"<body>",
			"    <div id=\"app\">",
			"",
			"    </div>",
			"",
			"    <script>",
			"        var vm = new Vue({",
			"            el: '#app',",
			"            data: {",
			"            },",
			"            methods: {",
			"            }",
			"        })",
			"    </script>",
			"</body>",
			"",
			"</html>"			
		]
	}
}

.vue后缀文件启用html语法补全

  1. 按F1,输入settings.json并选择Open Settings(JSON)
  2. 在settings.json中添加files.associations,内容如下
{
    "files.associations": {
        "*.vue":"html"
    }
}

Vue上手

vue对象实例

  1. el:指定要控制的区域
  2. data:是一个对象,指定控制区域内要用的到的数据
  3. methods:是一个对象,方法集,可以自定义方法
  • VM实例中,如果要访问data上的数据,或者要访问methods中的方法,必须使用this
<script>
        new Vue({
            el: '#app',
            data: {
                msg: 'world',
            },
            methods: {
                show:function(){
                    alert("hello")
                }
            },
        })
    </script>

基本指令

  1. 插值表达式和v-text
  2. v-cloak
  3. v-html
  4. v-bind 属性绑定 缩写是:
  5. v-on 事件绑定 缩写是@
  6. v-model 数据双向绑定

Vue生命周期钩子

官方文档链接:实例生命周期钩子

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted
  5. beforeUpdate
  6. updated
  7. beforeDestroy
  8. destroyed

Vue练习案例

基本指令练习

<!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>Document</title>
    <script src="./lib/vue.js"></script>

    <style>
        [v-cloak] {
            display: none;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- 使用v-cloak能够解决 插值表达式闪烁的问题 -->
        <p v-cloak>{{ msg }}</p>
        <h4 v-text="msg"></h4>
        <div v-html="msg2"></div>

        <!-- v-bind:是Vue中提供用于绑定属性的指令 -->
        <!-- v-bind:可以简写为 : -->
        <input type="button" value="按钮" v-bind:title="mytitle + '123'" id="btn">
        <input type="button" value="按钮" :title="mytitle + '123'" v-on:click="show">
        <!-- v-model:可以实现表单元素与Model中数据的双向绑定 -->
        <input type="text" v-model="msg">
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                msg: 'world',
                msg2: '<h1>html元素添加</h1>',
                mytitle: '这是自定义title'
            },
            methods: {
                show:function(){
                    alert("hello")
                }
            },
        })
    </script>
</body>

</html>

事件修饰符

  1. .stop
  2. .prevent
  3. .capture
  4. .self
  5. .once
<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <style>
        .inner {
            height: 150px;
            background-color: darkcyan;
        }

        .outer {
            padding: 40px;
            background-color: red;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- 使用.stop阻止冒泡 -->
        <div class="inner" @click="divInnerHandler">
            <input type="button" value="点击我" @click.stop="btnHandler">
        </div>
        <!-- 使用.prevent阻止默认行为 -->
        <a href="http://www.baidu.com" @click.prevent="linkClick">有问题,问百度(阻止默认行为)</a>

        <!-- 使用.capture实现捕获触发事件 -->
        <div class="inner" @click.capture="divInnerHandler">
            <input type="button" value="点击我" @click="btnHandler">
        </div>

        <!-- 使用.once 只触发一次事件-->
        <a href="http://www.baidu.com" @click.prevent.once="linkClick">有问题,问百度(阻止默认行为且只触发一次)</a>

        <!-- 使用.self 实现只有点击当前元素时才触发事件,只会阻止自己冒泡,不阻止其他元素的冒泡-->
        <div class="outer" @click="divOuterHandler">
            <div class="inner" @click.self="divInnerHandler">
                <input type="button" value="点击我" @click="btnHandler">
            </div>
        </div>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
            },
            methods: {
                btnHandler() {
                    console.log("你触发了 btn 按钮 点击事件");
                },
                divInnerHandler() {
                    console.log("你触发了 inner 按钮 点击事件");
                },
                divOuterHandler() {
                    console.log("你触发了 outer 按钮 点击事件");
                },
                linkClick() {
                    console.log("你触发了 link 点击事件");
                }
            }
        })
    </script>
</body>

</html>

Vue中的样式

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <style>
        .red {
            color: red;
        }

        .thin {
            font-weight: 200;
        }

        .italic {
            font-style: italic;
        }

        .active {
            letter-spacing: 0.5em;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- 这里的class需要使用v-bind做数据绑定 -->
        <h1 :class="['red','thin', flag?'active':'']">这是一个很大的H1,通过绑定class来改变我的样式</h1>
        <h1 :class="['red','thin', {active:flag}]">这是一个很大的H1,通过绑定class来改变我的样式</h1>
        <h1 :class="{red:false, thin:true, italic:false, active:false}">这是一个很大的H1,通过绑定class来改变我的样式</h1>
        <h1 :class="classObj">这是一个很大的H1,通过绑定class来改变我的样式</h1>

        <h1 :style="{color:'red','font-size':'40px'}">这是一个很大的H1,通过绑定class来改变我的样式</h1>
        <h1 :style="styleObj1">这是一个很大的H1,通过绑定class来改变我的样式</h1>
        <h1 :style="[styleObj1,styleObj2]">这是一个很大的H1,通过绑定class来改变我的样式</h1>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                flag: true,
                classObj: {red:false, thin:true, italic:false, active:false},
                styleObj1: {color:'red','font-size':'40px'},
                styleObj2: {'font-style': 'italic'}
            },
            methods: {
            }
        })
    </script>
</body>

</html>

v-for / v-if / v-show

*v-for 注意使用key属性

<!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>Document</title>
    <script src="./lib/vue.js"></script>
</head>

<body>
    <div id="app">
        <!-- 遍历数组 -->
        <!-- <p v-for="(item,i) in list">索引值:{{i}} --- id:{{item.id}} --- 名字:{{item.name}}</p> -->
        <!-- 遍历对象键值对 -->
        <!-- <p v-for="(val,key,i) in user">值:{{val}} --- 键:{{key}} --- 索引:{{i}}</p> -->
        <!-- 迭代数字 count从1开始-->
        <!-- <p v-for="count in 6">这是第{{count}}此循环</p> -->

        <div>
            <label>Id:
                <input type="text" v-model="id">
            </label>
            <label>Name:
                <input type="text" v-model="name">
            </label>
            <input type="button" value="添加" @click="add">
        </div>

        <!-- v-for循环时,key属性只能使用number或string -->
        <!-- key属性必须使用v-bind绑定,指定key的值 -->
        <p v-for="item in list" :key="item.id">
            <input type="checkbox">
            {{item.name}}
        </p>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                id:'',
                name:'',
                list: [
                    { id: 1, name: '萧薰儿' },
                    { id: 2, name: '小医仙' },
                    { id: 3, name: '美杜莎' },
                    { id: 4, name: '云韵' },
                    { id: 4, name: '雅妃' },
                ],
                user: {
                    id: 1,
                    name: '萧炎',
                    gender: '男'
                },
                flag
            },
            methods: {
                add(){
                    this.list.unshift({id:this.id, name:this.name})
                }
            }
        })
    </script>
</body>

</html>

过滤器的基本用法

<!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>Document</title>
    <script src="./lib/vue.js"></script>
</head>

<body>
    <div id="app">
        <p>{{ msg | msgFormat('邪恶') | append('!!!')}}</p>
    </div>

    <div id="app2">
        <p>{{ msg | msgFormat('疯狂') | append('!!!')}}</p>
    </div>
    <script>
        //定义全局过滤器
        Vue.filter('msgFormat', function (msg, arg) {
            // 方法1
            // return msg.replace('单纯','邪恶')
            // 方法2:正则
            return msg.replace(/单纯/g, arg)
        })

        Vue.filter('append', function (msg, arg) {
            return msg + arg;
        })

        var vm = new Vue({
            el: '#app',
            data: {
                msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的人'
            },
            methods: {
            }
        })

        var vm2 = new Vue({
            el: '#app2',
            data: {
                msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的人'
            },
            methods: {},
            filters: {
                // 定义私有过滤器,[过滤器名称:处理函数]
                // 过滤器调用时采用就近原则,如果私有过滤器和全局过滤器重名,优先调用私有过滤器
                msgFormat: function (msg, arg) {
                    return msg.replace(/单纯/g, arg) + '~~~'
                }
            }

        })
    </script>
</body>

</html>

跑马灯效果

<!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>Document</title>
    <script src="./lib/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="button" value="浪起来" @click="lang">
        <input type="button" value="低调" @click="stop">
        <h4>{{msg}}</h4>
    </div>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                msg: '猥琐,别浪~~! ',
                intervalId: null
            },
            methods: {
                lang() {
                    if (this.intervalId != null) return;

                    this.intervalId = setInterval(() => {
                        var start = this.msg.substring(0, 1)
                        var end = this.msg.substring(1)
                        this.msg = end + start;
                    }, 100)
                },
                stop() {
                    clearInterval(this.intervalId)
                    this.intervalId = null;
                }
            },
        })
    </script>
</body>

</html>

简易计算器

<!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>Document</title>
    <script src="./lib/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="n1">

        <select v-model="opt">
            <option value="+">+</option>
            <option value="-">-</option>
            <option value="*">*</option>
            <option value="/">/</option>
        </select>

        <input type="text" v-model="n2">
        <input type="button" value="=" @click="calc">
        <input type="text" v-model="result">
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                n1: 0,
                n2: 0,
                result: 0,
                opt: '+'
            },
            methods: {
                calc() {
                    switch (this.opt) {
                        case '+':
                            this.result = parseInt(this.n1) + parseInt(this.n2)
                            break;
                        case '-':
                            this.result = parseInt(this.n1) - parseInt(this.n2)
                            break;
                        case '*':
                            this.result = parseInt(this.n1) * parseInt(this.n2)
                            break;
                        case '/':
                            this.result = parseInt(this.n1) / parseInt(this.n2)
                            break;
                        default:
                            break;
                    }

                    //取巧方式
                    // var codeStr = 'parseInt(this.n1)' + this.opt + 'parseInt(this.n2)'
                    // this.result = eval(codeStr);
                }
            }
        })
    </script>
</body>

</html>

axios基本使用

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <script src="./lib/axios.js"></script>
</head>

<body>
    <div id="app">
        <input type="button" value="get请求" @click="getInfo">
        <input type="button" value="post请求" @click="postInfo">
    </div>

    <script>
        var http = axios.create({
            baseURL: 'http://jsonplaceholder.typicode.com'
        })

        var vm = new Vue({
            el: '#app',
            data: {
            },
            methods: {
                getInfo() {
                    // 不带参数
                    http.get('users').then(function (response) {
                        console.log(response)
                    }).catch(function (response) {
                        console.log(response)
                    })

                    // 带参数
                    http.get('users', { params: { username: 'test' } }).then(function (response) {
                        console.log(response)
                    }).catch(function (response) {
                        console.log(response)
                    })
                },
                postInfo() {
                    http.post('users', { username: 'test', password: 123456 }).then(function (response) {
                        console.log(response)
                    }).catch(function (response) {
                        console.log(response)
                    })
                }
            }
        })
    </script>
</body>

</html>

品牌列表案例

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <link rel="stylesheet" href="./css/bootstrap.min.css">
</head>

<body>
    <div id="app">
        <div class="card">
            <div class="card-header">
                <span v-fontweight="900" v-fontsize="'30px'">添加品牌</span>
            </div>
            <div class="card-body form-inline">
                <label>Id:
                    <input type="text" class="form-control" v-model="id">
                </label>
                <label>Name:
                    <!-- 使用按钮修饰符 -->
                    <input type="text" class="form-control" v-model="name" @keyup.enter="add">
                </label>
                <input type="button" value="添加" class="btn btn-primary" @click="add">
                <label>搜索名称关键字:
                    <input type="text" class="form-control" v-model="keywords" v-focus v-color="'blue'">
                </label>
            </div>
        </div>

        <table class="table table-light table-bordered table-hover table-striped">
            <thead class="thead-light">
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Ctime</th>
                    <th>Operation</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="item in search(keywords)" :key="item.id">
                    <td>{{item.id}}</td>
                    <td v-text="item.name"></td>
                    <td>{{ item.ctime | DateFormat }}</td>
                    <td>
                        <a href="" @click.prevent="del(item.id)">删除</a>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>

    <script>
        //定义全局过滤器
        Vue.filter('DateFormat', function (DateStr, pattern = "") {
            var dt = new Date(DateStr)
            var y = dt.getFullYear()
            var m = (dt.getMonth() + 1).toString().padStart(2, '0')
            var d = (dt.getDate()).toString().padStart(2, '0')

            if (pattern.toLowerCase() === 'yyy-mm-dd') {
                return `${y}-${m}-${d}`
            } else {
                var hh = (dt.getHours()).toString().padStart(2, '0')
                var mm = (dt.getMinutes()).toString().padStart(2, '0')
                var ss = (dt.getSeconds()).toString().padStart(2, '0')
                return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
            }
        })

        //自定义按键修饰符,对应键码
        Vue.config.keyCodes.f2 = 113

        //自定义全局指令v-focus,使用Vue.directive()
        //参数1:指令名称,定义时不需要加v-前缀,调用时需要加v-前缀
        //参数2:对象,指令相关函数集,在特定阶段执行相关函数 
        Vue.directive('focus', {
            //注:每个函数中第一个参数永远是el,表示被绑定指令的那个原生js对象
            bind: function (el) { //每当指定绑定到元素上时,会立即执行bind函数,且只触发一次

            },
            inserted: function (el) { //当元素插入到DOM中时,会执行inserted函数,且只触发一次
                el.focus()
            },
            updated() { //当VNode更新时,会执行updated,可能会触发多次

            },
        })

        Vue.directive('color', {
            bind: function (el, binding) {
                el.style.color = binding.value
            },
            inserted: function () {

            },
            updated() {

            },
        })

        //创建Vue实例对象
        var vm = new Vue({
            el: '#app',
            data: {//自定义变量
                id: '',
                name: '',
                keywords: '',//搜索关键字
                list: [
                    { id: 1, name: '宝马', ctime: new Date() },
                    { id: 2, name: '奔驰', ctime: new Date() },
                    { id: 3, name: '奥迪', ctime: new Date() },
                ]
            },
            methods: {//自定义方法
                add() {
                    var car = { id: this.id, name: this.name, ctime: new Date() }
                    this.list.push(car)
                    this.id = this.name = ''
                },
                del(id) {
                    // 方法1
                    // this.list.some((item,i) =>{
                    //     if(item.id == id){
                    //         this.list.splice(i,1)
                    //         return true;
                    //     }
                    // })

                    // 方法2
                    var index = this.list.findIndex(item => {
                        if (item.id == id) {
                            return true;
                        }
                    })
                    this.list.splice(index, 1);
                },
                search(keywords) {
                    var newList = [];

                    // 方法1
                    // this.list.forEach(item => {
                    //     //字符串匹配:是否包含字符串
                    //     if (item.name.indexOf(keywords) != -1) {
                    //         newList.push(item)
                    //     }
                    // });

                    // 方法2
                    newList = this.list.filter(item => {
                        if (item.name.includes(keywords)) {
                            return item
                        }
                    })
                    return newList;
                }
            },
            filters: {//自定义私有过滤器
                DateFormat: function (DateStr, pattern = "") {
                    var dt = new Date(DateStr)
                    var y = dt.getFullYear()
                    var m = (dt.getMonth() + 1).toString().padStart(2, '0')
                    var d = (dt.getDate()).toString().padStart(2, '0')

                    if (pattern.toLowerCase() === 'yyy-mm-dd') {
                        return `${y}-${m}-${d}`
                    } else {
                        var hh = (dt.getHours()).toString().padStart(2, '0')
                        var mm = (dt.getMinutes()).toString().padStart(2, '0')
                        var ss = (dt.getSeconds()).toString().padStart(2, '0')
                        return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
                    }
                }
            },
            directives: {//自定义私有指令
                'fontweight': { //设置字体粗细
                    bind: function (el, binding) {
                        el.style.fontWeight = binding.value
                    }
                },
                'fontsize': function (el, binding) { //注:此写法等同把代码写到bind和update函数中
                    el.style.fontSize = parseInt(binding.value) + 'px'
                }
            }
        })
    </script>
</body>

</html>

过渡动画实现

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <link rel="stylesheet" href="./css/animate.css">
    <style>
        .my-enter,
        .my-leave-to {
            opacity: 0;
            transform: translateY(150px);
        }

        .my-enter-active,
        .my-leave-active {
            transition: all 0.5s ease;
        }

        .ball {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background-color: red;
        }

        li {
            border: 1px dashed #999999;
            margin: 5px;
            line-height: 35px;
            padding-left: 5px;
            font-size: 12px;
            width: 100%
        }

        li:hover {
            background-color: cornflowerblue;
            transition: all 0.3s ease;
        }

        .v-enter,
        .v-leave-to {
            opacity: 0;
            transform: translateY(70px);
        }

        .v-enter-active,
        .v-leave-active {
            transition: all 0.5s ease;
        }

        .v-move {
            transition: all 0.5s ease;
        }

        .v-leave-active {
            position: absolute;
        }
    </style>
</head>

<body>
    <div id="app">
        <input type="button" value="自定义过渡动画触发" @click="show = !show">
        <transition name="my">
            <h3 v-if="show">H3 动画</h3>
        </transition>

        <hr>

        <input type="button" value="第三方过渡动画触发" @click="show2 = !show2">
        <transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter:200, leave:400}">
            <h6 class="animated" v-if="show2">H6 动画</h6>
        </transition>

        <input type="button" value="自定义小球半场动画触发" @click="showBall = !showBall">
        <transition @before-Enter="beforeEnter" @enter="enter" @after-Enter="afterEnter">
            <div class="ball" v-show="showBall"></div>
        </transition>

        <input type="button" value="自定义列表添加元素动画触发" @click="add">

        <!-- 为v-for循环创建的元素设置动画必须为每个元素设置:key属性 -->
        <!-- 为transition-group添加appear属性,实现页面初始入场效果 -->
        <!-- 为transition-group设置tag属性,指定其渲染为特定元素,默认渲染为span标签 -->
        <transition-group appear tag="ul">
            <li v-for="(item,i) in list" :key="item.id" @click=del(i)>
                {{item.id}} --- {{item.name}}
            </li>
        </transition-group>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                show: true,
                show2: true,
                showBall: true,
                count: 1,
                name: '名字',
                list: [
                    { id: 1, name: "名字" }
                ]
            },
            methods: {
                beforeEnter(el) {
                    el.style.transform = "translate(0,0)"
                },
                enter(el, done) {
                    el.offsetWidth
                    el.style.transform = "translate(150px, 450px)"
                    el.style.transition = 'all 1s ease'

                    done()
                },
                afterEnter(el) {
                    this.showBall = !this.showBall
                },

                add() {
                    //自增id
                    this.count = this.count + 1

                    var item = { id: this.count, name: this.name }
                    this.list.push(item)
                },
                del(i) {
                    this.list.splice(i, 1)
                }
            }
        })
    </script>
</body>

</html>

组件创建使用与传值

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <style>
        .v-enter,
        .v-leave-to {
            opacity: 0;
            transform: translateX(150px);
        }

        .v-enter-active,
        .v-leave-active {
            transition: all 0.3s ease;
        }
    </style>
</head>

<body>
    <div id="app">
        <globalcom></globalcom>
        <!-- 父组件向子组件传递方法使用v-on事件绑定机制 -->
        <privatecom v-bind:parentmsg="msg" @func="show"></privatecom>

        <hr>
        <a href="" @click.prevent="comName='login'">登录</a>
        <a href="" @click.prevent="comName='register'">注册</a>
        <!-- compontent是一个占位符,:is属性可以用来指定要展示的组件名称 -->
        <transition mode="out-in">
            <component :is="comName"></component>
        </transition>
    </div>

    <template id="globaltemp">
        <div>
            <input type="button" value="+1" @click="increment">
            <h3>{{count}}</h3>
        </div>
    </template>

    <template id="privatetemp">
        <div>
            <h1>这是私有template元素 子组件 --- {{parentmsg}}</h1>
            <input type="button" value="子组件按钮,触发父组件传递的func方法" @click="subclick">
        </div>
    </template>

    <script>
        //定义全局组件
        Vue.component('globalcom', {
            template: '#globaltemp',
            data: function () {
                return { count: 0 }
            },
            methods: {
                increment() {
                    this.count++
                }
            }
        })

        Vue.component('login', {
            template: '<h3>登录组件</h3>'
        })
        Vue.component('register', {
            template: '<h3>注册组件</h3>'
        })

        var vm = new Vue({
            el: '#app',
            data: {
                msg: '父类数据',
                msgfromson: null,
                comName: 'login'
            },
            methods: {
                show(param1, param2) {
                    msgfromson = param2
                    console.log('调用了父组件的show方法---' + param1)
                }
            },
            components: {
                privatecom: {
                    template: '#privatetemp',
                    // props中的数据只读
                    props: ['parentmsg'],
                    // data中的数据可读可写
                    data() {
                        return {
                            title: '标题',
                            content: '内容',
                            sonmsg: { name: '井底之蛙', age: 6 }
                        }
                    },
                    methods: {
                        subclick() {
                            this.$emit('func', 123, this.sonmsg)
                        }
                    }
                }
            }
        })
    </script>
</body>

</html>

使用ref获取DOM元素与组件

<!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>Document</title>
    <script src="./lib/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="button" value="ref获取" ref="mybtn" @click="getref">
        <h3 ref="myh3">我是h3,请通过ref来获取我的数据</h3>

        <hr>

        <login ref="mylogin"></login>
    </div>

    <script>
        var login = {
            template: '<h1>登录组件</h1>',
            data() {
                return {
                    msg: '组件数据'
                }
            },
            methods: {
                show(){
                    console.log('调用了组件方法')
                }
            },
        }

        var vm = new Vue({
            el: '#app',
            data: {
            },
            methods: {
                getref() {
                    console.log(this.$refs.myh3.innerText);
                    console.log(this.$refs.mylogin.msg);
                    this.$refs.mylogin.show()
                }
            },
            components: {
                'login': login
            }
        })
    </script>
</body>

</html>

组件案例-评论列表

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <link rel="stylesheet" href="./css/bootstrap.min.css">
</head>

<body>
    <div id="app">
        <cmt-box @func="loadComments"></cmt-box>
        <ul class="list-group">
            <li class="list-group-item" v-for="(item,index) in list" :key="index">{{item.content}}
                <span class="badge badge-secondary">评论人:{{item.user}}</span>
            </li>
        </ul>
    </div>

    <template id="tmp1">
        <div>
            <div class="form-group">
                <label>评论人:</label>
                <input class="form-control" type="text" v-model="user">
            </div>

            <div class="form-group">
                <label>评论内容:</label>
                <input class="form-control" type="text" v-model="content">
            </div>

            <div class="form-group">
                <button class="btn btn-primary" type="button" @click="submit">提交评论</button>
            </div>
        </div>
    </template>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                list: [
                    { user: '萧炎', content: '我最爱的人是药老' },
                    { user: '美杜莎', content: '异火的味道很不错' },
                    { user: '云韵', content: '等级再高也挡不住爱情' }
                ]
            },
            created() {
                this.loadComments()
            },
            methods: {
                loadComments() {
                    var list = JSON.parse(localStorage.getItem('cmts') || '[]')
                    this.list = list
                }
            },
            components: {
                'cmt-box': {
                    template: '#tmp1',
                    data() {
                        return {
                            user: '',
                            content: '',
                        }
                    },
                    methods: {
                        submit() {
                            var comment = { 'user': this.user, 'content': this.content }

                            //从localstrage中获取所有的评论
                            var list = JSON.parse(localStorage.getItem('cmts') || '[]')
                            list.unshift(comment)

                            localStorage.setItem('cmts', JSON.stringify(list))
                            this.user = this.content = ''
                            this.$emit('func')
                        }
                    }
                }
            }
        })
    </script>
</body>

</html>

watch监视及computed计算属性

<!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>Document</title>
    <script src="./lib/vue.js"></script>
</head>

<body>
    <div id="app">
        <input type="text" v-model="firstname">
        +
        <input type="text" v-model="lastname">
        =
        <input type="text" v-model="fullname">
        =
        <input type="text" v-model="fullnamecomputed">
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                firstname: '',
                lastname: '',
                fullname: ""
            },
            methods: {
            },
            watch: {//监视data中指定数据的变化,然后出发这个watch中对应的function函数
                'firstname': function (newVal, oldVal) {
                    this.fullname = newVal + '-' + this.lastname
                },
                'lastname': function (newVal) {
                    this.fullname = this.firstname + '-' + newVal
                }
            },
            computed: {//计算属性,本质是一个方法,不过使用时直接当做属性来使用而不当作方法调用
                //function内求值结果会被缓存起来,所用到的任何data中的数据发生变化都会立即重新求值
                'fullnamecomputed': function () {
                    return this.firstname + '-' + this.lastname
                }
            }
        })
    </script>
</body>

</html>

路由的使用

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <script src="./lib/vue-router.js"></script>

    <style>
        .router-link-active,
        .myactive {
            color: red;
            font-weight: 800;
            font-size: 30px;
        }

        .v-enter,
        .v-leave-to {
            opacity: 0;
            transform: translateX(140px);
        }

        .v-enter-active,
        .v-leave-active {
            transition: all 0.5s ease
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- router-link默认渲染为a标签,如果需要改变可以是用tag来指定 -->
        <router-link to="/account" tag="span">用户</router-link>
        <router-view></router-view>
    </div>

    <template id="accounttemp">
        <div>
            <h1>Account组件</h1>
            <!-- <router-link to="/login?id=9&name=sc">登录</router-link> -->
            <!-- 第1种路由传参方式 -->
            <router-link to="/account/login/9/sc">登录</router-link> <!-- 第2种路由传参方式 -->
            <router-link to="/account/register">注册</router-link>
            <transition mode="out-in">
                <router-view></router-view>
            </transition>
        </div>
    </template>

    <script>
        var account = {
            template: '#accounttemp'
        }

        var login = {
            // template: '<h1>登录组件 --- {{$route.query.id}} --- {{$route.query.name}}</h1>',//第1种路由传参方式
            template: '<h1>登录组件 --- {{$route.params.id}} --- {{$route.params.name}}</h1>',//第2种路由传参方式
            created() {
                // console.log(this.$route.query.id);//第1种路由传参方式
                console.log(this.$route.params.id);//第2种路由传参方式
            },
        }
        var register = {
            template: '<h1>注册组件</h1>'
        }

        const router = new VueRouter({
            routes: [//路由规则
                // 每个路由规则都是一个对象,这个规则对象有两个必须属性
                // 属性1:path,表示监听哪个路由链接地址
                // 属性2:component,表示对应path的展示组件,注意他的值必须是一个组件模板对象,不能是组件的引用名称
                { path: '/', redirect: '/account' },//根路径重定向到login
                {
                    path: '/account',
                    component: account,
                    // 路由嵌套
                    children: [
                        // { path: '/login', component: login },//第1种路由传参方式
                        { path: 'login/:id/:name', component: login }, //第2种路由传参方式
                        { path: 'register', component: register },
                    ]
                },
            ],
            linkActiveClass: 'myactive' //自定义激活类名
        })

        var vm = new Vue({
            el: '#app',
            data: {
            },
            methods: {
            },
            router, //将路由规则对象注册到vm实例上
            watch: { //监视路由的地址改变
                '$route.path': function (newVal, oldVal) {
                    if (newVal.indexOf('/account/login') != -1) {
                        console.log('欢迎进入登录界面');
                    } else if (newVal.indexOf('/account/register') != -1) {
                        console.log('欢迎进入注册界面');
                    }

                }
            }
        })
    </script>
</body>

</html>

路由命名视图实现经典布局

<!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>Document</title>
    <script src="./lib/vue.js"></script>
    <script src="./lib/vue-router.js"></script>

    <style>
        html,
        body {
            margin: 0;
            padding: 0;
        }

        h1 {
            margin: 0;
            padding: 0;
            font-size: 20px;
        }

        .header {
            background-color: orange;
            height: 80px;
        }

        .container {
            display: flex;
            height: 600px;
        }

        .left {
            background-color: lightgreen;
            flex: 2;
        }

        .main {
            background-color: lightpink;
            flex: 8;
        }
    </style>
</head>

<body>
    <div id="app">
        <!-- router-view的name属性值默认为default -->
        <router-view></router-view>
        <div class="container">
            <router-view name="left"></router-view>
            <router-view name="main"></router-view>
        </div>

    </div>

    <script>
        var header = {
            template: '<h1 class="header">Header头部区域</h1>'
        }
        var leftBox = {
            template: '<h1 class="left">Left侧边栏区域</h1>'
        }
        var mainBox = {
            template: '<h1 class="main">MainBox主体区域</h1>'
        }

        const router = new VueRouter({
            routes: [
                {
                    path: '/', components: {
                        'default': header,
                        'left': leftBox,
                        'main': mainBox
                    }
                }
            ]
        })

        var vm = new Vue({
            el: '#app',
            data: {
            },
            methods: {
            },
            router
        })
    </script>
</body>

</html>

使用webpack

mkdir webpack-study
cd webpack-demo
mkdir dist
mkdir src
  • 使用VSCode打开webpack-study文件夹
  • 在src目录下创建index.html与index.js
  • VSCode中使用快捷键 ctrl+` 打开终端输入:
//生成package.json文件
npm init -y

//因项目中用了jquery改变样式,所以安装jquery
npm i jquery -S

//安装html-webpack-plugin,可自动把html打包到内存,并为html添加bundle.js引用
npm i html-webpack-plugin -D

//如是全局安装webpack,在项目使用html-webpack-plugin,需要项目安装webpack
npm install webpack

//安装css样式加载器
npm i style-loader css-loader -D

//安装url加载器
npm i url-loader file-loader -D

//安装bootstrap 4.3.1及open-iconic字体图标库
npm i bootstrap -S
cnpm i open-iconic -D

//安装babel
npm i babel-core babel-loader babel-plugin-transform-runtime -D
npm i babel-preset-env babel-preset-stage-0 -D
//如报升级问题:npm i babel-loader@7 -D
  • 项目src目录下新建文件index.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>Document</title>

    <!-- 已在配置文件plugin中使用htmlWebpackPlugin处理 -->
    <!-- <script src="/bundle.js"></script> -->

    <!-- 已在配置文件module中使用style-loader,css-loader处理 -->
    <!-- <link rel="stylesheet" href="./css/index.css"> -->
</head>

<body>
    <ul>
        <li>第1个li</li>
        <li>第2个li</li>
        <li>第3个li</li>
        <li>第4个li</li>
        <li>第5个li</li>
        <li>第6个li</li>
        <li>第7个li</li>
    </ul>

    <div class="box"></div>
    <span class="oi oi-account-login" aria-hidden="true"></span>
    <span class="oi oi-account-logout" aria-hidden="true"></span>
</body>

</html>
  • 项目src目录下新建文件index.js
//导入Jquary, import * from *  是ES6中的导入模块的方式
import $ from 'jquery'

//使用import语法导入css样式表
//webpack默认只能打包处理js类型文件,如要处理非js类型文件则需手动安装第三方 loader加载器
//需要在配置文件中的添加module对象的rules属性
import './css/index.css'

//引入node_modules中相关文件可以直接写包的名称接具体文件路径
import 'bootstrap/dist/css/bootstrap.css'
import 'open-iconic/font/css/open-iconic-bootstrap.css'

$(function () {
    $('li:odd').css('backgroundColor', 'blue')
    $('li:even').css('backgroundColor', function () { return '#654321' })
})

class Person {
    static info = { name: 'scrat', age: 30 }
}

console.log(Person.info)
  • 项目src下的css目录里新建文件index.css
html,body{
    margin: 0;
    padding: 0;
}

ul {
    margin: 0;
    padding: 0;
}

li {
    list-style: none;
}

/* 默认webpack无法处理url地址 */
.box{
    width: 200px;
    height: 100px;
    background: url('../images/火柴人.jpg');
    background-size: cover;
}
  • 项目根目录下新建文件**.babelrc**
{
    "presets":["env","stage-0"],
    "plugins": ["transform-runtime"]
}
  • 项目根目录下新建配置文件webpack.config.js,内容如下:
const path = require('path');

const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    devServer: {
        contentBase: path.join(__dirname, 'src'),
        port: 9000,
        inline: true,
        compress: true,
        open: true,
    },
    plugins: [
        new htmlWebpackPlugin({
            template: path.join(__dirname, './src/index.html'),
            filename: 'index.html'
        })
    ],
    module: { //用于配置第三方模块加载器
        rules: [ //所有模块的匹配规则
            //配置处理.css文件的第三方loader规则,use列表处理流程从右到左
            { test: /\.css$/, use: ['style-loader', 'css-loader'] },

            //处理url路径的loader规则
            //默认图片base64处理,limit=限制文件字节数
            //若以url图片名显示默认名会hash处理,name=hash值8位 + 原名 + 原后缀
            { test: /\.(jpg|jpeg|png|gif|bmp)$/, use: 'url-loader?limit=20000&name=[hash:8]-[name].[ext]' },

            //字体文件的匹配规则
            { test: /\.(ttf|eot|svg|woff|woff2|otf)$/, use: 'url-loader' },

            //Babel配置
            { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ },
        ]
    },
    performance: {
        hints: false
    }
}
  • 使用web-dev-server启动
npm run dev

待更新

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值