自定义指令
官方:对普通 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 中删除时触发,只执行一次。
钩子函数的参数:
官网解释:
例子:设置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,pushState 和 replaceState,通过这两个 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>