vue基础
Vue自定义指令
<div id="app">
<input type="text" v-focus>
</div>
全局注册
Vue.directive{'focus',{
//指令选项
//指令调用,元素插入父节点时调用v-focus
inserted: function(el){
//聚焦元素
el.focus();
}
}}
局部注册
var app = new Vue({
el:'#app',
directives:{
focus:{
//指令选项
}
}
})
自定义指令的选项是由几个钩子函数组成的,每个都是可选的
bind:只调用一次,指令第一次绑定到元素时调用。可以定义一个在绑定时执行一次的初始化动作
inserted:被绑定元素插入父节点时调用(父节点存在即可) update:被绑定元素所在的末班更新时调用,不论绑定值是否变化,比较更新前后的绑定值,忽略不必要的模板更新
componentUpdate:被绑定元素所在模板完成一次更新周期时调用
unbind:只调用一次
el 指令所绑定的元素,可以用来直接操作DOM
binding 一个对象,包含以下属性
name:指令名 不包含v-前缀
value 指令的绑定值(指令名后的值)
Vue组件是单向数据流,所以无法在组件内部修改props value的值 解决办法就是给组件声明一个data,默认引用value的值,在组件内部维护data
表单类组件基本都有 v-model
异步组件
工程足够大,组件足够多,性能问题
vue允许组件定义为一个工厂函数,动态解析组件
Vue.js 只是在组件需要渲染时触发工厂函数,并且把结果缓存下来,用于后面再次渲染。
<div>
<child-component></child-component>
</div>
<script>
Vue.component('child-component',function(resole))
</script>
:is 特性 动态挂载组件
<div>
<component :is="currentView"></component>
<button @click="handle('A')">切换到A</button>
<button @click="handle('B')">切换到B</button>
</div>
<script>
var app = new Vue({
el:'#app',
components:{
comA:{
template:'<div>组件A</div>'
},
comB:{
template:'<div>组件B</div>'
}
},
data:{
currentView:'comA'
},
methods:{
handle:function(param){
this.curentView = 'com' + param;
}
}
})
</script>
vue内联模板
组件标签里使用 inline-template
eg: <child-component inline-template>
组件会把它当的内容当做模板,而不把他当做内容分发,模板更灵活。
(父子组件中数据都刻意渲染,作用域难理解。建议不使用)
递归组件
还是递归思想,只是vue写法
vue递归,必须给限制条件,否则抛出错误
vue访问slot
访问方法 $slots
this.$slots.default 包含所有没有被具名的slot
vue作用域是独立的 1、父组件模板在父组件作用域内编译,父组件模板的数据用父组件内data数据;
2、子组件模板在子组件作用域内编译,子组件模板的数据用子组件内data数据,如果要用父组件的必须用props传递;
3、子组件标签的数据,使用父组件内的data数据
<div id="demo">
<my-component v-if="show" v-bind:my-message="message">
<h2 v-if="show">{{message}}</h2>
</my-component>
</div>
<template id="child-component">
<h1>{{message}} {{myMessage}}</h1>
<slot v-if="show">this is slot</slot>
</template>
var vm = new Vue({
el : "#demo",
data : {
message : "vue",
show : true //<my-component>的show的数据
},
components : {
"my-component" : {
template : "#child-component",
props : ["myMessage"],
data : function(){
return {
message : "vue1",
show : true // #child-component的show的数据
}
}
}
}
});
vue slot(插槽) 组件的复合使用,混合父组件的内容与子组件的模板时,用slot,此过程叫做内容分发(transclusion). props传递数据。events触发事件、slot内容分发。Vue的3个Api来源,再复杂的组件也是这三部分。
子组件<slot>内的备用内容,它的作用域是子组件本身。
vue 父子组件 兄弟组件 跨级组件
父组件->子组件 props
子组件->父组件 $emit
$dispatch() //向上级派发事件(父级或多级都可以)
bus总线程传递
子组件中,this.$parent可以直接访问该组件的父实例或组件
父组件中,this.$children 访问它所有的子组件,而且可以递归向上或向下无线访问,直到最内层的组件
父组件中,子组件标签上使用ref指定一个名称,并在父组件内通过this.$refs来访问指定名称的子组件
$refs 在组件渲染完成后才填充,非响应式的。(直接访问子组件的应急方案,避免使用)
vue props
父组件向子组件传递数据! data 是组件自己的数据
一种是字符串数组
一种是对象
传递的数据不是写死的,用指令v-bind动态绑定,
父组
showFieldList(row) {
new this.$sidelipPage(FieldList, {
props: {
row
}
});
},
子组件
export default {
props: {
row: {
type: Object,//或者{String,Number}
default() {
return {};
}
}
}
}
vue 动态绑定 v-bind
eg:
<Form-item :label='item.formField'>
<Input type="text" v-model="formSearch.xm" placeholder="请输入..." size="small" />
</Form-item>
label = "{{item.formField}}"//不起作用,在label前加 :
vue列表渲染
<li v-for-"book in books">{{book}}</li>
vue v-else-if 紧跟v-if//v-else紧跟v-else-if或v-if
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
vue v-once
不需要表达式的指令 同v-cloak用法
首次渲染后不再随数据变化重新渲染
vue v-cloak
不需要表达式的指令
加载完之后才会显示,避免屏幕闪动
<div id="app" v-cloak>
{{msg}}
</div>
css中
[v-cloak] {
display: none;
}//写在@import 来加载 css 文件中会不起作用,将 [v-cloak] 写在 link 引入的 css 中,或者写一个内联 css 样式
简单路由
const NotFound = { template: '<p>Page not found</p>' }
const Home = { template: '<p>home page</p>' }
const About = { template: '<p>about page</p>' }
const routes = {
'/': Home,
'/about': About
}
new Vue({
el: '#app',
data: {
currentRoute: window.location.pathname
},
computed: {
ViewComponent () {
return routes[this.currentRoute] || NotFound
}
},
render (h) { return h(this.ViewComponent) }
})
render: (h, params) => {
return h("span", {
domProps: {
innerHTML: this.showUseStatus(params.row.useStatus)
},
style: {}
});
}
render 时间
render: (h, params) => {
return h("format", {
props: {
type: "date",
value: params.row.createTime,
param: "yyyy-MM-dd"
}
});
}
过度&动画(暂略)
异步组件
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
动态组件缓存
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
静态和动态的Prop
给 prop 传入一个静态的值:
<blog-post title="My journey with Vue"></blog-post>
prop 可以通过 v-bind 动态赋值
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<base-input v-bind:favorited="post.currentUserFavorited">
传入一个对象的所有属性
v-bind (取代 v-bind:prop-name)
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:post="post"></blog-post>
post: {
id: 1,
title: 'My Journey with Vue'
}
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>
向父级组件发送消息
添加一个 postFontSize 数据属性来支持这个功能:
new Vue({
el: '#blog-posts-events-demo',
data: {
posts: [/* ... */],
postFontSize: 1
}
})
$emit 方法并传入事件的名字,来向父级组件触发一个事件:
<button v-on:click="$emit('enlarge-text')">
Enlarge text
</button>
v-on 在博文组件上监听这个事件,就像监听一个原生 DOM 事件一样:
<blog-post
...
v-on:enlarge-text="postFontSize += 0.1"
></blog-post>
Prop 向子组件传递数据
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
一个组件默认可以拥有任意数量的prop,任何值都可以传递给任何prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样
组件
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
把这个组件作为自定义元素来使用:
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })
任意次数的复用:(组件之间互不影响,因为都市new的)
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:否则一个组件影响到其他实例
data: function () {
return {
count: 0
}
}
组件的全局注册和局部注册。一般都只是通过 Vue.component 全局注册
Vue.component('my-component-name', {
// ... options ...
})
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中
组件的局部注册
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components 选项中定义你想要使用的组件:(局部注册的组件在其子组件中不可用)
new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
自动过滤用户输入的首尾空白字符
<input v-model.trim="msg">
多个复选框,绑定到同一个数组
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
单选按钮
<div id="example-4">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
new Vue({
el: '#example-4',
data: {
picked: ''
}
})
选择框
单选时:
<div id="example-5">
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '...',
data: {
selected: ''
}
})
多选时 (绑定到一个数组):
<div id="example-6">
<select v-model="selected" multiple style="width: 50px;">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '#example-6',
data: {
selected: []
}
})
按键修饰符
通过全局 config.keyCodes 对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
监听事件
v-on:click="XXX"
内联语句处理器中访问原始的DOM,用变量$event
<button v-on:click="onclick('message',$event)"></button>
onclick(message,event){
alert(event);
}
v-for with v-if
同一节点,v-for 的优先级比 v-if 更高
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo }}
</li>
v-if 置于外层元素
<ul v-if="todos.length">
<li v-for="todo in todos">
{{ todo }}
</li>
</ul>
<p v-else>No todos left!</p>
组件中使用 v-for 时,key 现在是必须的
<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
v-for 遍历数组、对象
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
对象
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
//结果
0 firstName: John
1 lastName: Doe
2 age 30
v-show
根据条件展示元素的选项是 v-show 指令
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换
v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级
条件渲染
v-else 指令来表示 v-if v-else-if
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
class / style 组件,数据绑定 同样适用
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
添加 errorClass,但是只有在 isActive 是 truthy[1] 时才添加 activeClass
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
表示 active 这个 class 存在与否将取决于数据属性 isActive和text-danger 的 true or false
数组语法
将多个样式对象应用到同一个元素上
<div v-bind:style="[baseStyles, overridingStyles]"></div>
监听 watch
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
计算属性 computer
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新
v-bind 缩写:
在这里 href 是参数,告知 v-bind 指令将该元素的 href 特性与表达式 url 的值绑定
<a v-bind:href="url">...</a>
v-on 指令,它用于监听 DOM 事件 缩写@(有的html不识别)
<a v-on:click="doSomething">...</a>
v-if 指令
将根据表达式 seen 的值的真假来插入/移除 <p> 元素
<p v-if="seen">现在你看到我了</p>
v-once 指令
数据改变时,插值处的内容不会更新
<span v-once>这个将不会改变: {{ msg }}</span>