该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。
你是否有在使用网页的时候填了很多资料,但是一个不小心重整网页就导致辛苦填写的资料都消失不见了,今天我们就要来针对输入表单的使用者体验来进行优化的部分。
我们希望可以达到像是下面的效果。
你会发现在我输入了内容之後重新整理网页,表单里面的内容都还有留下,所以今天不管我怎麽输入内容,他都会暂存在你的网页之中,今天我们就要来看看再 Vue 里面是如何实作的。
暂存的部分你可以选用 cookie
或是 localStorage
,在这边我选用 localStorage
来暂存。
纯 JavaSrcipt 这边我就提供一个思路,不全部写出来了
// 1. 抓取 input 表单实体
const el = document.getElementById("#name");
// 3. localStorage 写入暂存资料
const handSave = (e) => {
localStorage.setItem('form-name', e.target.value);
}
// 2. 监听 input 跟 change 事件,不监听 keyUp 是因为手机键盘无法触发
el.addEventListener("input", handSave);
el.addEventListener("change", handSave);
总之就是去监控表单是否有被填入内容,如果触发了 input
或是 change
,就把输入的内容给写入 localStorage
。
首先针对表单一个个去绑定事件会有点太重工了,而且要处理也不是这麽方便,所以这时候我就有一个想法,我们不是透过 v-model
可以去同步表单的资料吗?那如果再有一个跟 v-model
相似的语法,但是具有暂存的功能的话,那不是方便很多,所以今天就来自己写一个有暂存功能的 v-model
。
我希望这样,有一个 v-model-save
的语法,它的功能跟 v-model
一模一样,然後还增加了储存 localStorage
的功能,我们来看一下怎麽做。
const name = ref("");
<input
class="name"
type="text"
placeholder="输入使用者名称"
v-model-save="name"
/>
首先要做这样一个 v-model-save
语法就需要我们之前所教的 vue 的 directive
这个功能,首先在 directive
里面我们要去监听 input
跟 change
事件。
app.directive('model-save', {
mounted(el, binding) {
el.handSave = (e) => {}
el.addEventListener("input", el.handSave);
el.addEventListener("change", el.handSave);
},
unmounted(el) {
el.removeEventListener("input", el.handSave);
el.removeEventListener("change", el.handSave);
},
})
在这边你会看到我在 mounted
传进来的 el
塞入一个 handSave
的 function,而不是我们一般去定义新的function 那样,为什麽? 因为我需要在 unmounted
去 removeEventListener
,但是我又不想把这个 function 丢到塞到 vue 或是 window 里面,所以这边我选择塞到 el
里面。
接下来我们要来定义一下储存的部分,这边有要定义三个储存的 function
// 1. 写入 Input DOM 的 value
const setInputValue = (value) => el.value = value;
// 2. 同步 Vue 中宣告的的变数(资料)
const setSyncDate = (value) => binding.instance[el.className] = value;
// 3. 塞入 localStorage 暂存资料
const setLocalStorage = (value) => localStorage.setItem(`form-${el.className}`, value);
这边有个重点,就是你的 class name
!
在这边我们是透过你的 class name
还有你宣告变数的名称,让它们保持一致来做比对,让它可以更简单的去同步表单上面以及变数上面的资料。
你会看到我使用了 binding.instance
,这个 instance
里面就是你透过 directive 传入的 proxy
物件,所以只去修改里面的 proxy
物件参数,自然上层传入的资料就会跟者被修改了。
app.directive('model-save', {
mounted(el, binding) {
const setInputValue = (value) => el.value = value;
const setSyncDate = (value) => binding.instance[el.className] = value;
const setLocalStorage = (value) => localStorage.setItem(`form-${el.className}`, value);
// 检查目前是 localStorage 有没有暂存的资料
if(!localStorage[`form-${el.className}`]){
setLocalStorage(binding.value);
}
setInputValue(localStorage[`form-${el.className}`]);
setSyncDate(el.value);
el.handSave = (e) => {
setLocalStorage(e.target.value);
setSyncDate(e.target.value);
}
el.addEventListener("input", el.handSave);
el.addEventListener("change", el.handSave);
},
unmounted(el) {
el.removeEventListener("input", el.handSave);
el.removeEventListener("change", el.handSave);
},
})
在这边我会特别在 localStorage 储存的 key
前面加上一个自己定义的字串,去做区分,毕竟整个网站还会有其他地方用到localStorage,避免 key
的冲突,所以我前面就会加一个前缀字做区分。
接下来你就可以把你要的资料都定义好
setup(){
const name = ref("");
const password = ref("");
const submitLogin = () => {
console.log({name, password})
for (var key in localStorage) {
if (/^form-(.+)/.test(key)) {
localStorage.removeItem(key)
}
}
alert("登入成功");
}
return {
name,
password,
submitLogin
}
}
这边你会看到我在 submitLogin
的 function 中去清掉了跟表单有关的 localStorage,因为毕竟表单送出了,自然暂存也就不需要了,那接下来我们就可以在 input 上面使用 v-model-save
。
<div class="center">
<div class="input-box">
<p>NAME</p>
<input
class="name"
type="text"
placeholder="输入使用者名称"
v-model-save="name"
/>
</div>
<div class="input-box mb-20">
<p>PASSWORD</p>
<input
class="password"
type="password"
placeholder="输入密码"
v-model-save="password"
/>
</div>
<button class="btn" @click="submitLogin">登入</button>
</div>
codepen 范例:https://codepen.io/MikeCheng1208/pen/vYZQeVq
在 Safari 上 cookie 跟 localStorage 的使用最多就是 7 天,所以如果你的暂存功能是会需要一个很长时间的话,可能会需要改变其他做法,相关内容可以参考一下文件。
Intelligent Tracking Prevention 2.1 : https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/
Apple adds a 7-Day Cap on All Script-Writable Storage : https://support.didomi.io/apple-adds-a-7-day-cap-on-all-script-writable-storage
今天介绍了一个很实际可以防呆且增加使用者体验的方式,透过 directive
能玩的花样其实还蛮多的,就看我们自己在实作上面要依照何种情境来做选择,如果你有其他 directive
的使用方式也可以在下面留言分享给大家知道。
Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。
我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc
那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc
Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng
>>: [Day-15] - Spring 标示说明性注解运用与设计
django 基础篇 主要说明如何创建一个基本的 django 服务。 基本工具 env虚拟机 - ...
本来想除了管理功能外全部都在Line介面里面解决,但做了一阵子觉得越想越不对劲,重新考量了一下思路,...
前言 假日没有行情,所以只能平日来做取得行情资料的工作,所以今天的文章是根据期货行情,模拟价格修改的...
前言 每当我们修改工作表或者仪表板的时候,Tableau Desktop 会立即进行运算以显示出对应...
在现在这种讲求快速开发的开发模式,我们通常不太会自己将所有功能都自己硬刻出来,而是会去使用第三方的套...