# todo 大案例
-
TodoWrap.vue 父组件
<template> <div class="todo-wrap"> <h1>todos</h1> <TodoForm :isAllTodoCompleted="isAllTodoCompleted" @changeAllTodo="changeAllTodo" @addTodo="addTodo" :len="todos.length" /> <!-- 自定义事件只能传递一次,所以这里使用了prop方式传递 --> <!-- 第一次用prop传递给儿子,第二次在儿子用自定义事件传递给孙子 --> <div v-show="todos.length"> <TodoList :todos="showTodos" :completedTodo="completedTodo" :delTodo="delTodo" :changeTodoText="changeTodoText" /> <!-- .sync 缩写 --> <!-- .sync 不仅传递了自定义事件,还传递了对应的prop --> <TodoFooter :type.sync="type" @delAllCompleted="delAllCompleted" :activeTodoNums="activeTodoNums" :completedTodoNums="completedTodoNums" /> </div> </div> </template> <script> import TodoForm from "./TodoForm"; import TodoList from "./TodoList"; import TodoFooter from "./TodoFooter"; export default { name: "TodoWrap", components: { TodoForm, TodoList, TodoFooter }, data() { return { todos: [{ id: "7t7t7d", text: "666", isCompleted: false }], type: "all", editTodoId: "", }; }, computed: { // 判断 所有的 isCompleted 是否为被选中 isAllTodoCompleted() { // 让箭头为灰色 // 当数组为空的时候,every 的结果是true return this.todos.length ? this.todos.every((todo) => todo.isCompleted) : false; }, showTodos() { const { type, todos } = this; return this.filterTodoByType(type, todos); }, activeTodoNums() { return this.filterTodoByType("active", this.todos).length; }, completedTodoNums() { return this.filterTodoByType("completed", this.todos).length; }, }, methods: { // 通过类别筛选数组的功能函数 filterTodoByType(type, todos) { return todos.filter((todo) => type === "all" ? true : type === "active" ? !todo.isCompleted : todo.isCompleted && type === "completed" ); }, // 删除 todo 函数 delTodo(id) { const delIndex = this.todos.findIndex((todo) => todo.id === id); if (delIndex > -1) { this.todos.splice(delIndex, 1); } }, // 修改 todo 的 isCompleted 属性 completedTodo(id) { const currentTodo = this.todos.find((todo) => todo.id === id); if (currentTodo) { currentTodo.isCompleted = !currentTodo.isCompleted; } }, // 修改所有 todo 的 isCompleted changeAllTodo(status) { this.todos.forEach((item) => { if (item.isCompleted !== status) { item.isCompleted = status; } }); }, // 输入框内容添加到数组中 addTodo(text) { this.todos.push({ id: new Date().getTime(), text, isCompleted: false, }); }, // 删除所有的已完成 delAllCompleted() { // console.log(id); this.todos = this.todos.filter((todo) => !todo.isCompleted); }, // 修改对应的 todo 内容 changeTodoText(id, text) { const currentTodo = this.todos.find((todo) => todo.id === id); if (currentTodo) { currentTodo.text = text; } }, }, }; </script> -
TodoForm.vue 子组件
<template> <div class="todo-form"> <i v-show="len" :class="['iconfont', 'icon-xiala' ,'icon',{'all-completed':isAllTodoCompleted}]" @click="$emit('changeAllTodo',!isAllTodoCompleted)" ></i> <input type="text" placeholder="输入内容" v-model.trim="value" @keydown.enter="handleEnter" /> </div> </template> <script> export default { name: "TodoForm", props: ["isAllTodoCompleted", "len"], data() { return { value: "", }; }, methods: { handleEnter() { const { value } = this; if (value) { this.$emit("addTodo", value); this.value = ""; } }, }, }; </script> -
TodoList.vue 子组件
<template> <div class="todo-list"> <!-- 循环的时候 todo 指的是具体的一项,我们需要其所有内容全部传递给 TodoItem 组件 --> <!-- 所以选择了传递整个对象 :todo="todo",也可以直接将整个对象下的所有属性一次性传递 v-bind="todo" --> <TodoItem v-for="todo in todos" :key="todo.id" v-bind="todo" @delTodo="delTodo" @completedTodo="completedTodo" @changeTodoText="changeTodoText" /> </div> </template> <script> import TodoItem from "./TodoItem"; export default { name: "TodoList", components: { TodoItem }, props: ["todos", "delTodo", "completedTodo", "changeTodoText"], }; </script> -
TodoItem.vue 孙子组件
<template> <div class="todo-item"> <div class="checkbox"> <input type="checkbox" :id="id" :checked="isCompleted" @change="$emit('completedTodo', id)" /> <label :for="id"></label> </div> <span :class="['todo-text', { completed: isCompleted }]" @dblclick="dblClick" v-show="!isEditing" >{{ text }}</span > <!-- autofocus html自动获取焦点属性 --> <input type="text" class="edit-input" :value="text" v-show="isEditing" @blur="handleBlur(id,$event.target.value)" ref="inputEle" /> <!-- 上面失去焦点事件内想要将输入框的内容当作参数传递下去 --> <!-- vue 的事件函数内 直接可以使用 $event 代表事件对象 --> <span class="del" @click="$emit('delTodo', id)">X</span> </div> </template> <script> export default { name: "TodoItem", props: ["id", "text", "isCompleted"], // 因为这里采用了传递属性的方式,所以上边的属性都没有了todo.id ,直接变成了id data() { return { isEditing: false, }; }, methods: { dblClick() { this.isEditing = true; // 使用 focus 方法 让 input 获取焦点 // 直接使用 focus 方法获得焦点不成功 // 因为 focus 执行的时候,页面中的 input 并没有出现(focus比先出现先执行,获得焦点在出现之前执行的) // 当直接修改了数据之后想要获取对应的更新之后的dom节点,需要借助 $nextTick 方法 this.$nextTick(() => { // document.querySelector(".edit-input").focus(); //这个不保险,推荐使用ref this.$refs.inputEle.focus(); // document 方式获取真实 dom 节点,需要替换成 ref // vue 中提供了 获取真实 dom 节点的方式 就是 ref // 当给普通的 html 添加 ref 属性时,ref 指的就是 html 节点的真实 dom, // 当 ref 属性添加到组件上时 ref 指的就是组件本身 // 获取 ref 就是使用组件 this.$refs.xx 获取 // 所以在父组件中给子组件添加 ref 属性,可以在父组件中获取子组件,那么子组件内的所有内容父组件都可以获取了 }); }, handleBlur(id, text) { this.isEditing = false; this.$emit("changeTodoText", id, text); }, }, }; </script> -
TodoFooter.vue 子组件
<template> <div class="todo-footer"> <span class="left" >{{activeTodoNums}} item{{activeTodoNums !== 1 ?'s':''}} left</span > <div class="btns"> <!-- changeType 换成了 update:type --> <button :class="type==='all'&&'active'" @click="$emit('update:type', 'all')" > all </button> <button :class="type==='active'&&'active'" @click="$emit('update:type', 'active')" > active </button> <button :class="type==='completed'&&'active'" @click="$emit('update:type', 'completed')" > completed </button> </div> <button class="right" @click="$emit('delAllCompleted')" v-show="completedTodoNums" > clear completed </button> </div> </template> <script> export default { name: "TodoFooter", props: ["type", "activeTodoNums", "completedTodoNums"], }; </script>
# .sync 修饰符
.sync 修饰符的用法 不需要在父组件定义修改的方法,一般只用在非引用类型的 data 上
-
父组件 TodoWrap.vue 文件
<template> <div class="todo-wrap"> <!-- <TodoFooter @changeType="changeType" /> --> <!-- 这个自定义事件的名称是 update:type 传递的函数其实是 function($event){type=$event} --> <!-- 使用 .sync 不用传递函数,下边已注释 --> <!-- <TodoFooter @update:type="type = $event" /> --> <!-- changeType 换成了 update:type --> <!-- .sync 缩写 --> <TodoFooter :type.sync="type" /> </div> </template> <script> export default { name: "TodoWrap", components: { TodoFooter }, data() { return { type: "all", // 这个 data 需要子组件修改,一般做法是在父组件定义好的方法,然后传递给子组件执行 // 也可以使用 自定义事件的 .sync 修饰符实现,一般只用在非引用数据类型的data上 // .sync 修饰符的用法不需要在父组件定义修改的方法 }; }, methods: { /* changeType(newType) { this.type = newType; }, */ }, }; </script> -
子组件 TodoFooter.vue 文件
<template> <div class="todo-footer"> <span class="left">{{2}} items left</span> <div class="btns"> <!-- <button @click="$emit('changeType','all')">all</button> <button @click="$emit('changeType','active')">active</button> <button @click="$emit('changeType','completed')">completed</button> --> <!-- changeType 换成了 update:type --> <button @click="$emit('update:type','all')">all</button> <button @click="$emit('update:type','active')">active</button> <button @click="$emit('update:type','completed')">completed</button> </div> <button class="right">clear completed</button> </div> </template>
# table 大案例
-
App.vue 文件
<template> <div id="app"> <TableFilter :filterTitleStr.sync="filterTitleStr" @changeShow="changeShow" /> <table :postList="showPostList" :delPost="delPost" :changeShow="changeShow" :changeEditId="changeEditId" :filterTitleStr="filterTitleStr" /> <PostDialog v-if="show" :show="show" @changeShow="changeShow" @onOk="onOk" :getPostByEditId="getPostByEditId" @changeEditId="changeEditId" /> </div> </template> <script> import TableFilter from "./components/TableFilter"; import Table from "./components/Table"; import PostDialog from "./components/PostDialog"; import shortid from "shortid"; export default { name: "App", components: { TableFilter, Table, PostDialog }, data() { return { postList: [ { id: 1, time: "2275-11-26", title: "Ytifwsjgg Qqqy Dskb Lstgceu Knrd Msev", country: "USA", author: "Sarah", reads: "3276", }, { id: 2, time: "2216-03-28", title: "Lkzv Dmnrpoe Fgj Pueqgbp Doj", country: "Japan", author: "Susan", reads: "3485", }, ], filterTitleStr: "", show: false, editId: "", }; }, computed: { // 展示的内容 showPostList() { return this.postList.filter((post) => post.title.includes(this.filterTitleStr) ); }, // 通过editId找到对应的内容 getPostByEditId() { return this.postList.find((post) => post.id === this.editId); }, // 通过有无editId来判断是添加操作还是修改操作 onOk() { return this.editId === "" ? this.addPost : this.changePost; }, }, methods: { // 删除对应的内容 delPost(id) { this.postList = this.postList.filter((post) => post.id !== id); }, // 改变对话框的出现状态 changeShow() { this.show = !this.show; }, // 添加内容 addPost(newPost) { this.postList.push({ ...newPost, id: shortid() }); }, // 改变EditId changeEditId(id) { this.editId = id; }, // 对话框中修改对应的内容 changePost(newPost) { this.postList.splice( this.postList.findIndex((post) => post.id === this.editId), 1, { ...newPost, id: this.editId } ); }, }, }; </script> -
TableFilter.vue 文件
<template> <div class="table-filter"> <!-- 表格筛选 --> <input type="text" v-model.trim.lazy="searchValue" /> <button class="search" @click="search">搜索</button> <button class="add" @click="$emit('changeShow')">添加</button> </div> </template> <script> export default { name: "TableFilter", data() { return { searchValue: "", }; }, methods: { search() { const { searchValue } = this; if (searchValue) { this.$emit("update:filterTitleStr", searchValue); } }, }, }; </script> -
PostDialog.vue 文件
<template> <div class="dialog-wrap"> <div class="dialog-mask"></div> <div class="dialog"> <h3>标题</h3> <div> <label for>时间</label> <input v-model="post.time" type="text" /> </div> <div> <label for>标题</label> <input v-model="post.title" type="text" /> </div> <div> <label for>阅读数</label> <input v-model="post.reads" type="text" /> </div> <div> <label for>作者</label> <input v-model="post.author" type="text" /> </div> <div> <button @click="onOk">确定</button> <button @click="onCancle">取消</button> </div> </div> </div> </template> <script> export default { name: "PostDialog", props: ["getPostByEditId"], data() { return { post: { time: "", title: "", country: "China", author: "", reads: 0, }, }; }, created() { if (this.getPostByEditId) { const post = { ...this.getPostByEditId }; // 删除属性 delete post.id; this.post = post; } }, methods: { onOk() { // 应该判断所有输入是否全部输入了然后再执行添加操作 // 下边执行的onOk是父组件中传递时定义的名字 this.$emit("onOk", this.post); // 关闭弹窗 this.$emit("changeShow"); // 清空操作 this.post = { time: "", title: "", country: "China", author: "", reads: 0, }; this.$emit("changeEditId", ""); }, onCancle() { this.$emit("changeShow"); this.$emit("changeEditId", ""); }, }, }; </script> -
Table.vue 文件
<template> <table> <thead> <th>序号</th> <th>时间</th> <th>标题</th> <th>作者</th> <th>阅读数</th> <th>操作</th> </thead> <tbody> <!-- 一次性将对象下的所有属性全部传递 --> <TrItem v-for="post in postList" :key="post.id" v-bind="post" @delPost="delPost" @changeShow="changeShow" @changeEditId="changeEditId" :filterTitleStr="filterTitleStr" /> </tbody> </table> </template> <script> import TrItem from "./TrItem"; export default { name: "Table", components: { TrItem }, props: [ "postList", "delPost", "changeShow", "changeEditId", "filterTitleStr", ], }; </script> -
TrItem.vue 文件
<template> <tr> <td>{{ id }}</td> <td>{{ time }}</td> <td> <span v-html="titleHasKeyStr" v-if="title.includes(filterTitleStr)&&filterTitleStr!==''" ></span> <span v-else>{{ title }}</span> <button>{{ country }}</button> </td> <td>{{ author }}</td> <td>{{ reads }}</td> <td> <button @click="editFun(id)">编辑</button> <button @click="$emit('delPost', id)">删除</button> </td> </tr> </template> <script> export default { name: "TrItem", props: [ "id", "time", "title", "country", "author", "reads", "filterTitleStr", ], methods: { editFun(id) { // 展示对话框 this.$emit("changeShow"); // 把id传过去,通过id找到对应的内容 this.$emit("changeEditId", id); }, }, computed: { titleHasKeyStr() { const { title, filterTitleStr } = this; const ind = title.indexOf(filterTitleStr); return ( title.slice(0, ind) + "<span class='key-str'>" + filterTitleStr + "</span>" + title.slice(ind + filterTitleStr.length) ); }, }, }; </script>
# vue 的 transition 过渡
-
有六个 clss 状态
-
进入 出现 enter -
xx-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。 -
xx-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡 / 动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。 -
xx-enter-to: 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 xx-enter 被移除),在过渡 / 动画完成之后移除。 -
离开 消失 leave -
xx-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。 -
xx-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡 / 动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。 -
xx-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 xx-leave 被删除),在过渡 / 动画完成之后移除。
-
-
简单案例
<template> <div> <h3>vue 的 transition 组件实现过渡</h3> <button @click="show1=!show1">测试</button> <br /> <!-- 使用 transition 包裹需要执行过滤效果的元素,并且需要给 transition 组件传递一个 name 属性, name 属性的属性值,是要和对应的 class 挂钩的 --> <transition name="fade"> <span class="txt" v-show="show1">hello</span> </transition> </div> </template> <style> .box { width: 100px; height: 100px; background-color: #ccc; transition: opacity 1s; } .fadeOut { opacity: 0; } /*渐入渐出效果*/ /* .fade-enter-active, .fade-leave-active { transition: opacity 0.5s; } .fade-enter, .fade-leave-to { opacity: 0; } */ /*左侧进入右侧离开*/ .txt { display: block; width: 100px; text-align: center; border: 1px solid #ccc; margin-left: 200px; } .fade-enter { transform: translateX(-100px); opacity: 0; } .fade-enter-active, .fade-leave-active { transition: all 0.5s; } .fade-leave-to { transform: translateX(100px); opacity: 0; } </style>
# vue 的 动画
还是要理解 class 类名
-
简单案例
在 index.html 中引入,这里引入的三版本,四版本的语法变成了 animate__animated animate__flipInY (动画名)
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" /><template> <div> <button @click="show2=!show2">按钮</button> <transition name="xxx"> <p v-show="show2"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus. </p> </transition> <hr /> <button @click="show3=!show3">按钮</button> <!-- 自定义类名,主要注意的是 enter-active-class,leave-active-class 后面的 class 值就是执行动画的类名 --> <!-- 注意在 index.html中引入的版本号 --> <transition appear enter-active-class="animated tada" leave-active-class="animated flipOutX" > <p v-show="show3">Lorem ipsum dolor sit amet</p> </transition> <hr /> <!-- 当相同的元素之间执行动画切换的话,需要添加不同的 key 值 --> <!-- <transition name="fade"> <button @click="isEditing=false" v-if="isEditing" key="save"> Save </button> <button @click="isEditing=true" v-else key="edit">Edit</button> </transition> --> <!-- 上边的简写,mode 是模式 --> <transition name="fade" mode="out-in"> <button :key="isEditing" @click="isEditing=!isEditing"> {{ isEditing ? 'Save' : 'Edit' }} </button> </transition> </div> </template> <script> export default { name: "VueTransiton", data() { return { show2: true, show3: true, isEditing: false, }; }, }; </script> <style> .box { width: 100px; height: 100px; background-color: #ccc; transition: opacity 1s; } /* 文字消失的过程中 */ .xxx-leave-active { animation: bounce 0.5s linear; } /* 这里和上边的效果相反 */ /* .xxx-enter-active { animation: bounce 0.5s linear reverse; } */ .xxx-enter-active { animation: fadeRight 0.5s linear; } @keyframes bounce { 0% { transform: scale(1); } 50% { transform: scale(1.5); } 100% { transform: scale(0); } } @keyframes fadeRight { 0% { transform: translateX(300px); opacity: 0; } 50% { transform: translateX(50px); opacity: 0.5; } 100% { transform: translateX(0px); opacity: 1; } } </style> -
初始渲染的过渡 (appear 属性)
https://cn.vuejs.org/v2/guide/transitions.html#%E5%88%9D%E5%A7%8B%E6%B8%B2%E6%9F%93%E7%9A%84%E8%BF%87%E6%B8%A1
# 列表过渡
-
简单案例
<div id="list-complete-demo" class="demo"> <button @click="shuffle">Shuffle</button> <button @click="add">Add</button> <button @click="remove">Remove</button> <transition-group name="list-complete" tag="p"> <span v-for="item in items" v-bind:key="item" class="list-complete-item" >{{ item }}</span > </transition-group> </div> <script> // import _ from "lodash"; import shuffle from "lodash/shuffle"; export default { name: "VueTransiton", data() { return { items: [1, 2, 3, 4, 5, 6, 7, 8, 9], }; }, methods: { add() { // 数组中求最大数 const max = Math.max(...this.items); this.items.push(max + 1); }, remove() { // 获取一个数组中的随机元素 const random = Math.floor(Math.random() * (this.items.length + 1)); this.items.splice(random, 1); }, shuffle() { // 随机打乱数组 /* const shuffleItems = []; const copyItems = [...this.items]; const num = copyItems.length; for (let index = 0; index < num; index++) { const random = Math.floor(Math.random() * copyItems.length); const element = copyItems[random]; copyItems.splice(random, 1); shuffleItems.push(element); } this.items = shuffleItems; */ // this.items = _.shuffle(this.items); this.items = shuffle(this.items); }, }, }; </script>
# 可复用的过渡
-
简单案例
-
VueTransiton.vue
<button @click="show4 = !show4">按钮</button> <SpecialTransition> <p v-show="show4">sf;skfsfsjlfs</p> <h3 v-show="show4">sf;skfsfsjlfs</h3> </SpecialTransition> <script> import SpecialTransition from "./SpecialTransition"; export default { name: "VueTransiton", components: { SpecialTransition, }, data() { return { show4: true, }; }, }; </script> -
SpecialTransition.vue
<template> <!-- 就是一个 transition 动画组件 --> <transition name="fade1"> <slot /> </transition> </template> <script> export default { name: "SpecialTransition", }; </script> <style scoped> .fade1-enter-active, .fade1-leave-active { transition: opacity 0.5s; } .fade1-enter, .fade1-leave-to { opacity: 0; } </style>
-
# 动态过渡
默认的过渡效果和动画效果是定死的,只能去修改 name,为了方便使用了 transition 的 js 钩子,通过钩子获取 dom 节点,然后修改 dom 节点的样式
-
简单案例
<button @click="show3 = !show3">按钮</button> <!-- 自定义类名,主要注意的是 enter-active-class,leave-active-class 后面的 class 值就是执行动画的类名 --> 出现的时间:<input type="number" v-model.lazy="inTime" /> 消失的时间:<input type="number" v-model.lazy="outTime" /> <transition appear @before-enter="show3BeforeEnter" @before-leave="show3BeforeLeave" enter-active-class="animated tada" leave-active-class="animated flipOutX" > <!-- 这里用的是js钩子before-enter --> <div v-show="show3"> <!-- 动态控制出现和消失的动画持续时间 --> <!-- 这个 p 因为使用了animate.css动画库,默认时间是1s --> <p>Lorem ipsum dolor sit amet</p> </div> </transition> <script> export default { data() { return { show3: true, inTime: 1, outTime: 1, }; }, methods: { show3BeforeEnter(el) { console.log("出现动画执行之前触发", el); // el 获取的是原生 dom 节点 // 下边改的是行内样式,所以要有show3BeforeLeave来改变样式,否则消失的时间也会按照inTime来 el.style.animationDuration = this.inTime + "s"; }, show3BeforeLeave(el) { console.log("离开动画执行之前触发", el); el.style.animationDuration = this.outTime + "s"; }, }, }; </script>
# 状态过渡
-
简单案例
<h3>状态过渡(非进入离开的动效,比如大小颜色等等)</h3> <input type="text" v-model.lazy.number="num" /> <!-- 当失去焦点的时候,数字展示依次递增或递减到目标数字 --> <p>{{ showNum }}</p> <script> export default { name: "VueTransiton", data() { return { num: 0, showNum: 0, }; }, watch: { num: { handler(newValue) { const run = setInterval(() => { if (this.showNum !== newValue) { this.showNum++; } else { clearInterval(run); } }, 50); }, }, }, }; </script>
# 过滤器
过滤器可直接在 template 中使用,遵循模板语法
-
简单案例
<template> <div> <h3>vue 中过滤器的使用</h3> <input type="text" v-model="message" /> <div>过滤器结果{{ message | capitalize }}</div> <!-- message是实参 capitalize是过滤器函数--> <!-- <div>计算属性结果:{{ capitalizeMessage(message) }}</div> --> <div>计算属性结果:{{ capitalizeMessage }}</div> </div> </template> <script> export default { name: "FilterDemo", data() { return { message: "hello", }; }, computed: { // 要实现计算属性传参需要给计算属性返回函数类型,一般不使用计算属性返回一个函数 capitalizeMessage() { // return (str) => str.charAt(0).toUpperCase() + str.slice(1); return this.message.charAt(0).toUpperCase() + this.message.slice(1); }, }, // 过滤器和计算属性写法很像,区别是前者的函数可以接收参数 filters: { // 字符串首字母大写的过滤器 capitalize(value) { if (!value) return ""; value = value.toString(); return value.charAt(0).toUpperCase() + value.slice(1); }, }, }; </script> -
全局过滤器
-
main.js 文件
Vue.filter("capitalize", function (value) { if (!value) return ""; value = value.toString(); return value.charAt(0).toUpperCase() + value.slice(1); }); -
FilterDemo.vue 组件 因为是全局的,所以可以直接使用
<template> <div> <h3>vue 中过滤器的使用</h3> <input type="text" v-model="message" /> <div>过滤器结果{{ message | capitalize }}</div> <!-- message是实参 capitalize是过滤器函数--> <div>计算属性结果:{{ capitalizeMessage }}</div> </div> </template> <script> export default { name: "FilterDemo", data() { return { message: "hello", }; }, computed: { // 要实现计算属性传参需要给计算属性返回函数类型,一般不使用计算属性返回一个函数 capitalizeMessage() { // return (str) => str.charAt(0).toUpperCase() + str.slice(1); return this.message.charAt(0).toUpperCase() + this.message.slice(1); }, }, }; </script>
-
-
搜索案例
在 vue2 中 v-html 内默认不能使用过滤器,需要使用 $options.filters.过滤器名称 获取过滤器函数然后直接使用<template> <div> <input type="text" v-model.lazy="searchTxt" /> <div> <p v-for="todo in showTodos" :key="todo.id"> <!-- 如果 todo 的内容部分包含了 searchTxt,那么对应的关键字变色 --> <span v-if="!searchTxt">{{ todo.text }}</span> <!-- 在 vue2 中 v-html 内默认不能使用过滤器,需要使用 $options.filters.过滤器名称 获取过滤器函数然后直接使用 --> <span v-else v-html="$options.filters.getStr(todo.text, searchTxt)" ></span> </p> </div> </div> </template> <script> export default { name: "FilterDemo", data() { return { todos: [ { id: "111", text: "fsjklfsn" }, { id: "222", text: "nmvn,xcmnv" }, { id: "333", text: "equwoiuo" }, ], searchTxt: "", }; }, computed: { showTodos() { return this.todos.filter((todo) => todo.text.includes(this.searchTxt) ); }, }, filters: { getStr: function (text, searchTxt) { return `${text.slice( 0, text.indexOf(searchTxt) )}<span class='color'>${searchTxt}</span>${text.slice( text.indexOf(searchTxt) + searchTxt.length )}`; }, }, }; </script>