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
宝剑锋从磨砺出,梅花香自苦寒来。

浙公网安备 33010602011771号