日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

一步一步学Vue(四)

發布時間:2023/11/29 vue 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步一步学Vue(四) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接上篇。上篇中給出了代碼框架,沒有具體實現,這一篇會對上篇定義的幾個組件進行分別介紹和完善:

1、TodoContainer組件

  TodoContainer組件,用來組織其它組件,這是react中推薦的方式,也是redux中高階組件一般就是用來包裝成容器組件用的,比如redux中的connect函數,返回的包裝組件就是一個容器組件,它用來處理這樣一種場景:加入有A、B兩個組件,A組件中需要通過Ajax請求和后端進行交互;B組件也需要通過Ajax請求和后端交互,針對這種場景有如下代碼:

//組件A定義 var CompA={template:'<div>A 渲染 list</div>',data:function(){return {list:[]}},methods:{getListA:function(){$.ajax({url:'xxx',dataType:'json',success:r=>this.list=r.data})}} }; //組件B定義 var CompB={template:'<div>B 渲染list</div>',data:function(){return {list:[]}},methods:{getListB:function(){$.ajax({url:'xxx',dataType:'json',success:r=>this.list=r.data})}} }

可以看出,A組件和B組件中都會存在Ajax訪問重復代碼,有重復代碼就要提取出來;第一種方式,提取公共方法,使用mixin混入到兩個組件中,所謂混入就是動態把方法注入到兩個對象中;

第二種方法使用外部傳入,這是react中推薦的方式,使用props傳入;其實我們仔細分析我們的兩個組件,都是為了渲染列表數據,至于是在組件外請求還是在組件內請求,它是不關注的,這樣我們可以進一步考慮,把AB組件重構成只用來渲染數據的pure組件,數據由外部傳入,而vue正好提供了這種props父傳子的機制,把Ajax操作定義到父組件中(就是我們這里提到的容器組件),也起到了重復代碼提取的作用,基于此請看我們的第二版代碼:

//A組件 var CompA={template:'<div>A</div>',props:['list'] }; //B組件 var CompB={template:'<div>B</div>',props:['list'] } //容器組件 var Container={template:`<comp-a :list="listA" ></comp-a><comp-b :list="listB" ></comp-b> `,components:{'comp-a':CompA,'comp-b':CompB},methods:{getListA:function(){//TODO:A 邏輯 },getListB:function(){//TODO:B 邏輯 }} }

這樣A、B組件變成了傻白甜組件,只是負責數據渲染,所有業務邏輯由容器組件處理;容器組件把A、B組件需要的數據通過props的方式傳遞給它們。

已經明白了容器組件的作用,那么我們來實現一下前幾篇中todolist的容器組件吧,上篇已有基本結果,這里先出代碼后解釋:

/*** 容器組件* 說明:容器組件包括三個字組件*/var TodoContainer = {template: `<div class="container"><search-bar @οnsearch="search($event)"></search-bar><div class="row"><todo-list :items="items" @onremove="remove($event)" @onedit="edit($event)"></todo-list> <todo-form :init-item="initItem" @onsave="save($event)" ></todo-form></div></div> `,data: function () {return {/*** Todolist數據列表* 說明:通過props傳入到Todolist組件中,讓組件進行渲染*/items: [],/*** TodoForm初始化數據* 說明:由于TodoForm包括兩種操作:新增和編輯;新增操作無需處理,編輯操作需要進行數據綁定,這里通過傳入initItem屬性進行編輯時數據的初始化* 如果傳入的值為空,說明為新增操作,由initItem參數的Id是否為空,來確認是更新保存還是新增保存*/initItem: {title: '',desc: '',id: ''}}},components: {'search-bar': SearchBar,/**SearchBar組件注冊 */'todo-form': TodoForm,/**TodoForm組件注冊 */'todo-list': todoList/**TodoList組件注冊 */},methods: {/*** 模擬保存數據方法* 輔助方法*/_mock_save: function (lst) {list = lst;},/*** 根據id查詢對象* 輔助方法*/findById: function (id) {return this.items.filter(v => v.id === id)[0] || {};},/*** 查詢方法* 由SearchBar組件觸發*/search: function ($e) {this.items = list.filter(v => v.title.indexOf($e) !== -1);},/*** 保存方法* 響應新增和更新操作,由TodoForm組件觸發*/save: function ($e) {//id存在則為編輯保存if (this.initItem.id) {var o = this.findById($e.id);o.title = $e.title;o.desc = $e.desc;} else {this.items.push(new Todo($e.title, $e.desc));}this.initItem = { id: '', title: '', desc: '' };this._mock_save(this.items);},/*** 刪除方法* 響應刪除按鈕操作* 由TodoItem組件觸發*/remove: function ($e) {this.items = this.items.filter(v => v.id !== $e);this._mock_save(this.items);},/*** 編輯按鈕點擊時,進行表單數據綁定*/edit: function ($e) {this.initItem = this.findById($e);}}}

  我們把所有業務邏輯也放在容器組件中處理,其它組件都是傻白甜,這樣的好處是,其它組件容易重用,因為只是數據渲染,并不涉及業務操作,這種組件沒有業務相關性,比如一個list組件我可以用它顯示用戶信息,當然也可以用它顯示角色信息,根據傳入的數據而變化。

  對上述代碼,需要簡單解釋一下的是,Vue中父子event傳遞是通過$emit和$on來實現的,但是寫法和angular中有一些差異;在angular中我們一般這樣寫:

//事件發射 $scope.$emit("onxxx",data); //事件監聽 $scope.$on("onxxx",function(e,data){//TODO: })

但是在vue中$on是直接使用v-on:onxxx或@onxxx來寫的,所以一般存在的是這樣的代碼:

<todo-list :items="items" @onremove="remove($event)" @onedit="edit($event)"></todo-list> <todo-form :init-item="initItem" @onsave="save($event)" ></todo-form>

其它代碼中加入了很多注釋,也比較簡單,就不做過多解釋了,有疑問可提交。

2、SearchBar組件

  SearchBar組件比較簡單,只是簡單觸發查詢按鈕,發射(觸發)onsearch事件,然后TodoContainer組件中使用 @οnsearch="search($event)" 進行監聽。

/*** 搜索組件*/var SearchBar = {template: `<div class="row toolbar"><div class="col-md-8">keyword:<input type="text" v-model="keyword" /><input type="button" @click="search()" value="search" class="btn btn-primary" /></div></div> `,data: function () {return {keyword: ''}},methods: {search: function () {this.$emit('onsearch', this.keyword);}}}

3、TodoForm組件

  TodoForm組件,是我們Todolist中的表單組件,編輯和新增公用,我們需要考慮的是,我們的初始化數據由外部傳入,首先看第一版代碼,考慮有什么坑?

/*** 表單組件*/var TodoForm = {template: `<div class="col-md-6"><div class="form-inline"><label for="title" class="control-label col-md-4">title:</label><input type="hidden" v-bind:value="todo.id" /><input type="text" v-model="todo.title" class="form-control col-md-8"></div><div class="form-inline"><label for="desc" class="control-label col-md-4">desc</label><input type="text" v-model="todo.desc" class="form-control col-md-8"></div><div class="form-inline"><input type="button" value="OK" v-on:click="ok()" class="btn btn-primary offset-md-10" /></div></div> `,props: ['initItem'],
     data: function {return {todo: this.initItem}
},methods: {ok: function () {this.$emit('onsave', this.todo);}}}

這段代碼有什么問題呢?我們把傳入的初始化參數給了我們的todo對象,這樣導致的直接問題是:新增的時候沒問題,但是編輯的時候無法綁定數據,原因是,編輯操作實際上就是修改外部傳入的initItem對象,但是todo只在組件初始化的時候被賦值,其它時候是不響應initItem變化的,如何才能響應initItem變化,很明顯是我們的computed屬性,computed屬性會響應其封裝對象的變化;代碼第二版修改如下:

/*** 表單組件*/var TodoForm = {template: `<div class="col-md-6"><div class="form-inline"><label for="title" class="control-label col-md-4">title:</label><input type="hidden" v-bind:value="todo.id" /><input type="text" v-model="todo.title" class="form-control col-md-8"></div><div class="form-inline"><label for="desc" class="control-label col-md-4">desc</label><input type="text" v-model="todo.desc" class="form-control col-md-8"></div><div class="form-inline"><input type="button" value="OK" v-on:click="ok()" class="btn btn-primary offset-md-10" /></div></div> `,props: ['initItem'],computed: {todo: function () {
          //這里不直接返回this.initItem 是因為會導致雙向綁定,因為傳遞的是引用
return { id: this.initItem.id, title: this.initItem.title, desc: this.initItem.desc };}},methods: {ok: function () {this.$emit('onsave', this.todo);}}}

?

?4、TodoList && TodoItem組件

  TodoList組件是數據列表組件,它的每一個列表項我們進行了一次封裝,每一個list中的列表項,就是一個TodoItem組件,所以在TodoItem組件中,只需要引入todoitem數據即可,唯一需要關注的就是todoItem組件中會觸發onremove和onedit事件。

/*** 列表項組件*/var TodoItem = {template: `<tr><th>{{todo.id}}</th><td>{{todo.title}}</td><td>{{todo.desc}}</td><td><input type="button" value="remove" @click="remove()" class="btn btn-danger" /><input type="button" value="edit" @click="edit()" class="btn btn-info" /></td></tr> `,props: ['todo'],methods: {edit: function () {console.log(this.todo);this.$emit('onedit', this.todo.id);},remove: function () {this.$emit('onremove', this.todo.id);}}}/*** 列表組件*/var TodoList = {template: `<div class="col-md-6"><table class="table table-bordered"><tr><th></th><th>title</th><th>desc</th><th></th></tr><todo-item v-for="item in items" :todo="item" :key="item.id" @onedit="edit($event)" @onremove="remove($event)"></todo-item></table></div> `,props: ['items'],components: {'todo-item': TodoItem},methods: {edit: function ($e) {this.$emit('onedit', $e);},remove: function ($e) {this.$emit('onremove', $e);}}}

這兩個數據渲染組件就沒什么好說名的了;但是大家發現一個很不爽的問題:由于我們在容器中統一管理了業務邏輯(更逼格高一些,叫狀態),所以在todoitem組件中觸發的事件沒辦法直接到TodoContainer組件中,只能通過一級一級的往上傳遞,所以在todolist中也有和todoitem中類似的觸發事件的代碼this.$emit('onremove', $e);這里組件層級才2級,如果多了狀態管理就是災難了,幸好vuex的出現,就是專門處理這種問題的,后期用到vuex的時候會詳細介紹。

5、小結

  todolist這個demo,就暫時告一段落了,下一片會以一個稍微復雜的demo(信息管理)來介紹vue-router,當然在一步一步學習的過程中,我還是沒能做到把所有基本概念過一遍,我個人覺得還是用到再解釋吧,否則還不如直接看文檔來的方便。。。

完整代碼:

index.html

<!DOCTYPE html> <html lang="en"><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>demo1</title><script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script><link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet"></head><body class="container"><div id="app"><todo-container></todo-container></div><script src="./todolist.js"></script> </body></html> View Code

todolist.js

; (function () {var list = [];var Todo = (function () {var id = 1;return function (title, desc) {this.title = title;this.desc = desc;this.id = id++;}})();/*** 搜索組件*/var SearchBar = {template: `<div class="row toolbar"><div class="col-md-8">keyword:<input type="text" v-model="keyword" /><input type="button" @click="search()" value="search" class="btn btn-primary" /></div></div> `,data: function () {return {keyword: ''}},methods: {search: function () {this.$emit('onsearch', this.keyword);}}}/*** 表單組件*/var TodoForm = {template: `<div class="col-md-6"><div class="form-inline"><label for="title" class="control-label col-md-4">title:</label><input type="hidden" v-bind:value="todo.id" /><input type="text" v-model="todo.title" class="form-control col-md-8"></div><div class="form-inline"><label for="desc" class="control-label col-md-4">desc</label><input type="text" v-model="todo.desc" class="form-control col-md-8"></div><div class="form-inline"><input type="button" value="OK" v-on:click="ok()" class="btn btn-primary offset-md-10" /></div></div> `,props: ['initItem'],computed: {todo: function () {return { id: this.initItem.id, title: this.initItem.title, desc: this.initItem.desc };}},methods: {ok: function () {this.$emit('onsave', this.todo);}}}/*** 列表項組件*/var TodoItem = {template: `<tr><th>{{todo.id}}</th><td>{{todo.title}}</td><td>{{todo.desc}}</td><td><input type="button" value="remove" @click="remove()" class="btn btn-danger" /><input type="button" value="edit" @click="edit()" class="btn btn-info" /></td></tr> `,props: ['todo'],methods: {edit: function () {console.log(this.todo);this.$emit('onedit', this.todo.id);},remove: function () {this.$emit('onremove', this.todo.id);}}}/*** 列表組件*/var TodoList = {template: `<div class="col-md-6"><table class="table table-bordered"><tr><th></th><th>title</th><th>desc</th><th></th></tr><todo-item v-for="item in items" :todo="item" :key="item.id" @onedit="edit($event)" @onremove="remove($event)"></todo-item></table></div> `,props: ['items'],components: {'todo-item': TodoItem},methods: {edit: function ($e) {this.$emit('onedit', $e);},remove: function ($e) {this.$emit('onremove', $e);}}}/*** 容器組件* 說明:容器組件包括三個字組件*/var TodoContainer = {template: `<div class="container"><search-bar @οnsearch="search($event)"></search-bar><div class="row"><todo-list :items="items" @onremove="remove($event)" @onedit="edit($event)"></todo-list> <todo-form :init-item="initItem" @onsave="save($event)" ></todo-form></div></div> `,data: function () {return {/*** Todolist數據列表* 說明:通過props傳入到Todolist組件中,讓組件進行渲染*/items: [],/*** TodoForm初始化數據* 說明:由于TodoForm包括兩種操作:新增和編輯;新增操作無需處理,編輯操作需要進行數據綁定,這里通過傳入initItem屬性進行編輯時數據的初始化* 如果傳入的值為空,說明為新增操作,由initItem參數的Id是否為空,來確認是更新保存還是新增保存*/initItem: {title: '',desc: '',id: ''}}},components: {'search-bar': SearchBar,/**SearchBar組件注冊 */'todo-form': TodoForm,/**TodoForm組件注冊 */'todo-list': TodoList/**TodoList組件注冊 */},methods: {/*** 模擬保存數據方法* 輔助方法*/_mock_save: function (lst) {list = lst;},/*** 根據id查詢對象* 輔助方法*/findById: function (id) {return this.items.filter(v => v.id === id)[0] || {};},/*** 查詢方法* 由SearchBar組件觸發*/search: function ($e) {this.items = list.filter(v => v.title.indexOf($e) !== -1);},/*** 保存方法* 響應新增和更新操作,由TodoForm組件觸發*/save: function ($e) {//id存在則為編輯保存if (this.initItem.id) {var o = this.findById($e.id);o.title = $e.title;o.desc = $e.desc;} else {this.items.push(new Todo($e.title, $e.desc));}this.initItem = { id: '', title: '', desc: '' };this._mock_save(this.items);},/*** 刪除方法* 響應刪除按鈕操作* 由TodoItem組件觸發*/remove: function ($e) {this.items = this.items.filter(v => v.id !== $e);this._mock_save(this.items);},/*** 編輯按鈕點擊時,進行表單數據綁定*/edit: function ($e) {this.initItem = this.findById($e);}}}var app = new Vue({el: '#app',components: {'todo-container': TodoContainer}});})();/*** * * <div id="app">* <todo-container></todo-container>* </app>*/ View Code

?

轉載于:https://www.cnblogs.com/Johnzhang/p/7223064.html

總結

以上是生活随笔為你收集整理的一步一步学Vue(四)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。