学习资源--Vue2官网
Vue2停更后,发现官网原来的学习路径变成英文了,所以找到了中文简介进行学习:
简介 | Vue.js https://cn.vuejs.org/guide/introduction
一、模板语法
1.1 文本插值、html插值、属性和使用限制
在about组件中写测试代码。不废话,直接上代码。
<template>
<div class="about">
<h1>This is an about page</h1>
{{ msg }}
<div v-html="htmTxt"></div>
<div v-bind:id="id" >百度</div>
<div :id="id" >百度</div>
<p>{{ count + 1 }}</p>
</div>
</template>
<script>
export default {
name: 'HomeView',
data() {
return {
msg: '<h2>静态文本</h2>',
htmTxt:'<h2>静态文本</h2>',
id: '1234',
attr: 'test-id',
count: 0,
}
},
components: {
}
}
</script>
使用限制:
1、插值仅限于表达式。
2、关于缩写,当属性和属性名称相同时,比如 属性id,属性名称id,可以写成 :id, Vue2不支持。
1.2 简单的事件,用于测试语法
<template>
<div class="about">
<h1>This is an about page</h1>
{{ msg }}
<div v-html="htmTxt"></div>
<div v-bind:id="id" >百度1</div>
<div :id="id" >百度2</div>
<div :testid = "testid">动态属性绑定</div>
<p>{{ count + 1 }}</p>
<p @click="myclick()">事件测试</p>
</div>
</template>
<script>
export default
{
name: 'HomeView',
data() {
return {
msg: '<h2>静态文本</h2>',
htmTxt:'<h2>静态文本</h2>',
id: '1234',
testid: 'testid',
count: 0,
}
},
methods:
{
myclick() {
this.count += 1;
console.log('点击事件');
var s = document.getElementById("1234").innerHTML;
alert(s)
}
},
components: {
}
}
</script>
1.3 指令:v-if、v-else、v-show
使用这几个指令控制dom显示,代码:
<template>
<div class="about">
<h1>This is an about page</h1>
{{ msg }}
<div v-html="htmTxt"></div>
<div v-bind:id="id" >百度1</div>
<div :id="id" >百度2</div>
<div :testid = "testid">动态属性绑定</div>
<p>{{ count + 1 }}</p>
<p @click="myclick()">控制Dom显示</p>
<div v-if="count % 2 == 0">count是偶数</div>
<div v-else>count是奇数</div>
<div v-show="count % 2 == 0">v-show:count是偶数时显示</div>
</div>
</template>
<script>
export default
{
name: 'HomeView',
data() {
return {
msg: '<h2>静态文本</h2>',
htmTxt:'<h2>静态文本</h2>',
id: '1234',
testid: 'testid',
count: 0,
}
},
methods:
{
myclick() {
console.log('点击事件');
var s = document.getElementById("1234").innerHTML;
alert(s)
this.count += 1;
}
},
components: {
}
}
</script>
心得:
1、v-if 和 v-show都实现了dom元素的渲染控制,他们的差别是:v-if 是真正控制了dom内容的输出,即dom中有就显示没有就不显示;而v-show是通过display:none来控制元素的显示的。
2、<div v-if>模块如果使用 <template v-if >来替换,可以消除本身模块在dom中的占位。
1.4 指令:v-for
<template>
<div class="about">
<h1>This is an about page</h1>
<ul>
<li v-for="student in students" :key="student.idx">
{{ student.idx }} - {{ student.name }} - {{ student.age }}岁
</li>
</ul>
</div>
</template>
<script>
export default
{
name: 'HomeView',
data() {
return {
students: [
{idx:'1', name: '张三', age: 18 },
{idx:'2', name: '李四', age: 19 },
{idx:'3', name: '王五', age: 20 }
]
}
},
components: {
}
}
</script>
1.5 指令 v-mode
绑定表单数据。
<template>
<div class="about">
<h1>This is an about page</h1>
<ul>
<li v-for="student in students" :key="student.idx">
{{ student.idx }} - {{ student.name }} - {{ student.age }}岁
</li>
</ul>
<button @click="$router.push('/')">Go to Home</button>
<input type="text" v-model.lazy="students[0].name" placeholder="修改第一个学生的名字"/>
<input type="number" v-model.number="students[0].age" placeholder="修改第一个学生的年龄"/>
<div>
<span>第一个学生的信息:</span>
<span>{{ students[0].idx }} - {{ students[0].name }} - {{ students[0].age }}岁</span>
</div>
<button @click="students.push({idx: students.length + 1 + '', name: '新学生', age: 18})">添加新学生</button>
</div>
</template>
<script>
export default
{
name: 'HomeView',
data() {
return {
students: [
{idx:'1', name: '张三', age: 18 },
{idx:'2', name: '李四', age: 19 },
{idx:'3', name: '王五', age: 20 }
]
}
},
methods: {
},
components: {
}
}
</script>
心得:
1、v-mode与绑定的数据是同步更新的。为了让数据在事件后更新,使用v-mode.lazy。
2、修饰符有三个:.lazy、number、trim。
1.6 方法(methods)、计算属性(computed)和侦听器(watch)
<template>
<div class="about">
<h1>This is an about page</h1>
<h3>价格计算</h3>
单价:<input type="number" v-model.number="price" placeholder="输入价格"/>
数量:<input type="number" v-model.number="quantity" placeholder="输入数量"/>
<button @click="price = 1; quantity = 1;">reset</button>
<div>
<span>总价:</span>
<span>函数计算:{{ getSum()}}</span> <span>计算属性{{ calcSum }}</span>
</div>
</div>
</template>
<script>
export default
{
name: 'HomeView',
data() {
return {
price: 1,
quantity: 1,
}
},
methods: {
getSum() {
return this.price * this.quantity;
}
},
computed: {
calcSum() {
return this.price * this.quantity;
}
},
watch: {
price(newVal, oldVal) {
console.log(`price changed from ${oldVal} to ${newVal}`);
},
},
components: {
}
}
</script>
心得:
1、插值表达式、函数计算和计算属性都可以。计算属性的优点:当数据没有发生变化时,不会重新计算。
1.7 v-bind 之 class与style绑定
<template>
<div class="about">
<h1>This is an about page</h1>
<h3>价格计算</h3>
单价:<input type="number" v-model.number="price" placeholder="输入价格"/>
数量:<input type="number" v-model.number="quantity" placeholder="输入数量"/>
<button @click="price = 1; quantity = 1;">reset</button>
<div>
<span>总价:</span>
<span>函数计算:{{ getSum()}}</span> <span>计算属性{{ calcSum }}</span>
</div>
<div><span>绑定样式</span><br/>
<div :class="{ active: price > 5 }">
价格大于5元时显示红色,否则显示绿色
</div>
</div>
</div>
</template>
<script>
export default
{
name: 'HomeView',
data() {
return {
active: 'active',
price: 1,
quantity: 1,
}
},
methods: {
getSum() {
return this.price * this.quantity;
}
},
computed: {
calcSum() {
return this.price * this.quantity;
}
},
watch: {
price(newVal, oldVal) {
console.log(`price changed from ${oldVal} to ${newVal}`);
},
},
components: {
}
}
</script>
心得:
可以绑定对象、数组、数组对象。
二、组件
2.1 组件基础
1、组件由html模板、js脚本和css三部分组成。
2、html模板内只能使用一个div。
3、组件目的是为了重用。一个页面可以在多个地方引用同一个组件。
4、组件是独立的,各组件内的数据互不相关。
5、所以data必须是函数
6、页面和组件之间传递数据:props。父传子。
7、组件可以通过事件向页面传递数据。子传父。
8、插槽。
2.2 第一个组件Hello.vue
Show me your code.
第一个组件hello.vue
<template>
<div class="hello">
<h1>Vue2 component</h1>
</div>
</template>
<script>
export default {
name: 'HelloView',
data() {
return {}
},
methods: {
},
components: {
}
}
</script>
<style scoped>
</style>
在about中引入hello.vue:
step1 import Hello from '@/components/Hello.vue';
step2 components: { Hello, }
step3 在所需处使用组件:<Hello/>
<template>
<div class="about">
<h1>This is an about page</h1>
<Hello/>
<Hello/>
<Hello/>
</div>
</template>
<script>
import Hello from '@/components/Hello.vue';
export default
{
name: 'AboutView',
data() {
return {
}
},
methods: {
},
components: {
Hello,
}
}
</script>
2.3 父页面通过props向组件传递数据
父页面代码:
<template>
<div class="about">
<h1>This is an about page</h1>
<Hello name="张三" code="007" :id='1'/>
<Hello name="李四" code="008" id='2'/>
<Hello/>
</div>
</template>
<script>
import Hello from '@/components/Hello.vue';
export default
{
name: 'AboutView',
data() {
return {
}
},
methods: {
},
components: {
Hello,
}
}
</script>
子组件代码:
<template>
<div class="hello">
<h1>Vue2 component</h1>
<p>id: {{ id }}</p>
<p>{{ code }}</p>
<p>name: {{ name }}</p>
</div>
</template>
<script>
export default {
name: 'HelloView',
data() {
return {
}
},
methods: {
},
components: {
},
props: {
id: {
type: Number,
default: 0
},
code: {
type: String,
default: ''
},
name: {
type: String,
default: ''
}
}
}
</script>
<style scoped>
</style>
注意:
1、data函数内不要再声明相同的变量了。
2、注意,id=“2”传递的是字符串,props验证会有错误:vue.runtime.esm.js:4482 [Vue warn]: Invalid prop: type check failed for prop "id". Expected Number with value 2, got String with value "2".
2.4 组件通过事件向父页面传递数据
组件代码:
<template>
<div class="hello">
<h1>Vue2 component</h1>
<p>id: {{ id }}</p>
<p>{{ code }}</p>
<p>name: {{ name }}</p>
<button @click="myPostMsg">向父页面发送数据</button>
</div>
</template>
<script>
export default {
name: 'HelloView',
data() {
return {
}
},
methods: {
myPostMsg() {
this.$emit('helloMsg', this.name);
}
},
components: {
},
props: {
id: {
type: Number,
default: 0
},
code: {
type: String,
default: ''
},
name: {
type: String,
default: ''
}
}
}
</script>
<style scoped>
</style>
父页面代码:
<template>
<div class="about">
<h1>This is an about page</h1>
<Hello name="张三" code="007" :id='1' @helloMsg="doHelloMsg"/>
<Hello name="李四" code="008" :id='2' @helloMsg="doHelloMsg"/>
<Hello @helloMsg="doHelloMsg"/>
<p>{{ msg }}</p>
</div>
</template>
<script>
import Hello from '@/components/Hello.vue';
export default
{
name: 'AboutView',
data() {
return {
msg: 'who?'
}
},
methods: {
doHelloMsg(data) {
console.log('AboutView 接收到数据:' + data);
this.msg = '收到子组件传过来的数据:' + data;
}
},
components: {
Hello,
}
}
</script>
理解:
1、从c++解耦的角度思考问题。子组件是父页面的组成部分;父页面应该是parent指针存在于子组件中。
2、子组件中定义了一个传数据的回调函数,参数一般是const char*,父页面中定义同样参数的函数,并将函数指针传递给子组件中。子组件在使用发送数据函数就相当于父页面执行已定义的参数是const char* 的函数。
3、根据上面两条规则,我们来看代码实现。
回调函数名称为 helloMsg, 参数为 字符串。
子组件中使用点击事件来实现 helloMsg的函数的执行(不必须是点击事件,任何函数都可以,只要“this.$emit('helloMsg', this.name);” 能执行到)。 emit函数执行已注册函数的运行(一般情况下,父页面已经完成函数指针的注册,如果注册函数null则不执行)。
父页面中通过 <...... @helloMsg="doHelloMsg"/> 绑定回调函数为 doHelloMsg。所以子组件执行已注册函数时相当于执行 父页面的doHelloMsg函数。
总结:
三步走:
1、子组件中某个函数中实现 this.$emit('helloMsg', 需要传递的数据);” helloMsg是双方的桥梁。
2、父页面在组件使用时,指定绑定的函数。比如 @helloMsg="doHelloMsg"/> 绑定了回调函数为doHelloMsg。
3、父页面中实现doHelloMsg(字符串参数)函数。
2.5 插槽
2.5.1 插槽内容
父页面
......
<Hint>来自父页面的插槽内容</Hint>
......
插槽组件
<template>
<div class="hint">
<h1>Hint module</h1>
<slot>组件的默认提示内容</slot>
</div>
</template>
<script>
export default {
name: 'HintSlot',
data() {
return {}
},
methods: {
},
components: {
}
}
</script>
<style scoped>
</style>
2.5.2 编译作用域
<Hint>来自父页面的插槽内容:{{ msg }}</Hint>
{{ msg }} 虽然显示在slot组件中,但是编译作用域在父页面
2.5.3 后备内容
<Hint></Hint> 时显示 "组件的默认提示内容"。
<Hint>{{ msg }}</Hint>,且 msg=‘ ’ 时 并不显示 "组件的默认提示内容",而是不显示内容。
2.5.4 具名插槽
父页面
......
<Hint>
<template v-slot:header>
<h3>这是头部内容</h3>
</template>
<template v-slot:main>
<p>这是主体内容</p>
</template>
<template v-slot:footer>
<h3>这是底部内容</h3>
</template>
</Hint>
......
插槽组件
<template>
<div class="hint">
<h1>Hint module</h1>
<slot name="header">Header</slot>
<hr/>
<slot name="main">main content</slot>
<hr/>
<slot name="footer">footer</slot>
</div>
</template>
2.5.5 作用域插槽
父页面
......
<template v-slot:default="slotProps" >
<h2>from slot id: {{ slotProps.id }}</h2>
</template>
......
插槽组件
<template>
<div class="hint">
<h1>Hint module</h1>
<slot name="header">Header</slot>
<hr/>
<slot name="main" :id="id">main content</slot>
<hr/>
<slot name="footer">footer</slot>
<hr/>
<slot :id="id">id</slot>
</div>
</template>
<script>
export default {
name: 'HintSlot',
data() {
return {
id:"007"
}
},
methods: {
},
components: {
}
}
</script>
<style scoped>
</style>
理解:
插槽中的数据,传递给父页面处理后返回。
2.5.6 动态插槽名
这个不常用。
2.6 动态组件&异步组件
1、动态引用组件
......
//import Hello from '@/components/Hello.vue';
const Hello = () =>import('@/components/Hello.vue');
......
2、$root
1541

被折叠的 条评论
为什么被折叠?



