Loading... # 过滤器 > Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:**双花括号插值和 `v-bind` 表达式** (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示: 过滤器的种类: - 全局过滤器:创建 Vue 实例之前全局定义过滤器 - 局部过滤器:在一个组件的选项中定义本地的过滤器 tip:当全局过滤器和局部过滤器重名时,会采用局部过滤器。 全局过滤器 ```javascript Vue.filter('过滤器名称', function (value[,param1,...] ) { //逻辑代码 }) ``` 定义局部过滤器 ```javascript new Vue({ filters: { '过滤器名称': function (value[,param1,...] ) { // 逻辑代码 } } }) ``` 应用过滤器 ```html {{ 表达式 | 过滤器名字}} ``` 案例: ```html <body> <div id="myDiv"> <p>未使用过滤器: {{birthday}}</p> <p>{{birthday | dataFormat}}</p> <p>未使用过滤器: {{message}}</p> <p>将钟替换为王: {{message | messageFormat}}</p> <p>不传参,默认使用刘: {{message | paramFormat}}</p> <p>传参,使用参数: {{message | paramFormat("罗")}}</p> </div> <script src="./js/vue.js"></script> <script src="./js/moment.js"></script> <script type="text/javascript"> Vue.filter("dataFormat", (value) => { return moment(value).format("YYYY-MM-DD HH:mm:ss"); }); Vue.filter("messageFormat", (value) => { return value.replace('钟', "王") }); const app = new Vue({ el: "#myDiv", data: { birthday: new Date(), message: '钟先生要出人头地' }, filters: { 'paramFormat': (value, param = "刘") => { return value.replace("钟", param) } } }) </script> </body> ```  # 侦听器 > 虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 `watch` 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。 `watch` 可以让我们监控一个值的变化。从而做出相应的反应。 ```html <body> <div id="app"> <input type="text" v-model='message'> </div> <script src="./js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: 'Hello World', }, watch: { message(newMessage, oldMessage) { console.log('新的值' + newMessage); console.log('旧的值' + oldMessage); } } }) </script> </body> ``` **深度监控** 如果监控的是一个对象,需要进行深度监控,才能监控到对象中属性的变化。 以前定义监控时,person 是一个函数,现在改成了对象,并且要指定两个属性: - `deep`:代表深度监控,不仅监控 person 变化,也监控 person 中属性变化 - `handler`:监控处理函数 ```html <body> <div id="app"> <input type="text" v-model="person.name"><br> <input type="text" v-model="person.age"> <button @click="person.age++">+</button> <h2> 姓名为:{{person.name}};年龄为:{{person.age}} </h2> </div> <script src="./js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { person: {} }, watch: { person: { deep: true, handler(obj) { console.log("name = " + obj.name + ", age=" + obj.age); } } } }) </script> </body> ``` # 组件化 ## 全局组件 在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。 - **组件其实也是一个 Vue 实例,因此它在定义时也会接收:data、methods、生命周期函数等** - 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有 el 属性 - 但是组件渲染需要 html 模板,所以增加了 template 属性,值就是 HTML 模板 - 全局组件定义完毕,任何 vue 实例都可以直接在 HTML 中通过组件名称来使用组件 - **一个组件的 `data` 选项必须是一个函数**,因此每个实例可以维护一份被返回对象的独立的拷贝 - 组件可以多次复用 ```html <div id="app"> <!--使用定义好的全局组件--> <counter></counter> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script type="text/javascript"> // 定义全局组件,两个参数:1,组件名称。2,组件参数 Vue.component("counter",{ template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>', data(){ return { count:0 } } }) var app = new Vue({ el:"#app" }) </script> ``` ## 局部组件 一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着 Vue 的加载而加载。 因此,对于一些并不频繁使用的组件,我们会采用局部注册。 我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致: ```javascript const counter = { template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>', data(){ return { count: 0 } } }; ``` 在 vue 页面中使用 ```javascript var app = new Vue({ el:"#app", components:{ counter: counter // 将定义的对象注册为组件 } }) ``` - components 就是当前 Vue 对象子组件集合。 - 效果与刚才的全局注册是类似的,不同的是,这个 counter 组件只能在当前的 Vue 实例中使用 ## 组件传值 我们定义一个子组件,并接受复杂数据: ```javascript const myList = { template: '<ul><li v-for="item in items" :key="item.id"> {{item.id}} : {{item.name}} </li></ul>', props: { items: { type: Array, default: [], required: true } } }; ``` 这个子组件可以对 items 进行迭代,并输出到页面。 props:定义需要从父组件中接收的属性 items:是要接收的属性名称 - type:限定父组件传递来的必须是数组 - default:默认值 - required:是否必须 ```html <div id="app"> <!-- 使用子组件的同时,传递属性,这里使用了v-bind,指向了父组件自己的属性lessons --> <my-list :items="lessons"/> </div> <script> var app = new Vue({ el: "#app", components:{ myList }, data: { lessons:[ {id:1, name: 'java'}, {id:2, name: 'python'}, {id:3, name: 'ui'}, ] } }) </script> ``` 另外看这个案例: ```javascript <div id="app"> <h2>num: {{num}} </h2> <!--使用子组件的时候,传递num到子组件中--> <counter :num="num"></counter> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 子组件,定义了两个按钮,点击数字num会加或减 Vue.component("counter", { template:'\ <div>\ <button @click="num++">加</button> \ <button @click="num--">减</button> \ </div>', props:['num']// count是从父组件获取的。 }) var app = new Vue({ el:"#app", data: { num: 0 } }) </script> ``` h2 中的 num 是修改不了的,为什么呢?子组件接收到父组件属性后,默认是不允许修改的。在官方文档也解释到了。https://cn.vuejs.org/v2/guide/components-props.html 只有父组件能修改,那么加和减的操作一定是放在父组件: ```javascript var app = new Vue({ el:"#app", data:{ num: 0 }, methods:{ // 父组件中定义操作num的方法 increment(){ this.num++; }, decrement(){ this.num--; } } }) ``` 我们可以**通过v-on指令将父组件的函数绑定到子组件**上: ```html <div id="app"> <h2>num: {{num}}</h2> <counter :count="num" @inc="increment" @dec="decrement"></counter> </div> ``` 在子组件中定义函数,函数的具体实现调用父组件的实现,并在子组件中调用这些函数。当子组件中按钮被点击时,调用绑定的函数: ```javascript Vue.component("counter", { template:'\ <div>\ <button @click="plus">加</button> \ <button @click="reduce">减</button> \ </div>', props:['count'], methods:{ plus(){ this.$emit("inc"); }, reduce(){ this.$emit("dec"); } } }) ``` 也就是说:**vue 提供了一个内置的 `this.$emit()` 函数,用来调用父组件绑定的函数** # 路由 ## 案例使用 现在我们来实现这样一个功能:一个页面,包含登录和注册,点击不同按钮,实现登录和注册页切换。  首先我们需要先创建两个组件,分别是登录和注册 login.js ```javascript const loginForm = { template:'\ <div>\ <h2>登录页</h2> \ 用户名:<input type="text"><br/>\ 密码:<input type="password"><br/>\ </div>\ ' } ``` register.js ```javascript const registerForm = { template:'\ <div>\ <h2>注册页</h2> \ 用 户 名:<input type="text"><br/>\ 密  码:<input type="password"><br/>\ 确认密码:<input type="password"><br/>\ </div>\ ' } ``` 在首页中分别引入它们 index.html ```html <body> <div id="app" style="text-align: center;font-size: 120%;"> <!--router-link来指定跳转的路径--> <span> <router-link to="/login">登录</router-link> </span> <span> <router-link to="/register">注册</router-link> </span> <hr /> <div> <!--vue-router的锚点--> <router-view></router-view> </div> </div> <script src="../js/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <script src="./login.js"></script> <script src="./register.js"></script> <script type="text/javascript"> // 定义路由 const routes = [{ path: '/login', component: loginForm }, { path: '/register', component: registerForm } ] // 创建 router 实例,然后传 routes 配置 const router = new VueRouter({ routes // (缩写) 相当于 routes: routes }) var vm = new Vue({ el: "#app", router }) </script> </body> ``` - 通过 router-link 指定一个跳转链接,当点击时,会触发 vue-router 的路由功能。 - 通过 router-view 来指定一个锚点,当路由的路径匹配时,vue-router 会自动把对应组件放到锚点位置进行渲染。 - 创建 VueRouter 对象,并指定路由参数 - routes:路由规则的数组,可以指定多个对象,每个对象是一条路由规则,包含以下属性: - - path:路由的路径 - component:组件名称 ## 动态路由 经常的,像 `/user/foo` 和 `/user/bar` 、 `/user/100` 和 `/user/101` 映射到同个组件上,就需要用到动态路由配置。简单的,我们可以用 `:` 一个 “路径参数” 使用冒号 `:` 标记。当匹配到一个路由时,参数值会被设置到 `this.$route.params`,可以在每个组件内使用。 ```javascript routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] ``` ```html <div>{{ $route.params.id }}</div> ``` | 模式 | 匹配路径 | $route.params | | ----------------------------- | ------------------- | -------------------------------------- | | /user/:username | /user/evan | `{ username: 'evan' }` | | /user/:username/post/:post_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` | 除了 `$route.params` 外,`$route` 对象还提供了其它有用的信息,例如,`$route.query` (如果 URL 中有查询参数)、`$route.hash` 等等。 ## 嵌套路由 ```javascript const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 当 /user/:id/profile 匹配成功, // UserProfile 会被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 当 /user/:id/posts 匹配成功 // UserPosts 会被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] }) ``` ## 命名路由 你可以在创建 Router 实例的时候,在 `routes` 配置中给某个路由设置名称。 ```js const router = new VueRouter({ routes: [ { path: '/user/:userId', name: 'user', component: User } ] }) ``` 要链接到一个命名路由,可以给 `router-link` 的 `to` 属性传一个对象: ```html <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link> ``` 这跟代码调用 `router.push()` 是一回事,具体后面介绍。 ```js router.push({ name: 'user', params: { userId: 123 }}) ``` ## 编程式路由 ### router.push() 除了使用 `<router-link>` 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。 | 声明式 | 编程式 | | ------------------------- | ------------------ | | `<router-link :to="...">` | `router.push(...)` | **在 Vue 实例内部,你可以通过 `$router` 访问路由实例。因此你可以调用 `this.$router.push`。** 想要导航到不同的 URL,则使用 `router.push` 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。 ```javascript // 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由,(name -> params) router.push({ name: 'user', params: { userId: '123' }}) // 带查询参数,变成 /register?plan=private (path -> query) router.push({ path: 'register', query: { plan: 'private' }}) ``` **如果提供了 `path`,`params` 会被忽略。** ```javascript const userId = '123' router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user ``` ### router.replace() 跟 `router.push` 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。 | 声明式 | 编程式 | | --------------------------------- | --------------------- | | `<router-link :to="..." replace>` | `router.replace(...)` | ### router.go(n) 这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 `window.history.go(n)`。 例子 ```javascript // 在浏览器记录中前进一步,等同于 history.forward() router.go(1) // 后退一步记录,等同于 history.back() router.go(-1) // 前进 3 步记录 router.go(3) // 如果 history 记录不够用,那就默默地失败呗 router.go(-100) router.go(100) ``` # 状态管理 Vuex 是一个专为 Vue.js 应用程序开发的**状态管理模式**。 ```javascript import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) ``` 现在,你可以通过 `store.state` 来获取状态对象,以及通过 `store.commit` 方法触发状态变更: ```js store.commit('increment') console.log(store.state.count) // -> 1 ``` 为了在 Vue 组件中访问 `this.$store` property,你需要为 Vue 实例提供创建好的 store。Vuex 提供了一个从根组件向所有子组件,以 `store` 选项的方式“注入”该 store 的机制: ```js new Vue({ el: '#app', store, methods: { increment() { this.$store.commit('increment') console.log(this.$store.state.count) } } }) ``` 注意:我们通过提交 mutation 的方式,而非直接改变 `store.state.count`,是因为我们想要更明确地追踪到状态的变化。 参考资料 https://router.vuejs.org/zh/ https://vuex.vuejs.org/zh/ https://mp.weixin.qq.com/s/KrkEpUjWoQ35ZjC0CP8slQ<hr class="content-copyright" style="margin-top:50px" /><blockquote class="content-copyright" style="font-style:normal"><p class="content-copyright">版权属于:乐心湖's Blog</p><p class="content-copyright">本文链接:<a class="content-copyright" href="https://www.xn2001.com/archives/646.html">https://www.xn2001.com/archives/646.html</a></p><p class="content-copyright">声明:博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" target="_blank" rel="nofollow noopener noopener" one-link-mark="yes">CC BY-SA 4.0 协议</a> ,转载请注明出处!</p></blockquote> 腾讯云社区邀请各位技术博主加入,福利多多噢! Last modification:March 31st, 2021 at 12:15 am © 允许规范转载 Support 如果觉得我的文章对你有用,请随意赞赏 ×Close Appreciate the author Sweeping payments Pay by AliPay Pay by WeChat