zoukankan      html  css  js  c++  java
  • Vue Q

    一、Vue框架介绍

    Vue是一个构建数据驱动的web界面的渐进式框架。

    目标是通过尽可能简单的API实现响应式的数据绑定和组合的视图组件。

    能够构建复杂的单页面应用。现在我们开始认识一下Vue~

    // HTML 页面
    <div id="app">
        <span>你的名字是{{name}}</span>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="../js/main.js"></script>
    
    // main.js 页面
    var app = new Vue({
        el: '#app',
        data: {
            name: "Gao_Xin"
        }
    });
    Vue demo

    二、Vue指令

    Vue的指令directives很像我们所说的自定义属性,指令是Vue模板中最常用的功能,

    它带有v-前缀,功能是当表达式改变的时候,相应的行为作用在DOM上。

    <template>
    <div>
      <h2>head</h2>
      <p v-text="msg"></p>
      <p v-html="html"></p>
    </div>
    </template>
    
    <script>
        export default {
            name: "head",
          data(){
              return {
                msg: "消息",
                html: `<h2>插入h2标题</h2>`
    
              }
          }
    
        }
    </script>
    
    <style scoped>
    
    </style>
    v-test v-html
    // HTML页面
    <div id="app">
            <label><input type="checkbox" v-model="sex" value="male">
                //  <input type="radio" v-model="sex" value="male">
            </label>
            <label><input type="checkbox" v-model="sex" value="female">
            </label>
            {{sex}}
    </div>  
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="../js/main.js"></script>  
    
    // main.js 页面
    
    var app = new Vue({
        el: '#app',
        data: {
            // sex: "male",
            sex: [],
        }
    });
    v-model input
    // HTML 页面
    <div id="app">
    <div>
            <texteare v-model="article">
            </texteare>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="../js/main.js"></script>
    // main.js 页面
    var app = new Vue({
        el: '#app',
        data: {
            // sex: "male",
            sex: [],
            article: "这是一段文本。。这是一段文本。。这是一段文本。。这是一段文本。。这是一段文本。。"
        }
    });
    v-model textarea
    // HTML页面
    <div id="app">
            <!--<select v-model="from">-->
                <!--<option value="1">单选1</option>-->
                <!--<option value="2">单选2</option>-->
            <!--</select>-->
            <!--{{from}}-->
            <select v-model="where" multiple="">
                <option value="1">多选1</option>
                <option value="2">多选2</option>
                <option value="3">多选3</option>
            </select>
            {{where}}
     </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="../js/main.js"></script>
    // main.js 页面
    var app = new Vue({
        el: '#app',
        data: {
            from: null,
            where: [],
        }
    });
    v-model select
    //  需求是展示一个人的所有爱好 以及喜欢吃的食物和价格
    // HTML 页面  
    <div id="app">
    <div> 
            <span>你的爱好是</span>
            <ul>
                <li v-for="hobby in hobby_list">{{hobby}}</li>
            </ul>
    </div>
    <div>
            <span>你喜欢的食物</span>
            <ul>
                <li v-for="food in food_list">{{food.name}}: 价格¥{{food.discount ? food.price*food.discount: food.price}}</li>
            </ul>
    </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="../js/main.js"></script>
    // main.js
    var app = new Vue({
        el: '#app',
        data: {
            hobby_list: ["王者毒药","LOL","吃鸡"],
            food_list: [
                {
                    name: "葱",
                    price: 5,
                    discount: .8,
                },
                {
                    name: "姜",
                    price: 8,
                    // discount: .5
    
                }
            ],
        }
    });
    v-for
    // 我们常常见到博客中评论回复的时候 @某某某
    // 我们点击这个用户是能够跳转的  那么这个应该是个动态的
    // 我们就需要给标签属性进行动态绑定 v-bind
    // HTML页面
    <style>
            .active {
                background: red;
            }
    </style>
    <div id="app">
       <div>
            <!--<a v-bind:href="my_link">点我</a>-->
            <a v-bind:href="my_link" :class="{active: isActive}">点我 
     </a>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="../js/main.js"></script>
    // main.js
    var app = new Vue({
        el: '#app',
        data: {
            my_link: "http://baidu.com",
            isActive: true,
        }
    });
    v-bind
    // 那我们以前的事件绑定在vue中是怎么做到的呢
    // HTML页面
    <div>
            <span>事件</span>
            <button v-on="{mouseenter: onMouseenter, mouseleave: onMouseleave}" v-on:click="onClick(1)">点我</button>
        </div>
        <div>
            <input type="text" v-on="{keyup: onKeyup}">
    </div>
    // main.js
    var app = new Vue({
        el: '#app',
        data: {
            my_link: "http://baidu.com",
            isActive: true,
        },
        methods: {
            onClick: function (a) {
                alert(a)
            },
            onMouseenter: function () {
                console.log("mouse enter")
            },
            onMouseleave: function () {
                console.log("mouse leave")
            },
            onKeyup: function () {
                console.log("key up")
            }
        },
    });
    v-on
    // 我们之前写过权限 我们现在模拟一个简单的权限
    // HTML页面
    <div>
            <div v-if="role == 'admin' || 'super_admin'">管理员你好</div>
            <div v-else-if="role == 'hr'">待查看简历列表</div>
            <div v-else> 没有权限</div>
    </div>
    // main.js 页面
    var app = new Vue({
        el: '#app',
        data: {
            role: 'admin',
           // role: 'hr',
        },
    });
    v-if v-else-if v-else
    // 现在我们要实现一个功能 点击一个按钮显示文本 再点击取消
    // 这种显示和隐藏的功能 vue也帮我们进行了封装
    // HTML页面
    <div id="app">
        <button @click="on_click()">
            点我
        </button>
        <p v-show="show">提示文本</p>
    </div>
    // main.js 页面
    var app = new Vue({
        el: '#app',
        data: {
            show: false,
        },
        methods: {
            on_click: function () {
                this.show = !this.show
            }
        }
    
    });
    v-show
    //  我们现在要获取用户的注册信息
    //  用户名以及手机号 用指令修饰符能够让我们更加便捷
    // HTML 页面
    <div>
        用户名: <input type="text" v-model.lazy.trim="username"><br>
        {{username}}
        手机号: <input type="text" v-model.number="phone"><br>
        {{phone}}
    </div>
    // main.js 页面
    var app = new Vue({
        el: '#app',
        data: {
            username: "",
            phone: "",
        },
    });
    指令修饰符
    // 我们现在有个需求 点击元素 让这个元素在浏览器窗口钉住
    // 我们只需自定义一个指令,只要给元素绑定指令就可以
    // HTML页面
    <style>
            .card {
                border: solid 3px red;
                 200px;
                height: 100px;
                background: #eeeeee;
                margin-bottom: 5px;
            }
    </style>
    <div id="app">
     <div class="card" v-pin:true.bottom.right="pinned">
            <button @click="pinned = !pinned">盯住/取消</button>
            这是一个盒子文本内容
        </div>
        <div class="card">
            这是一个盒子文本内容
        </div>
        <div class="card">
            这是一个盒子文本内容
        </div>
        <div class="card">
            这是一个盒子文本内容
        </div>
        <div class="card">
            这是一个盒子文本内容
        </div>
        <div class="card">
            这是一个盒子文本内容
        </div>
        <div class="card">
            这是一个盒子文本内容
        </div>
    </div>
    // main.js 页面
    Vue.directive('pin', function (el, binding) {
        var binded = binding.value;
        var position = binding.modifiers;
        var warning = binding.arg;
        console.log(position)
        if(binded){
            el.style.position = 'fixed';
            for(var key in position){
                if (position[key]){
                    el.style[key] = '20px';
                }
            }
            if (warning === 'true'){
                el.style.background = '#666'
            }
    
        }
        else {
            el.style.position = 'static';
            el.style.background = "#eeeeee"
        }
    });
    new Vue({
        el: '#app',
        data: {
            pinned: false,
        }
    });
    自定义指令以及修饰符和参数

    Vue获取DOM元素

        <style>
            .box {
                 200px;
                height: 200px;
                border: solid 1px red;
            }
        </style>
    
    </head>
    <body>
    <div id="app">
        <div  class="box" ref="my_box">
            这是一个盒子
        </div>
    </div>
    
    <script>
        const app = new Vue({
            el: "#app",
            mounted(){
                this.$refs.my_box.style.color = "red";
            }
        })
    </script>
    
    </body>
    获取DOM

    Vue计算属性

    我们的模板表达式非常的便利,但是逻辑复杂的时候,模板会难以维护,vue提供了计算属性。

    我们用方法也能达到效果,那么我们为什么要用计算属性呢~

    其实在vue中方法和计算属性达到的效果是一样的,但是计算属性是基于依赖进行缓存的,

    只有依赖的数据发生改变的时候,才会重新执行计算属性的函数,每次调用都会从缓存中拿之前算好的数据。

    而方法是每调用一次,执行一次。

    // 现在我们有一个成绩的表格 来计算总分和平均分
    // HTML页面
    <div id="app">
        <table border="1">
            <thead>
                <th>学科</th>
                <th>分数</th>
            </thead>
            <tbody>
                <tr>
                    <td>数学</td>
                    <td><input type="text" v-model.number="math"></td>
                </tr>
                <tr>
                    <td>物理</td>
                    <td><input type="text" v-model.number="physics"></td>
                </tr>
                <tr>
                    <td>英语</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>
    // js 页面
    var app = new Vue({
        el: '#app',
        data: {
            math: 90,
            physics:88,
            english: 78,
        },
        computed: {
            sum: function () {
                var total = this.math + this.physics + this.english
                return total
            },
            average: function () {
                var average_num = Math.round(this.sum/3)
                return average_num
            }
        }
    });
    计算属性 computed 

    Vue过滤器

    过滤器是在数据到达用户的最后一步进行简单的过滤处理,复杂的还是要用计算属性或者方法。

    // 我们两个需求 一个是价格展示后面自动加“元”
    //  单位 毫米和米的转换
    // HTML页面
    <div>
            <p>价格展示</p>
            <input type="text" v-model="price">
            {{price | currency('USD')}}
    </div>
    <div>
            <p>换算</p>
            <input type="text" v-model="meters">
            {{meters | meter}}
     </div>
    // js 代码
    Vue.filter('currency', function (val, unit) {
        val = val || 0;
        var ret = val+ unit
        return ret
    });
    
    Vue.filter('meter', function (val) {
        val = val || 0;
        return (val/1000).toFixed(2) + "米"
    });
    new Vue({
        el: '#app',
        data: {
            price: 10,
            meters: 10,
        }
    });
    过滤器 filter

    三、Vue组件

    组件 (Component) 是 Vue.js 最强大的功能之一。

    组件可以扩展 HTML 元素,封装可重用的代码。是可复用的Vue实例。

    组件的注册

    // html 代码
    <div id="app">
      <my-component></my-component>
    </div>
    // js 代码
    Vue.component('my-component', {
      template: '<div>A component!</div>'
    })
    var app = new Vue({
      el: '#app',
      data: {
           
      } 
    });
    全局注册
    // html 代码
    <div id="app">
      <my-component></my-component>
    </div>
    // js 代码
    // 组件中的data必须是个函数
    var Child = {
      template: '<div>A component!</div>',
      data: function() {
          return {
                name: "gao",
          }
    }};
    
    new Vue({
      // ...
      components: {
        // <my-component> 将只在父组件模板中可用
        'my-component': Child
      }
    })
    局部注册
    // js 代码
    Vue.component('child', {
        template: `<div><button @click="on_click()">{{msg}}</button></div>`,
        data: function () {
            return {
                msg: "点我",
            }
        },
        methods: {
            on_click(){
                alert(123)
            }
        }
    });
    new Vue({
        el: "#app",
    })
    组件中的data methods
    <script>
        var my_component = {
            template: `<div><h1>{{msg}}</h1></div>`,
            data(){
                return{
                    msg: "这是子组件"
                }
            }
        };
        var global_component = {
            template: `<div>
                            <h1>{{msg}}</h1>
                            <button @click="on_click">点我</button>
                            <my_component></my_component>
                        </div>`,
            data(){
                return {
                    msg: "全局组件"
                }
            },
            methods: {
                on_click() {
                    alert("123")
                }
            },
            components:{
                my_component:my_component,
            }
        };
        const app = new Vue({
            el: "#app",
            data: {
    
            },
            components: {
                global_component: global_component,
                // my_component: my_component,
            }
        });
    
    
    </script>
    子组件的注册

    组件之间的通信

    我们的组件在任何地方用的时候都要是一个样子么~

    可不可以我们给组件传个参数~让组件在不同的地方表现不同的状态~

    我们之前说过博客评论@某某某,点击用户名可以跳转到该用户站点。

    这样一个小功能,我们每次@的时候都要写,我们可以封装成组件,传值即可~~

    // html 代码
    <div id="app">
        <child username="gaoxin"></child>
    </div>
    // js 代码
    Vue.component('child', {
        template: `<a :href="'/user/'+ username">{{username}}</a>`,
        props: ["username"],
    });
    
    
    var app = new Vue({
        el: "#app",
        data:{
            name: "@gaoxin"
        }
    
    });
    父子通信

    app.$on(event, callback) 监听当前实例上的自定义事件,事件由$emit触发,回调函数接收事件触发器额外参数。

    app.$emit(event, [args....])  触发当前实例上的事件,额外参数传给监听器的callback回调函数。

    // html 代码
    <div id="app">
        <parent></parent>
    </div>
    // js 代码
    Vue.component('parent',{
        template: `
            <div>
                <child @show_balance="show"></child>
                <p v-if="active">您的余额998</p>
            </div>
        `,
        data: function () {
            return {
                active: false,
            }
        },
        methods: {
            show: function(data){
                this.active=true;
                console.log(data)
            }
        }
    
    });
    Vue.component('child', {
        template: `<div><button @click="on_click()">{{msg}}</button></div>`,
        data: function () {
            return {
                msg: "显示余额",
            }
        },
        methods: {
            on_click(){
                // alert(123)
                this.$emit('show_balance', {q:1,b:2})
            }
        }
    });
    子父通信

    平行组件之间的通信,喊话需要一个中间调度器,在组件加载完成之后去监听调度器事件,回调函数接收数据。

    // html 代码
    <div id="app">
        <whh></whh>
        <shh></shh>
    </div>
    // js 代码
    var Event = new Vue()
    
    Vue.component('whh',{
        template: `
            <div>
                我说: <input @keyup="on_change" v-model="i_said">
            </div>
        `,
        data: function () {
            return {
                i_said: '',
            }
        },
        methods: {
            on_change: function () {
                Event.$emit("whh_said_something", this.i_said)
            }
        }
    });
    Vue.component('shh', {
        template: `
            <div>
                花花说:{{whh_said}}
            </div>
        `,
        data: function () {
            return {
                whh_said: '',
            }
        },
        mounted: function () {
            var me = this
            Event.$on('whh_said_something', function (data) {
                me.whh_said = data
            })
        }
    });
    非父子组件通信

    混合Mixins

    重复功能和数据的储存器,可以覆盖Mixins的内容。

    // 点击显示和隐藏  提示框的显示和隐藏
    // html 代码
    <div id="app">
        <PopUp></PopUp>
        <ToolTip></ToolTip>
    </div>
    // js 代码
    var base = {
         data: function () {
            return {
                visible: false,
            }
        },
        methods: {
            show: function () {
                this.visible = true
            },
            hide: function () {
                this.visible = false
            }
        }
    }
    
    Vue.component('popup', {
        template:`
            <div>
            <button @click="show">PopUp show</button>
            <button @click="hide">PopUp hide</button>
            <div v-if="visible"><p>hello everybody</p></div>
            </div>
        `,
        mixins: [base],
        data: function () {
            return {
                visible: true,
            }
        }
    
    });
    Vue.component('tooltip', {
        template: `
            <div>
            <div @mouseenter="show" @mouseleave="hide">ToolTip</div>
            <div v-if="visible"><p>ToolTip</p></div>
            </div>
        `,
        mixins: [base]
    });
    
    new Vue({
        el: "#app",
    })
    Mixins

    插槽 Slot

    插槽是一套内容分发的API,在组件中,<slot>作为内容承载分发的出口

    // html 代码
    <div id="app">
        <panel>
            <div slot="title"> HELLO</div>
            <div slot="content">hello</div>
            
        </panel>
        <panel></panel>
        <panel></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="content">Failure is probably the fortification in your pole. It is like a peek your wallet as the thief, when you are thinking how to spend several hard-won lepta,</div>-->
            <div class="footer">
                <slot name="footer">更多信息</slot>
            </div>
        </div>
    </template>
    // js 代码
    Vue.component('panel', {
        template: '#panel-tpl',
    
    });
    
    new Vue({
        el: "#app",
    })
    Slot

    四、vue-router

    vue-router是Vue的路由系统,定位资源的,我们可以不进行整页刷新去切换页面内容。

    vue-router的安装和基本配置

    vue-router.js 可以下载 也可以用cdn,基本配置信息看如下代码~~~

    // html 代码
    <div id="app">
        <div>
            <router-link to="/">首页</router-link>
            <router-link to="/about">关于我们</router-link>
        </div>
        <div>
            <router-view></router-view>
        </div>
    
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
    <script src="../js/router_demo.js"></script>
    // js 代码
    var routes = [
        {
            path: "/",
            component: {
                template: `<div><h1>首页</h1></div>`
            }
        },
        {
            path: "/about",
            component: {
                template: `<div><h1>关于我们</h1></div>`
            }
        }
    ]
    
    var router = new VueRouter({
        routes: routes,
        // 路由去掉#
        // mode: 'history',
    });
    
    var app = new Vue({
        el: '#app',
        router: router,
    });
    vue-router demo

    路由的一些方法

    路由传参以及获取参数~~

    // html 代码
    <div id="app">
        <div>
            <router-link to="/">首页</router-link>
            <router-link to="/about">关于我们</router-link>
            <router-link to="/user/琴女?age=20">琴女</router-link>
            <router-link to="/user/提莫">提莫</router-link>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
    // js 代码
    var routes = [
        {
            path: "/",
            component: {
                template: `<div><h1>首页</h1></div>`
            }
        },
        {
            path: "/about",
            component: {
                template: `<div><h1>关于我们</h1></div>`
            }
        },
        {
            path: "/user/:name",
            component: {
                template: `<div>
                          <h1>我是:{{$route.params.name}}</h1>
                          <h1>我年龄是:{{$route.query.age}}</h1>
                        </div>`,
            }
        }
    ]
    
    var router = new VueRouter({
        routes: routes,
    });
    
    var app = new Vue({
        el: '#app',
        router: router,
    });
    传参以及获取参数

    命名路由~  注意router-link里to一定要v-bind~~

    // html代码
    <div id="app">
        <div>
            <router-link to="/">首页</router-link>
            <router-link :to="{name: 'about'}">关于我们</router-link>
            <router-link to="/user/gaoxin?age=19">gaoxin</router-link>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>
    // js代码
    let routes = [
            {
                path: '/',
                component: {
                    template: `<h1>这是主页</h1>`
                }
            },
            {
                path: "/about",
                name: "about",
                component: {
                    template: `<h1>关于我们</h1>`
                }
            },
            {
                path: "/user/:name",
                component: {
                    template: `<div>
                                <h1>我是{{$route.params.name}}</h1>
                               <h2>我的年龄是{{$route.query.age}}</h2>
                                </div>
                              `
                }
            }
        ];
    
        let router = new VueRouter({
            routes: routes,
            mode: "history"
        });
    
        const app = new Vue({
            el: "#app",
            router: router,
            mounted(){
                console.log(this.$route)
                console.log(this.$router)
            }
        })
    命名路由

    子路由~~ 以展示详细为例~~

    // 添加子路由变化的只有父级路由 
    // 基于上面的例子增加
    // js 代码
    {
            path: "/user/:name",
            component: {
                template: `<div>
                          <h1>我是:{{$route.params.name}}</h1>
                          <h1>我年龄是:{{$route.query.age}}</h1>
                          <router-link to="more" append>更多信息</router-link>
                          <router-view></router-view>
                        </div>`,
            },
            children: [
                {
                path: "more",
                component: {
                    template: `<div>
                          {{$route.params.name}}的详细信息
                    </div>`,
                }
            }
            ]
    
        },
    子路由

     手动访问路由,以及传参~~

    // 基于上面例子追加
    // html 代码
    <div id="app">
        <div>
            <router-link to="/">首页</router-link>
            <router-link to="/about">关于我们</router-link>
            <router-link to="/user/琴女?age=20">琴女</router-link>
            <router-link to="/user/提莫">提莫</router-link>
            // 添加一个button按钮
            <button @click="on_click">旅游</button>
        </div>
        <div>
            <router-view></router-view>
        </div>
    </div>    
    // js 代码
    // 注意路由name的使用 这是在原例子追加
    var app = new Vue({
        el: '#app',
        router: router,
        methods: {
            on_click: function () {
                setTimeout(function () {
                    this.$router.push('/about')
                    setTimeout(function () {
                        this.$router.push({name: "user", params:{name: "琴女"},query:{age: 20}})
                    }, 2000)
                }, 2000)
            }
        }
    });
    手动路由~以及传参

    命名路由视图 router-view

    当我们只有一个<router-view></router-view>的时候~所有内容都展示在这一个面板里面~

    如果是content 和 footer 就需要同时显示并且不同区域~这就需要对视图进行命名~

    // html 代码
    <div id="app">
        <div>
            <router-link to="/">首页</router-link>
            
        </div>
        <div>
            <router-view name="content" class="content-view"></router-view>
            <router-view name="footer" class="footer-view"></router-view>
        </div>
    
    </div>
    // js 中的主要代码
    var routes = [
        {
            path: "/",
            components: {
                content: {
                    template: `<div><h1>首页</h1></div>`,
                },
                footer: {
                    template: `<div><h1>关于我们</h1></div>`,
                }
            }
        },
    ]
    命名路由视图

    错误路由的重定向~~

    let routes = [
         {
                path: "**",
                redirect: "/"
            }   
    ]
    redirect

    $route以及$router的区别~~

      -- $route为当前router调转对象,里面可以获取name, path, query, params等~

      -- $router为VueRouter实例,有$router.push方法等~~

    路由的钩子

    路由的生命周期就是从一个路由跳转到另一路由整个过程,下面介绍两个钩子~

    router.beforeEach()   router.afterEach()  详情请看代码~~

    // html 代码
    <div id="app">
        <router-link to="/">首页</router-link>
        <router-link to="/login">登录</router-link>
        <router-link to="/user">用户管理</router-link>
        <div>
            <router-view></router-view>
        </div>
    </div>
    //  js 代码
    var routes = [
        {
            path: "/",
            component: {
                template: "<h1>首页</h1>"
            }
        },
        {
            path: "/login",
            component: {
                template: "<h1>登录</h1>"
            }
        },
        {
            path: "/user",
            component: {
                template: "<h1>用户管理</h1>"
            }
        }
    ];
    var router = new VueRouter({
        routes: routes
    });
    
    router.beforeEach(function (to,from,next) {
        // console.log(to)
        // console.log(from)
        // console.log(next)
        // next(false)
        if(to.path=="/user"){
            next("/login")
        }
        else {
            next();
        }
    });
    router.afterEach(function (to, from) {
        console.log(to)
        console.log(from)
    });
    
    var app = new Vue({
        el: '#app',
        router: router
    });
    路由钩子
    next:function  一定要调用这个方法来resolve这个钩子函数。
            执行效果依赖next方法的调用参数
            next() 什么都不做继续执行到调转的路由
            next(false) 中断当前导航 没有跳转 也没有反应
            next("/")  参数是路径 调转到该路径
            next(error)  如果next参数是一个Error实例 导航终止该错误
                        会传递给router.onError()注册过的回调中
    next 参数详解

    上面的例子~~如果/user下面还有子路由的情况下会怎么样呢~????

    // 匹配子路由 改一下匹配方法就可以~
    // js 改动代码
    router.beforeEach(function (to,from,next) {
        // console.log(to)
        // console.log(from)
        // console.log(next)
        // next(false)
        if(to.matched.some(function (item) {
                return item.path == "/post"
            })){
            next("/login")
        }
        else {
            next();
        }
    });
    // 元数据配置 改动代码
    // html 部分
     {
            path: "/user",
            meta: {
                required_login: true,
            },
            component: {
                template: `
                    <div>
                    <h1>用户管理</h1>
                    <router-link to="vip" append>vip</router-link>
                    <router-view></router-view>
                    </div>
                    `
            },
            children: [{
                path: "vip",
                meta: {
                  required_login: true,
                },
                component: {
                    template: '<h1>VIP</h1>'
                }
            }]
        }
    // js 部分
    router.beforeEach(function (to,from,next) {
        // console.log(to)
        // console.log(from)
        // console.log(next)
        // next(false)
        if(to.meta.required_login){
            next("/login")
        }
        else {
            next();
        }
    });
    匹配子路由以及元数据配置

    五、vue生命周期简介

    生命周期的钩子 LifeCycle hooks

    上面已经能够清晰的看到vue2.0都包含了哪些生命周期的钩子函数~~

    那么 执行顺序以及什么时候执行,我们上代码来看~~~

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    
    </head>
    <body>
    <div id="app">
        <p>{{message}}</p>
    </div>
    
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                message: "hello gaoxin!!"
            },
            beforeCreate: function () {
                console.group("beforeCreate  创建实例之前===========");
                console.log("el: " + this.$el); // undefined
                console.log("data: " + this.$data); // undefined
                console.log("message: " + this.message);
            },
            created: function () {
                console.group("Created:  创建实例完成===========");
                console.log("el: " + this.$el); // undefined
                console.log("data: " + this.$data); // 已被初始化
                console.log("message: " + this.message); // 已被初始化
            },
            beforeMount: function () {
                console.group("beforeMount  挂载前状态==========");
                console.log("el: " + this.$el); // 已被初始化
                console.log("data: " + this.$data); // 已被初始化
                console.log("message: " + this.message); // 已被初始化
            },
            mounted: function () {
                console.group("Mounted  挂载结束状态=============");
                console.log("el: " + this.$el); // 已被初始化
                console.log("data: " + this.$data); // 已被初始化
                console.log("message: " + this.message); // 已被初始化
            },
            beforeUpdate: function () {
                console.group("beforeUpdate  更新前状态=========");
                console.log("el: " + this.$el);
                console.log("data: " + this.$data);
                console.log("message: " + this.message);
            },
            updated: function () {
                console.group("Updated  更新完成状态");
                console.log("el: " + this.$el);
                console.log("data: " + this.$data);
                console.log("message: " + this.message);
            },
            beforeDestroy: function () {
                console.group("beforeDestroy  实例销毁之前");
                console.log("el: " + this.$el);
                console.log("data: " + this.$data);
                console.log("message: " + this.message);
            },
            destroyed: function () {
                console.group("Destoryed  实例销毁之后");
                console.log("el: " + this.$el);
                console.log("data: " + this.$data);
                console.log("message: " + this.message);
            }
    
        })
    </script>
    
    
    </body>
    </html>
    生命周期钩子函数

    create 和 mounted 相关

    执行上面代码,可以看到:

      beforecreated :el 和 data 并未初始化

      created:完成了data数据的初始化 el 没有

      beforeMount:完成了el 和 data的初始化

      mounted:完成了挂载

    也就是说~挂载前的状态是虚拟DOM技术,先把坑站住了~挂载之后才真正的把值渲染进去~

    update 相关

    我们在浏览器console里执行命令:

      app.message = "hello~"

    我们就出发了update相关的钩子函数~也就是说data里的值被修改会出发update的操作~

    destroy 相关

    我们在浏览器console里执行命令:

      app.$destroy();

    触发了destroy相关的钩子函数,也就是说组件被销毁~

    更改message的值~DOM中的值不变~也就是说DOM元素依然存在只是不受vue控制了~~

    六、Node.js  npm

    什么是Node.js  以及npm

    简单的来说 Node.js 就是运行在服务端的JavaScript,基于Chrome V8 引擎的。

    npm 是Node.js 的包管理工具。

    npm的安装和更新

    Node.js下载安装   Node.js 官网下载安装。npm自带的包管理工具。

    查看安装版本信息:

      --  node -v  查看Node.js 版本信息

      --  npm -v  查看npm版本信息

    更新npm到指定版本:

      --  npm install npm@5.3.0 -g

      -- npm install npm@latest -g 更新最新的稳定版本

    npm 常用操作

    之前我们用JQuery或者Bootstrap用cdn 或者直接手动下载并放入项目,而且要管理版本。

    有了npm,我们管理自己的依赖包以及版本更加简单。

    到自己项目目录下,进行以下命令:

      -- npm init -y    输入-y使用默认配置项 生成package.json文件。

      -- npm i jquery@0.0.0   简写install 为 i 下载依赖  不写@ 默认最新版本

      -- npm uninstall jquery  卸载依赖包

      -- npm update jquery   更新依赖包

      -- npm list  列出已安装的依赖

      -- npm install webpack --D 保存为开发环境依赖

      -- 老版本需要 --save 参数 现在不需要了

    我们的项目目录下会生成一个 node_modules 目录,我们用npm下的包会在这个目录下。

    我们所有的依赖信息放在package.json文件中,包括我们所有的依赖以及版本。

    如果我们删掉 node_modules目录,可以使用 npm i  来下载所有依赖。

    npm 常用配置项

    当我们用npm init 的时候用了参数 -y,如果不用-y我们可以进行一些配置。

    在我们的package.json文件中有很多配置项

      -- name  项目名字 中间不能有空格只能用小写

      -- version  项目版本

      -- description   项目描述信息

      -- main  项目的入口文件

      -- scripts 指定命令的快捷方式 npm run test     test是scripts里的键名 值为具体命令

      -- author 作者

      -- license  许可证

      -- dependencies  生成环境依赖的包以及版本信息

      -- devDependencies  开发环境的依赖

    webpack3

    webpack是什么

    webpack是一个模块打包器,它将根据模块的依赖关系进行静态分析,

    然后将这些模块按照指定的规则生成静态资源。

    那么,我们为什么要用这个东西呢~~因为前端的包袱太多,历史遗留问题太重~~~脑补吧......

    安装和配置

    webpack是跑在Node.js环境下的,所以确定自己有node环境。

    安装方式:

      -- npm install webpack -g  全局安装

      -- webpack  <要打包文件>  <打包后文件>     全局这种方式进行打包

      -- npm install webpack   在自己的项目下 npm init 后在下载webpack 这就是局部安装

      -- node_modules/.bin/webpack <要打包文件>  <打包后文件>   项目里要打包文件是入口文件

      -- 路径太长 太烦 可以自定义命令  在package.json 文件的 scripts下面自定义

    entry 和 output

    entry 入口文件  output 出口文件

    上面我们自定义命令的时候 命令太长了~~而且我们命令太多的时候我们需要每次都自定义多条命令~~

    我们可以把命令写在webpack.config.js文件中~~

    module.export = {
        // 所有的入口文件
        entry: {
             home: './main.js', 
             login: './login.js',
        }, 
        // 出口文件  
        output: {
             filename: '[name].bundle.js',
             path: __dirname + '/dist',
        }       
    }
    // backage.json  下的scripts
    scripts: {
         "pack": "node_moudles/.bin/webpack --watch"
    }
    
    //  运行命令
    npm  run pack
    webpack.config.js

    webpack4

    webpack的新特性

    1, webpack不在单独使用,需要webpack-cli

      -- 全局安装  npm install webpack webpack-cli -g -D

      -- 局部安装  npm install webpack webpack-cli -D

    2, 增加了模式区分 (development, production)

      --webpack --mode development/production 进行模式切换

      -- development 开发者模式 打包默认不压缩代码

      -- production  生产者模式 上线时使用,压缩代码。 默认是这个模式

    3,固定入口目录为src,与入口默认文件index.js,打包后文件在新增的dist目录下

      -- 当只有一个入口文件也就是src/index.js时,无需增加webpack.config.js

    4,多入口以及多出口

    entry: {
        // 多入口
        a: "./src/js/index.js",
        b: "./src/js/index2.js",
    }
    output: {
        // 多出口
        path: path.resolve(__dirname, 'dist'),
        filename: './js/[name].bundle.js'
    }
    webpack.config.js  

    vue-cli

    vue-cli是官方提供的快速构建这个单页面应用的脚手架。

    根据官方文档中的构件流程:

      -- 前提是已经安装了node.js 否则npm都用不了

      -- 1,使用npm全局安装vue-cli 

          npm install -g vue-cli

      -- 2, 安装完成后在自己的工作空间里

          vue init webpack vue-demo  

        输入命令后进入安装阶段,需要用户输入一些信息 这里省略了.....

      -- 3,切换到我们的项目目录下 

          cd vue-demo

          npm run dev

    目录结构:

      -- build 里面是一些操作文件,使用npm run * 时其实执行的就是这里的文件

      -- config 配置文件,执行文件需要的配置信息

      -- src 资源文件 所有的组件以及所有的图片 都在这个文件夹下

      -- node_modules  项目依赖包

      -- static 静态资源

      -- package.json   依赖包的json文件

    其实这里面命令很多~我们在后续项目中应用到再说~~~

    vue-cli配置JQuery、bootstrap

    第一步  下载安装

      -- npm install jquery 

      -- npm install bootstrap 

    第二步 修改build/webpack.base.conf.js

    const webpack = require('webpack')
    // 在module.exports里添加插件
    plugins: [
        new webpack.ProvidePlugin({
          $: "jquery",
          jQuery: "jquery",
          "windows.jQuery": "jquery",
          // Popper: ['popper.js', 'default']
        })
    ],
    //  *******下面是如果手动下载bootstrap用的*******
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          'vue$': 'vue/dist/vue.esm.js',
          '@': resolve('src'),
          // 如果是手动下载的bootstrap需要添加这个配置
          // 'assets': path.resolve(__dirname, '../src/assets'),
          // 'jquery': 'jquery/src/jquery'
        }
      },
    修改配置文件

    第三步 修改主程序的js文件 main.js

    import $ from 'jquery'
    import 'bootstrap/dist/css/bootstrap.min.css'
    import 'bootstrap/dist/js/bootstrap.min.js'
    main.js 

    vue-cli 3.0

    第一步 下载vue-cli 3.0

      -- npm install -g @vue/cli

      -- 报错 npm error  可以运行下面命令

        -- npm cache clean --force && npm cache verify

    第二步 创建项目

      -- vue create xxxx

      之后会出现很多选项,我们可以根据自己的习惯去选择~~

    第三步 目录结构以及配置文件

      -- vue-cli3 目录更加简单

      -- 我们手动在项目根目录下创建  vue.config.js 里面写vue的配置信息

    vue-cli3 配置jQuery、bootstrap

      -- 跟vue-cli2一样的配置,手动创建一个webpack.base.conf.js 

    七、Vuex简介

    vuex是一个专门为Vue.js设计的集中式状态管理架构。

    状态? 我们把它理解为在data中需要共享给其他组件使用的部分。

    Vuex和单纯的全局对象有以下不同:

    1、Vuex 的状态存储是响应式的。当vue组件从store中读取状态的时候,

      若store中的状态发生变化,那么相应的组件也会相应的得到高效更新。

    2、你不能直接改变store中的状态。改变store中的状态的唯一途径就是显示的

      提交(commit)mutation。这样使得我们可以方便的跟踪每一个状态的变化,

      从而让我们能够实现一些工具来帮助我们更好的了解我们的应用。

    安装使用vuex

      --  npm install vuex

    // main.js
    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import vuex from 'vuex'
    
    Vue.use(vuex)
    
    Vue.config.productionTip = false
    
    const store = new vuex.Store({
        state: {
          show: false,
        }
    });
    
    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: '<App/>'
    });
    vuex的使用一
    // 为了方便维护,我们通常把在src下面新建一个store文件夹,
    // 然后在里面新建一个index.js
    import Vue from 'vue'
    import Vue_x from "vuex"
    
    Vue.use(Vue_x);
    
    export default  new Vue_x.Store({
       state: {
          show: false,
        },
    });
    // 那么main.js要改成
    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import store from "./store"
    
    Vue.config.productionTip = false;
    
    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: '<App/>'
    });
    vuex的使用二

    State

    简而言之~~state是保存我们data中需要共享的数据。

    由于Vuex的存储是响应式的,从store实例中读取状态的最简单的方式就是在计算属性中返回某个状态。

    this.$store.state.count

    // 创建一个组件
    const Counter = {
      template: `<div>{{ count }}</div>`,
      computed: {
        count(){
          return this.$store.state.count
        }
      }
    };
    组件中获取vuex中状态

    Getter

    有时候我们需要从store中的state中派生出一些状态,例如对数据进行简单的计算。

    并且很多组件都需要用到此方法,我们要么复制这个函数,要么抽取到一个公共函数,多处导入。

    我们vuex提供了更加方便的方法,getter ,它就像计算属性一样,getter的返回值会根据它的依赖被

    缓存起来,只有它的依赖发生改变时,才会重新计算。

    Getter会接收state作为其第一个参数:

    import Vue from 'vue'
    import Vue_x from "vuex"
    
    Vue.use(Vue_x);
    
    export default  new Vue_x.Store({
       state: {
         count: 20,
       },
      // 通过 this.$store.getters.my_func
      getters: {
        my_func: function (state) {
          return state.count * 2
        }
      },
    
    });
    Getter使用

    Getter也可以接收getters为第二个参数:

    import Vue from 'vue'
    import Vue_x from "vuex"
    
    Vue.use(Vue_x);
    
    export default  new Vue_x.Store({
       state: {
         count: 20,
       },
      // 通过 this.$store.getters.my_func
      getters: {
        my_func: function (state) {
          return state.count * 2
        },
        // 通过 this.$store.getters.my_func_count
        my_func_count: function (state, getters) {
          return getters.my_func.length
        }
      },
    
    });
    Getter使用

    Mutation

    更改Vuex中的store中的状态的唯一方法是提交mutation。

    每个mutation都有一个字符串的事件类型(type),和一个回调函数handler。

    也就是说我们要触发mutation中定义的方法(type),然后才会执行这个方法(handler)。

    这个方法就是我们更改状态的地方,它会接收state为第一个参数,后面接收其他参数:

    import Vue from 'vue'
    import Vue_x from "vuex"
    
    Vue.use(Vue_x);
    
    export default  new Vue_x.Store({
       state: {
         count: 20,
       },
      // 需要通过 this.$store.commit('increment', 10)
      mutations: {
         increment (state, n) {
           // 变更状态
           state.count += n
         }
      }
    
    });
    Mutation基本使用

    Mutation需要遵守Vue的响应规则

    既然vuex中的store中的状态是响应式的,那么当我们状态变更时,监视状态的vue组件也会更新。

    这就意味着vuex中的mutation也需要与使用vue一样遵守一些注意事项:

      -- 1,最好提前在你的store中初始化好所有的所需要的属性

      -- 2,当对象需要添加属性时,你应该使用

          --  Vue.set(obj, 'newProp', 123)

          --  以新对象代替老对象  state.obj = { ...state.obj, newProp: 123}

    八、axios的简单使用

    基于Promise的HTTP请求客户端,可以同时在浏览器和node.js使用。

    使用npm安装axios

      -- npm install axios -D

    基本的配置

    // main.js
    import axios from "axios"
    
    Vue.prototype.$axios = axios
    
    // 组件中
    methods: {
         init () {
            this.$axios({
                 method: "get",
                 url: "/user"
            })
        },
    };
    axios的基本配置

    基本的使用

    test(){
              this.$axios.get(this.$store.state.apiList.course,{
                params: {
                  id: 123,
                }
              }).then(function (response) {
                // 请求成功回调函数
              }).catch(function (response) {
                // 请求失败的回调函数
              })
    }
    get请求
    test(){
              this.$axios.post(this.$store.state.apiList.course,{
                  course_title: "Python",
                  course_price: "19.88"
              }).then(function (response) {
                // 请求成功回调函数
              }).catch(function (response) {
                // 请求失败的回调函数
              })
    }
    post请求
    function getCourse(){
              return this.$axios.get('/course/12')
            }
    function getCourse_all() {
              return this.$axios.get('/course')
            }
    this.$axios.all([getCourse_all(),getCourse()])
              .then().catch()
    发送多个并发请求
    methods: {
              init(){
                var that = this
                this.$axios.request({
                  url: that.$store.state.apiList.course,
                  method: 'get'
                }).then(function (data) {
                  if (data.status === 200){
                      that.courseList = data.data
                  }
                }).catch(function (reason) {
                  console.log(reason)
                })
              }
    },
    axios.request

    九、Vuex 坑!

    1.setTimeout/ setInterval

    • 场景一 :this指向改变无法用this访问vue实例
      mounted(){
        setTimeout( function () {
        //setInterval同理
        console.log(this); //此时this指向Window对象
        },1000) ;
      }
    • 解决方法 :使用箭头函数或者缓存this
      //箭头函数访问this实例因为箭头函数本身没有绑定this
      setTimeout(() => {
        console. log(this);},  500) ;
        //使用变量访问this实例let self=this;
      },1000);
      setTimeout (function () {
        console. log(self);//使用self变量访问this实例
      }, 1000) ;

    setInterval路由跳转继续运行并没有销毁

    • 场景一 :比如一些弹幕,走马灯文字,这类需要定时调用的,路由跳转之后,因为组件已经销毁了,但是setlnterval还没有销毁,还在继续后台调用,控制台会不断报错,如果运算量大的话,无法及时清除,会导致严重的页面卡顿。

      • 解决方法 :在组件生命周期beforeDestroy停止setInterval
      created() {
           this.intervalid = setInterval(() => {
              this.layerError = "";
              this.Timer = null;
          }, 100000);
       }
      beforeDestroy( ){
        //我通常是把setInterval( )定时器赋值给this实例,然后就可以像下面这么暂停。
        clearInterval(this.intervalid);
      }

    2.Vue路由拦截浏览器后退实现草稿保存类似需求

    • 场景一 :为了防止用户突然离开,没有保存已输入的信息。

      • 解决方法 :
      //在路由组件中:mounted(){},
      beforeRouteLeave (to, from, next) {
          if(用户已经输入信息){
            //出现弹窗提醒保存草稿,或者自动后台为其保存
          }else{
            next(true);//用户离开
          }
      }

    3.自定义组件添加click等事件不生效

    • 场景一 :一些自定义组件,需要额外添加一些事件来实现一些特定需求
      <template>
        <el-progress type="circle" :percentage=“0" @click="stopProgress">   </elprogress>
      </template>
      <script>
        export default {
           methods:{
                stopProgress() { 
                console.log('停止')
                }
            }
        }
      </script>
    • 解决方法:使用.native修饰符
      <template>
        <el-progress type="circle" :percentage="0" @click.native="stopProgress"></el-progress>
      </template>
      <script>
        export default {
            methods:{
                stopProgress() { 
                console.log('停止')
                }
            }
        }
      </script>

    4.手动操控自定义组件

    • 场景一 :一些自定义组件,需要去获取组件对象进行一些其他的Dom操作

      • 解决方法 :使用ref属性暴露组件获取句柄
      <template>
        <el-progress type="circle" :percentage="O" ref="progress"></el-progress></template>
      <script>
        this.$refs.progress //组件对象实例, 可以手动调用组件的内置方法和属性
        this.$refs.progress.$el //组件 对象的最外层dom元素
      </script>

    5.深度作用选择器

    • 场景一 : scoped的样式,希望影响到子组件的默认样式

    在样式中设置完scoped在浏览器解析为如下图这样,a是个div,a div里面包含一个组件里面解析完了div的样式名字为b,想在父组件影响到子组件的默认样式。解决方法:

      <style scoped>
        .a >>> .b { /* ... */ }
      </style>
        //有些像Sass之类的预处理器无法正确解析>>>。这种情况下你可以使用/deep/操作符取而代之- - - -这是一个>>>的别名,同样可以正常工作。  <style scoped lang=“scss”>
        .a /deep/ .b { /* ... */ }
      </style>

    6.Vue数组/对象更新视图不更新

    • 场景一 :很多时候我们习惯于这样操作数组和对象
      data() { 
        return {
            arr: [1,2,3],
            obj:{
              a: 1,
              b: 2 
            }
        }; 
      },
     // 数组更新视图不更新
     this.arr[0] = 'OBKoro1';
     this.arr.length = 1;
     console.log(arr);// ['OBKoro1']; 
     // 数据更新,对象视图不更新     
     this.obj.c = 'OBKoro1';
     delete this.obj.a; //删除对象的属性
     console.log(obj);  // {b:2,c:'OBKoro1'}
    • 解决方法 :

      • this. $set(你要改变的数组/对象,你要改变的位置/key,你要改成什么value)
      • 数组原生方法触发视图更新( vue官网可查):
      • 整体替换数组/对象

    7.Vue Filters过滤器的使用

    • 场景一 :常见的数据文本的格式化
      <!– 在双花括号中 –>
     <div>{{ message | DateFormat }}</div>    //展示正确时间
     <!– 在'v-bind'中 –>
     <div v-bind:id='rawId | formatId'></div>
     //Demo:一个日期过滤器返回yyyy- MM-ddhh:mm:ss的样式
     //引入一个提前写好日期格式化的js  import dayjs from ‘dayjs’;
     export default {
        data() {
           return {
                   //时间毫秒
                   message:18324798324789
               }
       },
       filters: {
             //传入进行日期格式化
         DateFormat(value) {
           return dayjs(value).format(“YYYY-MM-DD HH:mm:ss")
             }
       }
     }

    8.Vue深度watch与watch立即触发回调

    • 场景一 :在watch里面监测对象里面对应的值是监测不到的,可以用如下方法。

      • 选项: deep
      • 在选项参数中指定deep:true,可以监听对象中子属性的变化。
      • 选项: immediate
      • 在选项参数中指定immediate:true,将立即以表达式的当前值触发回调,也就是默认触发一次。
      watch: {
       obj: {
           handler(val, oldVal) {
             console.log('属性变化触发这个回调;',val, oldVal);
           },
           deep: true // 监测这个对象中每一个属性的变化
       },
       step: { // 属性 //watch
          handler(val, oldVal) {
           console.log('默认触发一次', val, oldVal);
          },
          immediate: true // 默认触发一次
       }
     }</cod  e> 

    参考链接:https://www.vue-js.com/topic/5be446a7fffaa30f33091cf1

  • 相关阅读:
    myeclipse导入项目中的乱码问题的解决
    myeclipse中的jar包的引入与新建
    myeclipse如何修改默认存储文件路径
    oracle迁移数据到mysql
    如何设置myeclipse的编码格式
    tns的查找与修改
    在PL/SQL中输入SQL语句时关键字的首字母自动变成大写
    滤器处理中文编码
    题解导航
    莫队总结应用
  • 原文地址:https://www.cnblogs.com/bubu99/p/11988519.html
Copyright © 2011-2022 走看看