Vue2.x
注册组件:
// 注册
// 模板指向内容只能有一个根元素
Vue.component('runoob', {
template: '<h1>自定义组件!</h1>'
})
// 创建根实例
new Vue({
el: '#app'
})
注册一定要在实例化之前不然没有作用!
模板内容必须在#app层之内
// <runoob> 将只在父模板可用
即:
new Vue({
el: '#app',
components: {
'runoob': {
template: '<h1>自定义组件!</h1>'
}
}
})
--------------------------------------------------------------------------------
prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":
<div id="app">
<child message="hello!"></child>
</div>
<script>
Vue.component('child', {
// 声明 props
props: ['message'],
// 同样也可以在 vm 实例中像 "this.message" 这样使用
template: '<span>{{ message }}</span>'
})
// 创建根实例
new Vue({
el: '#app'
})
</script>
进阶版:
<div id="app">
<child :message="hello"></child>
//message对应模板里的{{ message }}
//hello对应datal里的hello
//即输出的为<span>ABCD</span>
</div>
<script>
Vue.component('child', {
// 声明 props
props: ['message'],
template: '<span>{{ message }}</span>'
})
// 创建根实例
new Vue({
el: '#app',
data:{
hello:'ABCD'
}
})
</script>
输出 'ABCD'
------------------------------------------------------------
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>在Vue中注册组件</title>
</head>
<body>
<div id="app">
<todo :todo-data="groceryList"></todo>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue " type="text/javascript"></script>
<script>
/**
* 请注意,extend创建的是一个组件构造器,而不是一个具体的组件实例。
* 所以他不能直接在new Vue中这样使用: new Vue({components: fuck})
* 最终还是要通过Vue.components注册才可以使用的。
*/
// 构建一个子组件
var todoItem = Vue.extend({
template: ` <li> {{ text }} </li> `,
props: {
text: {
type: String,
default: ''
}
}
})
// 构建一个父组件
// 组件命名时使用驼峰命名则引用时采用小写单词间加'-'分割的方法(如:todoItem =>todo-item)
var todoWarp = Vue.extend({
template: `
<ul>
<todo-item
v-for="(item, index) in todoData"
v-text="item.text"
></todo-item>
</ul>
`,
props: {
todoData: {
type: Array,
default: []
}
},
// 局部注册子组件
components: {
todoItem: todoItem
}
})
// 注册到全局
Vue.component('todo', todoWarp)
new Vue({
el: '#app',
data: {
groceryList: [
{ id: 0, text: '牛排' },
{ id: 1, text: '芝士' },
{ id: 2, text: '汉堡' }
]
}
})
</script>
</html>
v-bind 指令可以用于响应式地更新 HTML 特性:
<a v-bind:href="url">...</a>
<a href="url的值">...</a>
理解:
<a v-bind:AAA="BBB">...</a>
<a AAA="BBB">...</a>
缩写:
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
即:v-bind:省略v-bind => :
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
即:v-on => @
// $watch 是一个实例方法
vm.$watch('something', function (newValue, oldValue) {
// 这个回调将在 vm.something改变后调用
})
要写到实例化之后才有效果!
var vm =new Vue({
el: '#app', //vm.$el
data: { //vm.$data
selected: ''
}
});
document.write(vm.$data === data) // true
document.write(vm.$el === document.getElementById('vue_det')) // true
自定义指令
<div id="app">
<p>页面载入时,input 元素自动获取焦点:</p>
<input v-focus>
</div>
<script>
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
// 创建根实例
new Vue({
el: '#app'
})
</script>
Class排坑:
<style>
.active {
width: 100px;
height: 100px;
background: green;
}
.text-danger {
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="{ active: isActive}"></div>
//class正常命名正常使用
<div v-bind:class="{'text-danger': hasError }"></div>
//class含义其他符号(下划线'_'没事)使用单引号(双引号出错别用)
// 不然报错=> net::ERR_CONNECTION_TIMED_OUT
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: true,
hasError: true
}
})
</script>
//text-danger 类背景颜色覆盖了 active 类的背景色:
<style>
.active {
width: 100px;
height: 100px;
background: green;
}
.text-danger {
background: red;
}
</style>
<div id="app">
<div v-bind:class="classObject"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
classObject: {
active: true,
'text-danger': true
//如果写一个class列表注意单引号(双引号可以用和上面不一样) 不然Unexpected token -
}
}
})
</script>
//这里的css覆盖其实根本就没这功能全靠css样式的先后顺序,同权值的情况下已下面的为准而已。
//编写时注意css的顺序。
<style>
.base {
width: 100px;
height: 100px;
}
.active {
background: green;
}
.text-danger {
background: red;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="classObject"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: true,
error: {
value: true,
type: 'fatal'
}
},
computed: {
classObject: function () {
return {
base: true,
active: this.isActive && this.error.value,
'text-danger': this.error.value && this.error.type === 'fatal',
}
}
}
})
</script>
虽然第一眼看起来有点SB的写法不过慢慢理解后发现这样写比较灵活。
//把一个数组传给 v-bind:class
<style>
.active {
width: 100px;
height: 100px;
background: green;
}
.text-danger {
background: red;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="[activeClass, errorClass]"></div>
//是[] 不是{}
</div>
<script>
new Vue({
el: '#app',
data: {
activeClass: 'active',
errorClass: 'text-danger'
//直接使用class
}
})
</script>
//类似的写法
<div id="app">
<div v-bind:style="[baseStyles, overridingStyles]">菜鸟教程</div>
//这里是style 而不是class
</div>
<script>
new Vue({
el: '#app',
data: {
baseStyles: {
color: 'green',
fontSize: '30px'
},
overridingStyles: {
'font-weight': 'bold'
}
}
})
</script>
-----------------------------------------------------------------------------------
<style>
.text-danger {
width: 100px;
height: 100px;
background: red;
}
.active {
width: 100px;
height: 100px;
background: green;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: false,
activeClass: 'active',
errorClass: 'text-danger'
}
})
</script>
computed vs methods
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
把代码改了改,应该可以体现 computer 属性“依赖缓存”的概念以及与 method 的差别。如下面代码,cnt 是独立于 vm 对象的变量。在使用 reversedMessage 这个计算属性的时候,第一次会执行代码,得到一个值,以后再使用 reversedMessage 这个计算属性,因为 vm 对象没有发生改变,于是界面渲染就直接用这个值,不再重复执行代码。而 reversedMessage2 没有这个缓存,只要用一次,函数代码就执行一次,于是每次返回值都不一样。
var cnt=1;
var vm = new Vue({
el: '#app',
data: {
message: 'Runoob!'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
cnt+=1;
return cnt+this.message.split('').reverse().join('')
}
},
methods: {
reversedMessage2: function () {
cnt+=1;
return cnt+this.message.split('').reverse().join('')
}
}
})
/ / 输出结果 :
原始字符串: Runoob!
计算后反转字符串: 2!boonuR
计算后反转字符串: 2!boonuR
使用方法后反转字符串: 3!boonuR
使用方法后反转字符串: 4!boonuR
事件修饰符
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >
即当前输入框失去焦点时触发
.trim
如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:
注意是首尾空格中间的不管
<input v-model.trim="msg">
<div id="app">
<p>多个复选框:</p>
<input type="checkbox" id="runoob" value="Ruob" v-model="checkedNames">
<label for="runoob">Runoob</label>
<input type="checkbox" id="google" value="Gole" v-model="checkedNames">
<label for="google">Google</label>
<input type="checkbox" id="taobao" value="Taao" v-model="checkedNames">
<label for="taobao">taobao</label>
<br>
<span>选择的值为: {{ checkedNames }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
checkedNames: []
}
})
</script>
复选框的v-model绑定一个数组checkedNames,当复选框选择时数组添加当前value值。
如果没有value值则数组添加Null。
Vue.directive('runoob', function (el, binding) {
// 简写方式设置文本及背景颜色
el.innerHTML = binding.value.text
el.style.backgroundColor = binding.value.color
})
<div id="app">
<div v-runoob="{ color: 'green', text: '菜鸟教程!' }"></div>
</div>
binding输出为[object Object] 即:{ color: 'green', text: '菜鸟教程!' }对象
一个首字母大写的过滤器
<div id="app">
{{ message | capitalize }}
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'runoob'
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
</script>
<div id="app">
<p>原始字符串: {{ message }}</p>
<p>计算后反转字符串: {{ reversedMessage1 }}</p>
<p>计算后反转字符串: {{ reversedMessage2() }}</p>
</div>
如果是methods里的方法要加'()'
如果有同名的已后面的为准。
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Runoob!'
},
computed: {
// 计算属性的 getter
reversedMessage1: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
},
methods: {
// 计算属性的 getter
reversedMessage2: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
</script>
<div id="app">
<p>
全选:
</p>
<input type="checkbox" id="checkbox" v-model="checked" @change="changeAllChecked()">
<label for="checkbox">
{{checked}}
</label>
<p>
多个复选框:
</p>
<input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
<label for="runoob">
Runoob
</label>
<input type="checkbox" id="google" value="Google" v-model="checkedNames">
<label for="google">
Google
</label>
<input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
<label for="taobao">
taobao
</label>
<br>
<span>
选择的值为:{{checkedNames}}
</span>
</div>
new Vue({
el: '#app',
data: {
checked: false,
checkedNames: [],
checkedArr: ["Runoob", "Taobao", "Google"]
},
methods: {
changeAllChecked: function() {
if (this.checked) {
this.checkedNames = this.checkedArr
//如果点了全选将数组checkedArr直接填充数组checkedNames 中达到全选
} else {
this.checkedNames = []
}
}
},
watch: {
"checkedNames": function() {
if (this.checkedNames.length == this.checkedArr.length) {
//如果选择内容的长度等于最大长度触发全选按钮。
this.checked = true
} else {
this.checked = false
}
}
}
})
//提交
submit:function(){
var params=new Object();
params.AAA=this.AAA;
params.BBB=this.BBB;
params.CCC=this.CCC;
//将data里的值插入params对象中
//var con = JSON.stringify(params)
alert(JSON.stringify(params));
// something -> 调用api吧数据传到后台
}
}
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
new Vue({
el: '#app',
data: {
sites: [
{ text: 'Runoob' },
{ text: 'Google' },
{ text: 'Taobao' }
]
}
})
</script>
//为什么不直接<li v-for="item in sites">{{ item .text }}</li>呢?
过渡&动画:
v-show="false" 是 display: none;
v-if="false" 是直接去除
报错
也不知道为什么Warnings原来全是格式问题
Missing space before value for key 'props' (键值前缺少空格)
Missing space before opening brace(左大括号前缺少空格)
There should be no space before ','(在“,”之前不应该有空格)
A space is required after ',' (“,”后需要空格)
Trailing spaces not allowed (no-trailing-spaces) (不允许尾随空格)
Expected indentation of 4 spaces but found 6(预期缩进4个空格,但找到6个)
Strings must use singlequote (字符串必须使用单引号)
Missing semicolon (semi) (缺少分号(半))
Expected 1 empty line after import statement not followed by another import(导入语句后没有其他导入后,预计有1个空行)