vue官方实例
vue实例:
head <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>Document</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script> <style> .active { color: skyblue; } .text-danger { color: red; } div { font-size: 14px; font-weight: normal; color: grey; } .title { font-size: 22px; font-weight: bolder; color: skyblue; } </style> </head> 实例1: <div id="app1"> <div class="title">(1) app1 插值表达式</div> {{message}} </div> var app = new Vue({ el: "#app1", data: { message: 'hello vue' } }) 实例2: <div id="app2"> <div class="title">(2) app2 v-bind</div> <span v-bind:title="message">鼠标悬停几秒看效果</span> </div> var app2 = new Vue({ el: "#app2", data: { message: '页面加载于 ' + new Date().toLocaleString() } }) 实例3: <div id="app3"> <div class="title">(3) app3 v-if</div> <p v-if="seen">现在你看到我了</p> </div> var app3 = new Vue({ el: "#app3", data: { seen: true } }) 实例4: <div id="app4"> <div class="title">(4) app4 v-for</div> <ol> <li v-for="todo in todos">{{todo.text}}</li> </ol> </div> var app4 = new Vue({ el: "#app4", data: { todos: [ { id: 1, text: '学习js' }, { id: 2, text: '学习vue' }, { id: 3, text: '学习node' }, ] } }) 实例5: <div id="app5"> <div class="title">(5) app5 v-on:click</div> <p>{{message}}</p> <button v-on:click="reverseMessage">逆转消息</button> </div> var app5 = new Vue({ el: '#app5', data: { message: 'hello vue' }, methods: { reverseMessage: function () { this.message = this.message.split('').reverse().join('') } } }) 实例6: <div id="app6"> <div class="title">(6) app6-双向数据绑定</div> <p>{{message}}</p> <input v-model="message"> </div> var app6 = new Vue({ el: '#app6', data: { message: 'klll dss' } }) 实例7: <div id="app7"> <div class="title">(7) app7-v-html-组件-绑定class对象</div> <div v-bind:class="{active:isActive}">1样式测试-绑定的数据对象定义在模板里</div> <div v-bind:class="classObj">2样式测试-绑定的数据对象定义在data中</div> <div v-bind:class="classObj1">3样式测试-绑定的数据对象是一个返回对象的计算属性</div> <div v-bind:class="[activeClass,errorClass]">4样式测试-把数组传给v-bind:class以应用一个class列表</div> <div v-bind:class="[isActive?activeClass:'',errorClass]">5样式测试-根据条件切换列表中的class</div> <div v-bind:class="[{active:isActive},errorClass]">6样式测试-根据条件切换列表中的class-数组语法中可以使用对象语法简单</div> <div v-bind:style="{color:activeColor,fontSize:fontSize+'px'}">7样式测试-绑定内联样式-对象语法</div> <div v-bind:style="styleObject">8样式测试-绑定内联样式对象</div> <ol> <todo-item v-for="item in groceryList" v-bind:todo="item" v-bind:key="item.id"></todo-item> </ol> <p>Using mustaches: {{ rawHtml }}</p> <!-- v-html把其当成html进行解析,span内容将会替换成属性值rawHtml,直接作为html,忽略解析属性值中的数据绑定 --> <p>Using v-html directive: <span v-html="rawHtml"></span></p> </div> // 全局注册组件,app7内的地方都可以引用 Vue.component('todo-item', { props: ['todo'], template: `<li v-bind:id="todo.id">{{todo.text}}</li>` }) var app7 = new Vue({ el: '#app7', data: { groceryList: [ { id: 2, text: '蔬菜' }, { id: 3, text: '奶酪' }, { id: 4, text: '随便时代开始的但是' } ], rawHtml: "<span style='color:red'>this should be red</span>", isActive: true, classObj: { active: false, 'text-danger': true }, isActive: true, error: null, activeClass: 'active', errorClass: 'text-danger', activeColor: 'red', fontSize: 30, styleObject: { color: 'red', fontSize: '21px' } }, computed: { classObj1: function () { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal' } } } }) 实例8: <!-- 计算属性 --> <div id="app8"> <div class="title">(8) app8-计算属性</div> <p>Original msg:"{{message}}"</p> <p>Computed reversed message:"{{reverseMessage}}"</p> </div> var app8 = new Vue({ el: '#app8', data: { message: 'ddd fff' }, computed: { // 计算属性的getter reverseMessage: function () { return this.message.split('').reverse().join('') } } }) 实例9: <div id="app9"> <div class="title">(9) app9-watch</div> {{fullName}} </div> var app9 = new Vue({ el: '#app9', data: { fName: 'ff', lName: 'll', // fullName:'ff ll' }, // 可以选择watch监听可以选择computed计算属性,推荐计算属性 computed: { fullName: function () { return this.fName + ' ' + this.lName } }, watch: { fName: function (val) { this.fullName = val + ' ' + this.lastName }, lName: function (val) { this.fullName = this.fName + ' ' + val } } }) 实例10: <div id="app10"> <div class="title">(10) app10-setter</div> {{fullNames}} </div> var app10 = new Vue({ el: '#app10', data: { fNames: 'ff', lNames: 'll', // fullNames:'ff ll' }, // 可以选择watch监听可以选择computed计算属性,推荐计算属性 computed: { fullNames: { get: function () { return this.fNames + ' ' + this.lNames }, set: function (newValue) { var names = newValue.split(' '); this.fNames = name[0]; this.lNames = names[names.length - 1]; } } } }) 实例11: <div id="app11"> <div class="title">(11) app11-watch</div> <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div> var app11 = new Vue({ el: '#app11', data: { question: '', answer: 'i cannot give you an answer until you ask a question' }, watch: { question: function (newQuestion, oldQuestion) { this.answer = 'waiting for you to stop typing...' this.debouncedGetAnser() } }, created() { this.debouncedGetAnser = _.debounce(this.getAnswer, 500) }, methods: { getAnswer: function () { if (this.question.indexOf('?') === -1) { this.answer = 'Questions usually contain a question mark. ;-)' return } this.answer = 'thisingk...' var vm = this axios.get('https://yesno.wtf/api') .then(function (response) { vm.answer = _.capitalize(response.data.answer) }) .catch(function (error) { vm.answer = 'error ' + error }) } } }) 实例12: <div id="app12"> <div class="title">(12) app12-v-for</div> <ul> <li v-for="item in items"> {{item.msg}} </li> </ul> <ul> <!-- 唯一key --> <li v-for="(item,index) in itemss" v-bind:key="index">{{parentMsg}} - {{index}} - {{item.msg}} </li> </ul> <div>计算属性computed-数组过滤或排序后的结果</div> <ul> <li v-for="n in evenNumbers">{{n}}</li> </ul> <div>methods-数组过滤或排序后的结果</div> <ul> <li v-for="n in even(numbers)">{{n}}</li> </ul> <div>将只渲染未完成的todo</div> <ul> <li v-for="todo in todos" v-if="!todo.isComplete"> {{todo}} </li> </ul> </div> var app12 = new Vue({ el: '#app12', data: { items: [ { msg: 'fj' }, { msg: 'fdss' } ], parentMsg: 'parent', itemss: [ { msg: 'dssd' }, { msg: 'dsdsde' } ], numbers: [1, 2, 3, 4, 5], todos: [ { isComplete: true, value: '12' }, { isComplete: false, value: '22' }, { isComplete: false, value: '33' } ] }, computed: { evenNumbers: function () { // filter过滤出能被2整除的元素 return this.numbers.filter(function (number) { return number % 2 === 0 }) } }, methods: { even: function (numbers) { return numbers.filter(function (number) { return number % 2 === 0 }) } } }) 实例13: <div id="app13"> <div class="title">(13) app12-v-for-todo</div> <form v-on:submit.prevent="addNewTodo"> <label>Add a todo</label> <input v-model="newTodoText" id="new-todo" placeholder="E.G. Feed the cat"> <button>Add</button> </form> <ul> <li is="todo-item" v-for="(todo,index) in todos" v-bind:key="todo.id" v-bind:title="todo.title" v-on:remove="todos.splice(index,1)"></li> </ul> </div> Vue.component('todo-item', { template: ` <li>\ {{title}}\ <button v-on:click="$emit(\'remove\')">Remove</button>\ </li>\ `, props: ['title'] }) var app13 = new Vue({ el: '#app13', data: { newTodoText: '', todos: [ { id: 1, title: 'Do the dishes', }, { id: 2, title: 'Take out the trash', }, { id: 3, title: 'Mow the lawn' } ], nextTodoId:4 }, methods:{ addNewTodo:function(){ this.todos.push({ id:this.nextTodoId++, title:this.newTodoText }) this.newTodoText = '' } } })
vue-router:
vue router功能: 嵌套的路由/视图表 模块化的/基于组件的路由配置 路由参数/查询/通配符 基于vue.js过渡系统的视图过渡效果 细粒度的导航控制 带有自动激活的css class的链接 h5历史模式或hash模式,在IE9中自动降级 自定义的滚动条行为 <router-view> 是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 <router-view> 以/开头的嵌套路径会被当作根路径,则使用嵌套路径无须设置嵌套的路径。
vue-router传参:
router传参方式:路由匹配参数;query方式传参;params方式传参; (1)动态路由匹配,路由匹配参数: // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } // 获取参数 let name = this.$route.params.id; // 链接里的id被封装进了 this.$route.params (2) query this.$router.push('/login/' + this.id); this.$route.query.id this.$router.push({ path: '/payment/recharge', query: { amount: that.amount } }); this.$route.query.amount 完全可以在链接后加上?进行传参 http://localhost:8080/?id=18 this.$route.query.id (3) params this.$router.push({ name: '确认图片', params: { amount: that.amount } }) this.$route.params.amount ps:若提供了path,则params会被忽略
$router && $route:
$router:router实例,用于路由跳转, (1)this.$router.push({ path: '/payment/recharge', query: { amount: that.amount } }); (2)this.$router.push({ name: '确认图片', params: { amount: that.amount } }) $route:当前激活的路由信息对象,用于获取参数, (1)this.$route.query.amount (2)this.$route.params.amount
嵌套路由:
嵌套路由: 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 } ] } ] })
编程式导航::
导航方式: (1)<router-link>创建a标签来定义导航链接(声明式导航) (2)router.push(location, onComplete?,onAbort?) (编程式导航) (3)router.replace(location, onComplete?,onAbort?) (编程式导航) (3)router.go(n) (编程式导航) ps:想要导航到不同的URL,则使用router.push方法,该方法会向history栈添加一个新的记录,当用户点击浏览器回退按钮时则回到之前的url。 该方法的参数可以是一个字符串路径或者一个描述地址的对象。router.replace不会向history添加新记录,只是替换当前的history记录。 router.go在history记录中向前或向后后退多少步。 // 字符串,路径path匹配 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 /register/userId=123 router.push({ name: 'user', params: { id: '1' }}) // 带查询参数,变成 /register?id=1 router.push({ path: 'register', query: { id: '1' }}) ps:若提供了path,则params会被忽略
命名路由:
在创建router实例的时候,在routes配置中给某个路由设置名称。 const router = new VueRouter({ routes: [ { path:'/user/:userId', name:'user', component:User } ] }) // 链接到命名路由方式(1)给router-link的to属性传递一个对象(2)给router.push传递一个对象 <router-link :to="{name:'user', params:{userId:123}}">User</router-link> router.push({name:'user', params: {userId:123}})
重定向:
重定向: { path: '/a', redirect: '/b' } { path: '/a', redirect: { name: 'foo' }}
导航守卫:
导航守卫:主要用来通过跳转或取消的方式守卫导航。登录的拦截,权限的校验,等 ps:参数或查询的改变并不会触发进入或离开的导航守卫。可以通过$route对象来应对这些变化或使用beforeRouteUpdate的组件内守卫。 全局前置守卫: const router = new VueRouter({...}) router.beforeEach((to, from, next)=>{ next() }) ps:一定要调用next方法来resolve这个钩子,执行效果依赖next方法的调用参数。进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed next(false) 中断当前导航,可以判断某些条件下如url改变了则中断,url会重置到from路由对应的地址; next('/) next({path:'/'}) 跳转到一个不同的地址,当前导航被中断,然后进行一个新的导航; 全局后置钩子: const router = new VueRouter({...}) router.afterEach((to, from, next)=>{ }) 路由独享的守卫: const router = new VueRouter({ routes:[ { path:'/foo', component:Foo, beforeEnter: (to, from, next) => { //... } } ] }) 组件内钩子: const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当钩子执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } } 完整的导航解析流程: 导航被触发。 在失活的组件里调用离开守卫。 调用全局的 beforeEach 守卫。 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。 在路由配置里调用 beforeEnter。 解析异步路由组件。 在被激活的组件里调用 beforeRouteEnter。 调用全局的 beforeResolve 守卫 (2.5+)。 导航被确认。 调用全局的 afterEach 钩子。 触发 DOM 更新。 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
路由元信息:
路由元信息:路由配置里的一个属性meta,其是一个对象,可以存放一些key-value,通过路由元信息meta实现不同路由展现不同页面(带不同的meta信息,展示不同页面布局) routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录 例如,根据上面的路由配置,/foo/bar 这个 URL 将会匹配父路由记录以及子路由记录。 一个路由匹配到的所有路由记录会暴露为 $route 对象 (还有在导航守卫中的路由对象) 的 $route.matched 数组。因此,我们需要遍历 $route.matched 来检查路由记录中的 meta 字段 直接在路由配置的时候,给每个路由添加一个自定义的meta对象,在meta对象中可以设置一些状态,来进行一些操作。用它来做登录校验再合适不过了。
路由懒加载:
路由懒加载: 当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,能提高页面的访问速度。 路由和组件的常用两种懒加载方式: 1.vue异步组件实现路由懒加载 component:resolve => (['需要加载的路由的地址',resolve]) 如component: resolve => require(['./page/linkParamsQuestion.vue'], resolve) 2.es提出的import const HelloWorld = () => import('需要加载的模块地址')
import Vue from 'vue' import 'normalize.css/normalize.css'// A modern alternative to CSS resets // 引入animated动画 import '@/styles/lib/animate.min.css' import '@/styles/lib/layer.css' import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' import './styles/index.scss' // global css import App from './App' import router from './router' import store from './store' import * as allFilters from './filters/allFilters' Object.keys(allFilters).forEach(key => { Vue.filter(key, allFilters[key]) }) import '@/icons' // icon // import FastClick from 'fastclick' // FastClick.attach(document.body); Vue.filter('changeMemberNum', function(val) { return val.replace(/\s/g, '').replace(/(.{4})/g, '$1 '); }) // import '@/permission' // permission control // 使用代理的方式请求URLaxios request // import Axios from 'axios' // import VueAxios from 'vue-axios' // Vue.use(VueAxios, Axios) // 微信js-sdk const $wx = require('weixin-js-sdk'); Vue.prototype.$wechat = $wx; import VueQrcode from '@chenfengyuan/vue-qrcode'; Vue.component(VueQrcode.name, VueQrcode); // 页面加载进度条显示NProgress import NProgress from 'nprogress' // Progress 进度条 import 'nprogress/nprogress.css'// Progress 进度条样式 router.beforeEach((to, from, next) => { NProgress.start() // 开启Progress NProgress.configure({ ease: 'ease', speed: 500 }); // 配置进度条 next(); NProgress.done() }) router.afterEach(() => { NProgress.done() // 结束Progress }) Vue.use(MintUI) Vue.config.productionTip = false new Vue({ el: '#app', router, store, template: '<App/>', components: { App } })
参考 & 感谢:vue官网 & 各路大神
https://segmentfault.com/a/1190000009651628
宝剑锋从磨砺出,梅花香自苦寒来。