Vue.js and jQuery datetimepicker、jQuery autocomplete
前言
把Vue.js真正運用在工作上,其複雜的開發環境就會出現一些地雷需要留意
畢竟現實工作中的專案,同一頁面會用到的JS函式庫不會只有Vue.js,通常還會混搭
地雷事項
1.jQuery的.val("指派值") 不會觸發JS事件,沒有事件觸發,Vue不會探測到資料改變
由於Vue.js的v-model指令預設監聽JS的input事件
所以遇到jQuery日期選擇器或jQuery autocomplete這種會使用到 $("input").val("指派值") 的插件
即使v-model指令雙向綁定到<input>DOM元素,實際上Vue.js是不會獲取到jQuery插件給予的值
有幾種解法:
解法1.修改jQuery插件原始碼,觸發input事件 (治本方法,就算沒使用Vue.js,也不影響其他功能運作)
例如:jQuery autocomplete (jQuery自動完成懶人包)
解法來源:jQuery修改input的val能否触发v-model的更新
但並非每個jQuery插件原始碼都那麼好修改,例如:DateTimePicker
所以下面再提供另一方法
解法2.在<input>的blur事件中,透過$event.target.value取得<input>的值並指派給雙向綁定的對象
※根據我的測試,jQuery插件有的會觸發Vue.js的change事件(jQuery autocomplete),有的不會觸發Vue.js的change事件(上述的jQuery datetimepicker),所以目前我覺得在blur事件中處理比較靠譜
<!DOCTYPE html>
<html lang="utf-8">
<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>測試頁</title>
<link href="~/css/bootstrap.css" rel="stylesheet" type="text/css" />
<!--日期選擇jquery datetimepicker 出處: http://xdsoft.net/jqplugins/datetimepicker/-->
<link href="~/Content/jQuery_datetimepicker/jquery.datetimepicker.css" rel="stylesheet" />
<style type="text/css">
body {
padding-top:30px;
}
</style>
</head>
<body>
<div class="container" id="mydateApp">
<div class="row">
<div class="form-group col-xs-12">
<!-- 輸入日期-->
<label>從</label>
<input type="text" name="mydateFrom" v-model="mydateFrom" v-on:blur="mydateFromBlur" /> ~
<label>到</label>
<input type="text" name="mydateTo" v-model="mydateTo" v-on:blur="mydateToBlur" />
</div>
<div class="form-group col-xs-12">
<button type="button" class="btn btn-primary" v-on:click="mySubmit">送出</button>
</div>
<div v-text="submitResult">
</div>
</div>
</div>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<!--Vue.js-->
<script src="~/Scripts/vue.js"></script>
<!--日期選擇器-->
<script src="~/Content/jQuery_datetimepicker/jquery.datetimepicker.js"></script>
<script type="text/javascript">
let vue_mydateApp = new Vue({
el: "#mydateApp",
data: {
mydateFrom: "", //輸入的日期
mydateTo: "",
submitResult:"" //顯示結果
},
methods: {
mydateFromBlur: function ($event) {
let vm = this;
vm.mydateFrom = $event.target.value;//更新雙向綁定對象的值
},
mydateToBlur: function ($event) {
let vm = this;
vm.mydateTo = $event.target.value;//更新雙向綁定對象的值
},
mySubmit: function () {
let vm = this;
vm.submitResult = `${vm.mydateFrom}~${vm.mydateTo}`;
}
}
});//end Vue app
//DOM元素啟用jQuery datetimepicker
$(function () {
$("input[name='mydateFrom'],input[name='mydateTo']").datetimepicker({
lang: 'ch',//簡中
timepicker: false,//不選擇時間
format: 'Y/m/d',//時間格式
});
});
</script>
</body>
</html>
這種情況已經是工程師自行決定何時更新數據,所以在<input>使用v-model雙向綁定 或 v-bind:value 單向綁定 value屬性 兩種寫法已經都沒差
<!--輸入日期-->
<label>從</label> <!--也可以單向綁定value屬性-->
<input type="text" name="mydateFrom" v-bind:value="mydateFrom" v-on:blur="mydateFromBlur" /> ~
<label>到</label>
<input type="text" name="mydateTo" v-bind:value="mydateTo" v-on:blur="mydateToBlur" />
採用第二種解法需留意,對於有些jQuery插件(jQuery autocomplete),需要等待一點時間讓<input>填完值後才能更新雙向綁定的對象,所以寫法要加上setTimeout↓
your_blur_event: function ($event) {
let vm = this;
setTimeout(function () {
vm.yourdata = $event.target.value;
}, 200);//等待值確實填入input
}
※ ↑ 如果用戶操作速度超快,有可能雙向綁定的對象還沒更新時,用戶就點擊、執行其他功能導致前端邏輯不正確,setTimeout會是效能瓶頸,若有使用,請謹慎思考前端操作流程
解法3.找Vue.js的第三方插件以取代jQuery 插件
※2019.01.18追記:jQuery叫用 $("input[type='checkbox'] , input[type='radio']").prop("checked",true);,也必須留意不會觸發input事件
※2019.1.21追記:個人使用的jQuery DateTimePicker 還有另一方法可以給予Vue.js data,利用jQuery監聽<input>的change事件,當change事件觸發時,再用.val()抓DOM元素的值給予Vue.js的data值
<!--日期選擇jquery datetimepicker 出處: http://xdsoft.net/jqplugins/datetimepicker/-->
<link href="~/Content/jQuery_datetimepicker/jquery.datetimepicker.css" rel="stylesheet" />
<div id="myApp">
<input type="text" name="myDate" v-model="myDate" />
</div>
<!--引用jQuery-->
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<!--引用 Vue.js-->
<script src="~/Scripts/vue.js"></script>
<!--日期選擇jquery datetimepicker 出處: http://xdsoft.net/jqplugins/datetimepicker/-->
<script src="~/Content/jQuery_datetimepicker/jquery.datetimepicker.js"></script>
<script type="text/javascript">
let vueApp = new Vue({ //實例化Vue App
el: "#myApp",
data: {
myDate: ""
}
});
/*以下是jQuery的操作*/
$(function () {
$("input[name='myDate']").datetimepicker({//啟用jQuery datetimepicker
lang: 'ch',//簡中
timepicker: false,//不選擇時間
format: 'Y/m/d',//時間格式
});
/*解法↓*/
$("input[name='myDate']").change(function () {
//vueApp為Vue.js的全域實體變數
vueApp.myDate = $(this).val();//從jQuery抓DOM的值指派給Vue.js的data
});
});
</script>
↑ 但不是每個jQuery plugin都可以這樣做,我使用的 jQuery autocomplete (jQuery自動完成懶人包) ,就算在jQuery監聽的change、blur事件中使用.val() 抓DOM元素的值
.val() 抓到值仍然不是 autocomplete 下拉清單中的用戶選定值,所以要使用什麼解法真的都要試過一遍Orz
2.雖然同樣是表單輸入欄位,但<input type="hidden" />隱藏欄位必須用v-bind:value的指令才能正確存取DOM元素的值
隱藏欄位注定偵測不到用戶的input事件,所以用v-model指令無意義,只能綁定DOM元素的value屬性,存取才會正常,例如:表單提交
解法來源:v-model do not work with hidden input ?
↓ ASP.net MVC的View畫面
<!DOCTYPE html>
<html lang="utf-8">
<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>測試頁</title>
<link href="~/css/bootstrap.css" rel="stylesheet" type="text/css" />
<style type="text/css">
body {
padding-top:30px;
}
</style>
</head>
<body>
<div class="container" id="myApp">
<div class="row">
<form action="@Url.Action("Test","Common")" method="post">
<input type="hidden" name="myHidden" v-bind:value="myHidden" /> <!--如果這裡的value預設值和Vue不一樣的話,則以Vue為主-->
<div class="form-group col-xs-12">
<button type="button" class="btn btn-info" v-on:click="modifyHidden">修改hidden的值</button>
<button type="button" class="btn btn-info" id="btnQueryHidden">jQuery抓hidden的值確認看看</button>
<button type="submit" class="btn btn-primary">送出表單</button>
</div>
<div>
<!--剛剛提交的結果-->
@ViewData["myHidden"]
</div>
</form>
</div>
</div>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<!--Vue.js-->
<script src="~/Scripts/vue.js"></script>
<script type="text/javascript">
let vue_mydateApp = new Vue({
el: "#myApp",
data: {
myHidden: "vue_init", //hidden的值
},
methods: {
modifyHidden: function ($event) {
let vm = this;
vm.myHidden = Date.now();//修改hidden值
}
}
});//end Vue app
//以下是jQuery世界
$(function () {
$("#btnQueryHidden").on("click", function () {
alert($("input[type='hidden']").val());
});
});
</script>
</body>
</html>
3.創建Vue實例後,才針對資料物件追加屬性的寫法
Javascript的物件可以動態追加屬性(鍵值),但有些地雷需要留意
↓以下是錯誤寫法
<div class="container" id="myApp">
<div class="row">
<div class="form-group col-xs-12">
<button type="button" class="btn btn-primary" v-on:click="mySubmit">追加屬性</button>
</div>
<div v-text="myObj.newKey"></div> <!--顯示新追加屬性的值-->
</div>
</div>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<!--Vue.js-->
<script src="~/Scripts/vue.js"></script>
<script type="text/javascript">
let vue_myApp = new Vue({
el: "#myApp",
data: {
myObj: {
name: "高級打字員"
}
},
methods: {
mySubmit: function () {
let vm = this;
vm.myObj.newKey = "newValue"; //追加新屬性,不會響應式
}
}
});//end Vue app
</script>
↓這樣寫才正確(適用追加一個屬性)
<body>
<div class="container" id="myApp">
<div class="row">
<div class="form-group col-xs-12">
<button type="button" class="btn btn-primary" v-on:click="mySubmit">追加屬性</button>
</div>
<div v-text="myObj.newKey"></div><!--顯示新追加屬性的值-->
</div>
</div>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<!--Vue.js-->
<script src="~/Scripts/vue.js"></script>
<script type="text/javascript">
let vue_myApp = new Vue({
el: "#myApp",
data: {
myObj: {
name: "高級打字員"
}
},
methods: {
mySubmit: function () {
let vm = this;
//第二個參數是字串,第三個參數則任意型別
Vue.set(vm.myObj, "newKey", "New Hello World!!");//追加新屬性,響應式的正確寫法
}
}
});//end Vue app
</script>
</body>
↓ 追加多個屬性的正確寫法
<body>
<div class="container" id="myApp">
<div class="row">
<div class="form-group col-xs-12">
<button type="button" class="btn btn-primary" v-on:click="mySubmit">追加屬性</button>
</div>
<ul>
<li v-for="(value , key) in myObj" v-text="( key + ' '+ value)"></li>
</ul><!--顯示新追加屬性的值-->
</div>
</div>
<script src="~/Scripts/jquery-3.2.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<!--Vue.js-->
<script src="~/Scripts/vue.js"></script>
<script type="text/javascript">
let vue_myApp = new Vue({
el: "#myApp",
data: {
myObj: {
name: "高級打字員"
}
},
methods: {
mySubmit: function () {
let vm = this;
vm.myObj = Object.assign({}, vm.myObj, {
age: 27,
favoriteColor: 'Vue Green',
threeKey:"threeKeyValue"
})
}
}
});//end Vue app
</script>
</body>
↓這種的,就沒救了
4.留意修改、刪除Array的幾個限制
※附送上移、下移的功能實作
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<title>Hello, Vue.js!</title>
<style type="text/css">
body {
padding-top: 30px;
}
</style>
</head>
<body>
<div class="container" id="myApp">
<div class="row">
<div class="form-group col-12">
<button type="button" class="btn btn-warning" v-on:click="EditMyArray">把myArray的b替換成z</button>
<button type="button" class="btn btn-danger" v-on:click="ClearMyArray">清除myArray</button>
<button type="button" class="btn btn-success" v-on:click="RestoreMyArray">恢復myArray</button>
</div>
<div class="form-group col-12">
顯示myArray資料↓
<ul v-if="myArray.length>0">
<li v-for="(item , index) in myArray" v-text="item"></li>
</ul>
</div> <!--end .form-group-->
<div class="form-group col-12">
<button type="button" class="btn btn-warning" v-on:click="Editinit_users">把init_users的username Allen替換成ALLEN</button>
<button type="button" class="btn btn-danger" v-on:click="Clearinit_users">清除init_users</button>
<button type="button" class="btn btn-success" v-on:click="Restoreinit_users">恢復init_users</button>
</div>
<div class="form-group col-12">
顯示init_users資料↓
<ul v-if="init_users.length>0">
<li v-for="(user , index) in init_users">
id:{{user.id}}
<b> username:{{user.username}} </b>
email:{{user.email}} age:{{ user.age}}
sort:{{user.sort}}
</li>
</ul>
</div> <!--end .form-group-->
<div class="form-group col-12">
輸入字串並上移、下移資料↓
<ul v-if="init_users.length >0" style="list-style:none;">
<!--此範例會改變陣列順序,由於出現沒被綁定的表單欄位,故必須事先v-bind:key才能跟著變換順序-->
<li v-for="(user , index) in init_users" v-bind:key="user.id" style="border:1px solid #000;" >
id:{{user.id}} username:{{user.username}} age:{{ user.age}}
<br />
email:
<input type="text" v-model="user.email" placeholder="輸入email"
class="form-control" style="display:inline-block;width:25%;" />
<input type="text" placeholder="我沒被綁定" />
<br />
<button type="button" class="btn btn-info" v-on:click="Up(user,index);">上移</button>
<button type="button" class="btn btn-info" v-on:click="Down(user,index);">下移</button>
</li>
</ul>
</div> <!--end .form-group-->
</div> <!--end .row-->
</div> <!--end .container-->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<!-- 引用Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
//模擬這是後端預先準備的Json資料
let init_users = [
{
id: 1,
"username": "Allen",
"email": "Allen@april.biz",
age: 32,
sort:1 //sort通常會存在後端的DB
},
{
id: 2,
"username": "Brench",
"email": "Brench@melissa.tv",
age: 18,
sort: 2
},
{
id: 3,
"username": "Cherry",
"email": "Cherry@miniasp.com",
age: 25,
sort: 3
},
{
id: 4,
"username": "David",
"email": "David@miniasp.com",
age: 44,
sort: 4
}
];
let myArray = ["a", "b", "c"];
let app = new Vue({
el: '#myApp',/*定義Vue作用範圍,el指的是element*/
data: {//data是關鍵字
myArray: myArray,
init_users: init_users,//模擬把後端資料指派給init_users data
//計算屬性放在data沒有作用
// init_users_indexObj: function () {
// let vm = this;
// let firstIndex = 0;
// let lastIndex = 0;
// if (vm.init_users.length > 0) {//有資料時
// lastIndex = vm.init_users.length - 1;
// }
// return { firstIndex: firstIndex, lastIndex: lastIndex };
//}
},
computed: {
//計算屬性一定要有回傳值
init_users_indexObj: function () {
let vm = this;
let firstIndex = -1;
let lastIndex = -1;
if (vm.init_users.length > 0)
{//有資料時
firstIndex = 0;
lastIndex = vm.init_users.length - 1;
}
return { firstIndex: firstIndex, lastIndex: lastIndex };
}
} ,
methods: { //methods是關鍵字,通常處理和用戶的互動事件
EditMyArray: function () {
let vm = this;
let source = "b";
let target = "z";
let delIndex = vm.myArray.findIndex(function (item, index) {
return item === source; //找不到index就回傳-1
});
//錯誤寫法,不是響應式
//vm.myArray[delIndex] = target ;
//正確寫法
//if (delIndex !== -1)
//{
//Vue.set給index -1不會有事,不必防呆
Vue.set(vm.myArray, delIndex, target);//替換陣列中的值,會連同源資料 myArray都一起替換
//}
},
ClearMyArray: function () {//清除陣列
//this.myArray.length = 0;//資料清除,但不是響應式的錯誤寫法
//this.myArray = []; //或 指向new Array(); 是響應式寫法,但只是把指標指向其它位址,源資料仍存在
this.myArray.splice(0,this.myArray.length); //連同源資料也刪除
},
RestoreMyArray: function () {
this.myArray = myArray;
},
Editinit_users: function () {
let vm = this;//把username Allen改成ALLEN
let source = "Allen";//要找的username
let target = "ALLEN";//要替換的username
let delIndex = vm.init_users.findIndex(function (userObj, index) {
return userObj.username === source; //找不到,index回傳-1
});
if (delIndex !== -1)
{//有找到
//集合物件可以正確這樣處理
vm.init_users[delIndex].username = target;
// Vue.set(vm.init_users[delIndex], "username", target);//替換集合物件中,某個物件屬性的值
//↑上面兩種寫法都會連同 源資料init_users一起修改
}
},
Clearinit_users: function () {//清除陣列
// this.init_users.length = 0;//資料清除,但不是響應式的錯誤寫法
//this.init_users = []; //或 指向new Array(); 是響應式寫法,但只是把指標指向其它位址,源資料仍存在
this.init_users.splice(0,this.init_users.length); //連同源資料也刪除
},
Restoreinit_users: function () {
this.init_users = init_users;
},
Up: function (user,index) {
let vm = this;
//找出前一筆資料交換Sort
//如果已是第一筆就不執行上移
let currentSort = user.sort;
//let currentIndex = vm.init_users.findIndex(function (item, idx) {
// return item.id === user.id;
//});
let currentIndex=index;
//往上面的資料走訪
for (let idx = currentIndex; idx >= vm.init_users_indexObj.firstIndex; idx--)
{
if (vm.init_users[idx].sort < currentSort) {//交換Sort資料
user.sort = vm.init_users[idx].sort;
vm.init_users[idx].sort = currentSort;
//交換陣列位置,以變更View
let tempObj = vm.init_users[idx];//target object先暫存
vm.init_users[idx] = user;//source放到正確位置
vm.init_users[currentIndex] = tempObj;//最後處理
break;//僅處理一筆即可
}//end if
}//end
},
Down: function (user,index) {
let vm = this;
//找出下一筆資料交換Sort
//如果已是最後一筆就不執行下移
let currentSort = user.sort;
// let currentIndex = vm.init_users.findIndex(function (item,idx) {
// return item.id === user.id;
// });
let currentIndex=index ;
for (let idx = currentIndex; idx <= vm.init_users_indexObj.lastIndex; idx++)//往下尋找資料
{
if (vm.init_users[idx].sort > currentSort)
{//交換Sort資料
user.sort = vm.init_users[idx].sort;
vm.init_users[idx].sort = currentSort;
//交換陣列位置,以變更View
let tempObj = vm.init_users[idx];//target object先暫存
vm.init_users[idx] = user;//source放到正確位置
vm.init_users[currentIndex] = tempObj;//最後處理
break;
}
}//end for
}
}
});
</script>
</body>
</html>
線上Demo:https://jsfiddle.net/ShadowKao/j834vkas/
↑ 此範例會改變元素在陣列的位置,如果剛好畫面有未綁定的表單欄位<input>、<select>、<textarea>,記得v-for迴圈要 v-bind:key 綁定一個唯一鍵值讓Vue識別追蹤
5.留意修改、刪除Object資料集的幾個限制
※附送上移、下移功能的實現
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<title>Hello, Vue.js!</title>
<style type="text/css">
body {
padding-top: 30px;
}
</style>
</head>
<body>
<div class="container" id="myApp">
<div class="row">
<div class="form-group col-12">
<button type="button" class="btn btn-warning" v-on:click="Editinit_users">把init_users的username Allen替換成ALLEN</button>
<button type="button" class="btn btn-danger" v-on:click="Clearinit_users">清除init_users</button>
<button type="button" class="btn btn-success" v-on:click="Restoreinit_users">恢復init_users</button>
</div>
<div class="form-group col-12">
顯示init_users資料↓
<ul v-if="Object.keys(init_users).length>0">
<li v-for="(user , key) in init_users">
userid:{{user.userid}}
<b> username:{{user.username}} </b>
email:{{user.email}} age:{{ user.age}}
sort:{{user.sort}}
</li>
</ul>
</div> <!--end .form-group-->
<div class="form-group col-12">
輸入字串並上移、下移資料↓
<ul v-if="Object.keys(init_users).length >0" style="list-style:none;">
<li v-for="(user , key) in init_users" style="border:1px solid #000;" >
userid:{{user.userid}} username:{{user.username}} age:{{ user.age}}
<br />
email: <input type="text" v-model="user.email" placeholder="輸入email" class="form-control" style="display:inline-block;width:50%;" />
<br />
<button type="button" class="btn btn-info" v-on:click="Up(user,key);">上移</button>
<button type="button" class="btn btn-info" v-on:click="Down(user,key);">下移</button>
</li>
</ul>
</div> <!--end .form-group-->
</div> <!--end .row-->
</div> <!--end .container-->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<!-- 引用Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script>
<script type="text/javascript">
let init_users = //.net的Dictionary<string,Object>可以序例化為這樣的Json格式
{
"1": {
userid:"1",
username: "Bret",
email: "Bret@april.biz",
age: 32,
sort: 10
},
"2":
{
userid: "2",
username: "Antonette",
email: "Antonette@melissa.tv",
age: 18,
sort: 20
},
"3":
{
userid: "3",
username: "Allen",
email: "Allen@miniasp.com",
age: 25,
sort: 30
},
"4":
{
userid: "4",
username: "Jack",
email: "Jack@miniasp.com",
age: 44,
sort: 40
}
};
let app = new Vue({
el: '#myApp',/*定義Vue作用範圍,el指的是element*/
data: {
init_users: init_users
},
methods: { //methods通常處理和用戶的互動事件
Editinit_users: function () {
let vm = this;//把username Allen改成ALLEN
let source = "Allen";//要找的username
let target = "ALLEN";//要替換的username
for(let key in vm.init_users)
{
if(vm.init_users[key].username===source)
{
vm.init_users[key].username=target;
//Vue.set(vm.init_users[key], "username", target);//替換集合物件中,某個物件屬性的值
//↑兩種寫法都可以
}
}
},
Clearinit_users: function () {//清除物件群
let vm = this;
//this.init_users = { }; //或 指向new Object(); 是響應式寫法,但只是把指標指向其它位址,源資料仍存在
Object.keys(vm.init_users).forEach(function (key) {
// delete vm.init_users[key]; //不是響應式寫法
Vue.delete(vm.init_users, key);//連同 源資料也被刪除
});
},
Restoreinit_users: function ()
{
this.init_users = init_users;
},
Up: function (user,currentKey) {
let vm = this;
//找出前一筆資料交換Sort
//如果已是第一筆就不執行上移
let currentSort = user.sort;
let lastIndex = Object.keys(vm.init_users).length - 1;
//由下往上面的資料走訪
for (let idx = lastIndex; idx >= 0; idx--)
{
//將索引換算成對應的key字串
let key = Object.keys(vm.init_users)[idx];
if (vm.init_users[key].sort < currentSort)
{//交換Sort資料
user.sort = vm.init_users[key].sort;
vm.init_users[key].sort = currentSort;
//掛到不同的key,以變更View
let tempObj = vm.init_users[key];//target object先暫存
vm.init_users[key] = user;//source放到正確位置,上移
vm.init_users[currentKey] = tempObj;//最後處理
break;//僅處理一筆即可
}//end if
}//end
},
Down: function (user,currentKey) {
let vm = this;
//找出下一筆資料交換Sort
//如果已是最後一筆就不執行下移
let currentSort = user.sort;
for (let key in vm.init_users)//往下尋找資料
{
if (vm.init_users[key].sort > currentSort)
{//交換Sort資料
user.sort = vm.init_users[key].sort;
vm.init_users[key].sort = currentSort;
//交換物件的key,以變更View
let tempObj = vm.init_users[key];//target object先暫存
vm.init_users[key] = user;//source放到正確位置
vm.init_users[currentKey] = tempObj;//最後處理
break;
}
}//end for
}
}
});
</script>
</body>
</html>
線上Demo:https://jsfiddle.net/ShadowKao/r7vz6nqm/
刪除物件資料集可使用迴圈搭配 Vue.delete( target, key )
但如果對陣列使用迴圈搭配 Vue.delete,例如↓
let vm = this;
for(let idx in vm.myArray)
{
Vue.delete(vm.myArray,idx);
}
這種情況就會如同在迴圈中呼叫.splice(index,1); 不完全刪除資料,因為每刪除一筆陣列中的元素,陣列大小就會改變
let vm =this;
for(let idx=0;idx<vm.myArray.length;idx++)
{
vm.myArray.splice(idx,1);
}
結論
陣列刪除↓
let deleteIndex = 0;//先找出要刪除的陣列索引
let vm =this;
vm.myArray.splice(deleteIndex,1);//刪除一筆
//全部刪除陣列中的元素
vm.myArray.splice(0,vm.myArray.length);
物件刪除↓
let vm = this;
Vue.delete(vm.myObject, key);//刪除一筆
for(let key in vm.myObject)//刪除多筆
{
Vue.delete(vm.myObject, key);
}
詳見官網說明:注意事项
進階議題官網說明:深入响应式原理
6.使用 v-if 切換畫面,如果內容有表單欄位時,最好使用v-model指令雙向綁定那些表單欄位
要不然改使用 v-show (顯示或隱藏display:none;)來切換畫面
<!DOCTYPE html>
<html lang="utf-8">
<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>[Vue.js] 切換畫面可能遇到的問題</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style type="text/css">
body {
padding-top: 30px;
}
</style>
</head>
<body>
<div class="container" id="myApp">
<div class="row">
<!--v-if會重新渲染畫面-->
<div class="form-group col-xs-12">
<input type="checkbox" v-model="isChecked" /> <label>請勾我</label>
</div>
<div v-if="isChecked" class="form-group col-xs-12">
v-if 沒綁定: <input type="text" placeholder="沒綁定" />
</div>
<div v-else class="form-group col-xs-12">
v-else 沒綁定 <input type="text" placeholder="沒綁定" />
</div>
<div class="form-group col-xs-12">
使用v-bind:key (維持不綁定,不完美的解法,輸入的值在切換後消失)↓
</div>
<div v-if="isChecked" class="form-group col-xs-12">
v-if 沒綁定但有key: <input type="text" placeholder="沒綁定" v-bind:key="1" />
</div>
<div v-else class="form-group col-xs-12">
v-else 沒綁定但有key <input type="text" placeholder="沒綁定" v-bind:key="2" />
</div>
<div class="form-group col-xs-12">
使用v-model解法(雙向綁定)↓
</div>
<div v-if="isChecked" class="form-group col-xs-12">
v-if 有綁定<input type="text" placeholder="有綁定" v-model="myIf" />
</div>
<div v-else class="form-group col-xs-12">
v-else 有綁定<input type="text" placeholder="有綁定" v-model="myElse" />
</div>
<div class="form-group col-xs-12">
改用v-show解法(不綁定)↓
</div>
<div v-show="isChecked" class="form-group col-xs-12">
v-show: <input type="text" placeholder="沒綁定" />
</div>
<div v-show="isChecked===false" class="form-group col-xs-12">
v-show isChecked===false <input type="text" placeholder="沒綁定" />
</div>
<div class="form-group col-xs-12">
改用v-show解法(有綁定)↓
</div>
<div v-show="isChecked" class="form-group col-xs-12">
v-show: <input type="text" placeholder="有綁定" v-model="myShow" />
</div>
<div v-show="isChecked===false" class="form-group col-xs-12">
v-show isChecked===false <input type="text" placeholder="有綁定" v-model="myShowFalse" />
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!--Vue.js-->
<script src="https://vuejs.org/js/vue.js"></script>
<script type="text/javascript">
let myApp = new Vue({
el: "#myApp",
data: {
isChecked: true, //預設打勾
myIf: "",
myElse: "",
myShow: "",
myShowFalse: ""
}
});
</script>
</body>
</html>
線上Demo:https://jsfiddle.net/ShadowKao/u8oyb1ch/
7. 使用 v-if 切換畫面,搭配 animate.css 、wow.js 插件使用的話...
由於 v-if 會重新渲染DOM元素,要小心會重新觸發CSS動畫的執行,如果不想讓CSS動畫重新執行的話,請改用 v-show
線上Demo:https://jsfiddle.net/ShadowKao/gzr1t8be/