Vue(基础:自定义指令&路由)

410 阅读5分钟

自定义指令

官方:对普通 DOM 元素进行底层操作,这时候就会用到自定义指令

全局指令

全局指令是指可以在多个Vue实例中使用的指令,注册全局指令时,指令名字不要用大写字母且不要加V-,但是在使用时需要加上V-,格式如下:

Vue.directive('指令名',{定义对象})
//这里的定义对象中有5个钩子函数:bind、inserted、update、componentUpdated、unbind

使用

需求:自定义全局指令v-focus,让文本框自动获取焦点

(1)注册自定义全局指令,调用钩子函数

//注意:一个指令定义对象可以提供如下几个钩子函数 (均为可选)
// 注意:和JS行为有关的操作,最好在 inserted 中去执行,放置 JS行为不生效,比如el.focus()
//注册
 Vue.directive('focus', {
        bind: function (el) { // 只调用一次,指令第一次绑定到指定元素时调用。在这里可以进行一次性的初始化设置
        },
        inserted: function (el) {  // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
            el.focus()
        },
        updated: function (el) {  // 当VNode更新的时候,会执行 updated, 【可能会触发多次】
        }
    })

(2)在指定文本框使用自定义全局指令

<!--使用时一定记得加“V-”-->
<input type="text" id="search" v-model="keywords" v-focus>

钩子函数

  • bind:当指令绑定在 HTML 元素上时触发,只执行一次。在这里可以进行一次性的初始化设置
  • inserted:被绑定的元素,插入到父节点的 DOM 中时调用(仅保证父节点存在)。
  • update:组件更新时调用。当指令绑定的元素状态/样式、内容(这里指元素绑定的 vue 数据) 发生改变时触发
  • componentUpdated:组件与子组件更新时调用。
  • unbind:当指令绑定的元素从 dom 中删除时触发,只执行一次。

钩子函数的参数:

官网解释: image.png 例子:设置Dom节点元素颜色样式

<div id="app">
    搜索框:
    <input type="text" id="search" v-model="name" v-color>
</div>
<script>
    //自定义全局指令 v-color:设置DOM元素的color属性
    Vue.directive('color', {
        bind: function (el,binding) {
            el.style.color = 'red';
            el.style.fontWeight=600;
            console.log(binding.name); //打印结果:color
            console.log(binding.value); //打印结果:red
        },
    })
    new Vue({
        el: '#app',
        data: {
            name: ''
        }
    })
</script>

私有指令

在某一个 vue 对象内部自定义的指令称之为私有指令。这种指令只可在当前vue对象的挂载区域有用。

<div id="app">
    <span v-fontweight="600">hello,word</span>
</div>
<script>
    new Vue({
        el: '#app',
        //此处的自定义私有指令:只在#app区域内可用
        directives: {
            'fontweight': {
                bind: function (el, binding) {
                //设置字重
                    el.style.fontWeight = binding.value;
                }
            }
        }
    })
</script>

上述代码还可以简写为这样

//自定义私有指令(简写形式)
directives: {
    'fontweight': function (el, binding) { 
    //注意,这个function等同于把代码写到了 bind钩子和update钩子中去了
        el.style.fontWeight = binding.value;
    }
}

路由基础

学习路由基础之前我们先来了解一下什么是SPA和MPA?

SPA和MPA

  • SPA ,只有一个HTML页面,通过路由实现页面内的局部切换,公共资源部分只加载一次;我们熟知的JS框架如react,vue,angular,ember都属于SPA(我的理解:单页面局部资源的切换)。
  • MPA ,每次切换页面资源都需要重新加载,一般我们之前平常写的a标签就是这样一个原理,实现页面切换(我的理解:多页面全部资源的切换)
  • 区别 | | SPA | MPA | | ------------- | ----------------------------------- | -------------------------------------- | | 组成 | 一个外壳页面和多个页面片段组成 | 多个完整页面构成 | | 资源共用(jss,css) | 共用,只在外壳部分加载 | 不共用,每个页面都要加载 | | 刷新方式 | 局部刷新或者更改 | 整体刷新 | | url模式 | 哈希模式(a.com/#/page1.com/#/page2.com) | 历史模式(a.com/page1.com; a.com/page2.com) | | 用户体验 | 页面片段切换快,用户体验好 | 页面切换加载慢,体验不好 | | 转场动画 | 容易实现 | 无法实现 | | 数据传递 | 容易 | 依赖url传参,或者cookie、localstorage等 | | 搜索引擎优化(SEO) | 需要单独方案,实现较为困难 | 简单 | | 开发成本 | 难度高,借助专业的框架 | 难度低,但是页面重复代码多 | | 维护成本 | 相对较低 | 相对较高

路由介绍

简单的说,路由是根据不同的 url 地址展示不同的内容或页面。

前端路由是如何做到URL和内容进行映射呢? 答:监听URL的改变

前端路由原理

路由的概念在软件工程中出现,最早是在后端路由中实现的。服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示。

URL的hash模式

URL的hash也就是锚点(#), 本质上是改变window.location的href属性;我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新;另外每次 hash 值的变化,还会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作。

<div id="app">
    <a href="#/home">home</a>
    <a href="#/about">about</a>
    <div id="router-view"></div>
</div>
<script>
    const routerView = document.querySelector('#router-view');
    // url的hash
    // URL的hash也就是锚点,本质上就是改变window.location 的 href 属性
    // 我们可以通过直接赋值location.hash 来改变 href 但是页面不会刷新
    window.addEventListener('hashchange',()=>{
        console.log(location.hash);
        if(location.hash==="#/home"){
            routerView.innerHTML = "home";
        }else if(location.hash==="#/about"){
            routerView.innerHTML = "about";
        }
    })
</script>

hash的优势就是兼容性更好,但是缺陷在浏览器地址栏会留有一个#,显得不像一个真实的路径,特殊情况下浏览器还会忽略#,会造成一定的麻烦。

HTML5中的History模式

因为HTML5标准发布。多了两个 API,pushStatereplaceState,通过这两个 API 可以改变 url 地址且不会发送请求。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面;

<div class="nav">
    <a onclick="linkTo(1)">link1</a>
    <a onclick="linkTo(2)">link2</a>
</div>
<div id="router-view">
</div>
<script>
    var view = document.getElementById('router-view');
    function linkTo(link){
        switch(link) {
            case 1: {
                window.history.pushState({a:1}, 'mylink1', '/link1');
                view.innerHTML = 'link1 content';
                break;
            }
            case 2: {
                window.history.pushState({a:1}, 'mylink2', '/link2');
                view.innerHTML = 'link2 conetnt';
                break;
            }
            default: 
                return;
        }
        return false;
    }
</script>