通俗易懂--快速入门Vue--3
1.组件使用的细节点1
- is属性在tbody中应用
<div id="root">
<table>
<tbody>
<row></row>
<row></row>
<row></row>
</tbody>
</table>
</div>
<script>
Vue.component('row',{
template:`<tr><td>this is a row</td></tr>`
});
var vm = new Vue({
// el限制一个vue实例的管理范围。
el:"#root",
});
</script>
-
看似上面代码书写没有什么问题,但是打开页面你会看到,如下图:
所有的tr标签都跑到了tbody外面,这是不符合规范的。
-
那么如何解决这个问题,通过is属性,只需要在原来代码改一下:
<div id="root"> <table> <tbody> <tr is="row"></tr> <tr is="row"></tr> <tr is="row"></tr> </tbody> </table> </div>
原有的html实例不变,这样就可以避免tr标签上升到tbody标签外头了。
-
同样像ul(li),select(option)
<ul> <li is="row"></li> <li is="row"></li> <li is="row"></li> </ul> <select> <option is="row"></option> <option is="row"></option> <option is="row"></option> </select>
2.组件使用的细节点2
-
data在子组件中,必须为一个函数,同时函数有返回数据。
Vue.component('row',{ data:function(){ return { content:"this is content" } }, template:`<tr><td>{{content}}</td></tr>` });
3.在Vue中操作DOM
-
Vue不建议在代码中操作DOM,但是在复杂动画效果,不操作DOM,光靠数据的绑定,是无法实现的。
<div id="app"> <div ref="hw" @click="handleClick">hello world</div> </div> var app = new Vue({ el:"#app", methods:{ handleClick:function () { //指的是ref="hw"的DOM divDom = this.$refs.hw; console.log(divDom.innerHTML) } } })
-
那么在组件中是如何应用ref,咱们定义一个计数功能:
<div id="root"> <!-- 父组件监听change变化并交给 handleChange处理--> <counter @change="handleChange" ref="one"></counter> <counter @change="handleChange" ref="two"></counter> <div>{{total}}</div> </div>
Vue.component("counter",{ template:`<div @click="handleClick">{{number}}</div>`, data:function () { return { number:0 } }, methods:{ handleClick:function () { this.number ++; //子组件需要向父组件传递事件,当当前组件数据发生变化时。 this.$emit('change') } } }); var vm = new Vue({ // el限制一个vue实例的管理范围。 el:"#root", //total用来计算两个counter组件内数据的和 data:{ total:0 }, methods:{ handleChange:function () { //total求和 this.total = this.$refs.one.number + this.$refs.two.number } } });
4.父子组件的数据传递
-
父组件可以向子组件传递参数,但是子组件不能修改传递到子组件的参数,这就是单向数据流。
- 方式1:子组件通过复制参数,从而只更改复制过来的参数
<div id="root"> <!--1.父组件向子组件传递名字为count的值--> <counter :count="0"></counter> <counter :count="5"></counter> </div> var counter = { // 2.子组件定义props接收count data:function(){ return { // 3.既然子组件无法修改父组件传来的参数 // 那么number为复制传过来的参数,咱们使用number number:this.count } }, props:['count'], // 4.子组件使用复制过来的number, template:`<div @click="handleClick">{{number}}</div>`, methods:{ handleClick:function () { // 并且还可以更改复制的number this.number ++ } } }; var vm = new Vue({ // el限制一个vue实例的管理范围。 el:"#root", components:{ counter:counter } });
- 方式2:子组件向父组件传递事件
<div id="root"> <!--1.父组件向子组件传递名字为count的值--> <!--监听inc事件,一旦触发执行父组件handleIncrease函数--> <counter :count="0" @inc="handleIncrease"></counter> <counter :count="5" @inc="handleIncrease"></counter> <div>{{total}}</div> </div> var counter = { // 2.子组件定义props接收count data:function(){ return { // 3.既然子组件无法修改父组件传来的参数 // 那么number为复制传过来的参数,咱们使用number number:this.count } }, props:['count'], // 4.子组件使用复制过来的number, template:`<div @click="handleClick">{{number}}</div>`, methods:{ handleClick:function () { // 并且还可以更改复制的number this.number ++; // 5.子组件通过触发事件,将触发的inc事件传递给父组件 this.$emit('inc',1) } } }; var vm = new Vue({ // el限制一个vue实例的管理范围。 el:"#root", data:{ total:5, }, components:{ counter:counter }, methods:{ // 父组件定义函数 handleIncrease:function (step) { // step 为子组件 $emit的第二个参数。 this.total += step } } });
5.组件参数校验与非props特性
-
首先需要了解的是什么是props特性
props特性其实就是,在父组件中传入了参数,恰巧子组件在props也定义了该参数的校验规则。并且子组件能使用该参数在template进行渲染
<child content="hell world"></child> Vue.component('child',{ // 子组件接收props props:{ // 传入content的类型 // 方式1:content:[String,Number] // 方式2: content:{ type:String,//要求传入值类型 required:false,//是否必填 defaule:"default value",//默认值 validator:function (value) { // 传入数据长度大于5 return (value.length > 5) } } }, template:`<div>Child</div>` }); var vm = new Vue({ el:"#root", });
-
非props特性
父组件向子组件传递的是一个属性,子组件并没有声明该属性定义的内容。 1.这样子组件就不能使用该属性在子组件template渲染。 2.那么该属性会在template定义的最外层标签的标签里,显示.e.g.: <div content="hello">hello</div>
6.如何给组件绑定原生事件
-
当给一个组件标签绑定一个事件其实是自定义事件,不会触发原生事件
<div id="root"> <!--当给一个组件标签绑定一个事件其实是自定义事件,不会触发原生事件--> <child @click="handleClick"></child> </div> Vue.component("child",{ // 在标签绑定事件时原生的事件 template:"<div @click='handleClick'>Child</div>", methods:{ //会触发 handleClick:function () { alert("click click") } } }); var vm = new Vue({ el:"#root", methods:{ // 不会触发 handleClick:function () { alert("click") } } });
-
那么如何触发自定义事件?$emit
Vue.component("child",{ // 在标签绑定事件时原生的事件 template:"<div @click='handleClick'>Child</div>", methods:{ //会触发 handleClick:function () { //通过$emit触发自定义事件 this.$emit("click") } } });
-
但是这样写代码冗余,过于繁琐?通过添加事件修饰符.native
<div id="root"> <!--当给一个组件标签绑定一个事件其实是自定义事件,不会触发原生事件--> <!--通过添加.native将该事件转为原生click事件--> <child @click.native="handleClick"></child> </div> </body> <script> Vue.component("child",{ // 在标签绑定事件时原生的事件 template:"<div>Child</div>", }); var vm = new Vue({ el:"#root", methods:{ // 不会触发 handleClick:function () { alert("click") } } }); </script>
7.非父子组件传值
- 当把一个网页拆分成多个部分,每个部分是一个组件
-
如图红线,第二层的组件要跟第一层组件传值可以通过
父组件通过props向子组件传值,子组件通过事件触发,向父组件传值
-
如果第三层组件想传值给第一层组件呢?
如果直接传值是不行了,只能通过第一层组件向第二层,第二层向第三层传值,返回来也是一样。
-
但是这样传值相对比较复杂,比如出现如下图③的情况就相当复杂了:
- 那么如何解决呢?一般有2种方式解决非父子组件传值,一种是vue官方提供的框架vuex,另一种使用发布订阅模式(总线机制)。
- 示例:兄弟组件传值
<div id="exp">
<!--实现点击第一个子组件,里面值变成第二子组件值-->
<!--实现点击第二个子组件,里面值变成第一子组件值-->
<!--这两个child子组件是兄弟关系-->
<child content="James"></child>
<child content="Lucy"></child>
</div>
// 1.将bus属性挂载到 Vue()实例里,以后创建的Vue()实例都有bus属性
Vue.prototype.bus = new Vue();
Vue.component("child",{
props:{
content:String
},
// 1.1.在vue当中单向数据流,子组件不能改变父组件传递的内容
// 所以定义一个data 返回复制后父组件传的内容
data:function(){
return {
selfContent:this.content
}
},
//2.给子组件绑定一个点击事件
template:`<div @click="handleClick">{{selfContent}}</div>`,
methods:{
handleClick:function () {
// 3.通过之前挂载的bus属性,
// 这个bus又是vue实例,所以也有$emit方法。
// 通过$emit触发change事件,同时携带当前标签的内容
this.bus.$emit('change',this.selfContent)
}
},
// 4.mounted为一个生命周期钩子,页面渲染完执行周期函数mounted
// 监听这个bus.的改变(change事件)
mounted:function () {
// 5.底下function使this作用域发生,需要保存当前this
var this_ = this;
this.bus.$on('change',function (msg) {
this_.selfContent = msg
})
}
});
var vm = new Vue({
// el限制一个vue实例的管理范围。
el:"#exp",
});
8.Vue中的插槽
- 插槽使用场景:当子组件内容是根据父组件传递过来的DOM内容进行显示,可以使用插槽。
<div id="exp">
<child>
<p>Dell</p>
</child>
</div>
<script>
//当父组件child标签内没有内容,则会显示<slot>默认内容</slot>
Vue.component('child',{
template:`
<div>
<p>Hello</p>
<slot>默认内容</slot>
</div>`
});
var vm = new Vue({
el:"#exp",
});
</script>
-
具名插槽
- 给插槽取一个名字。每个插槽能按照你的要求插入具体位置。
<div id="exp"> <body-content> <div class="header" slot="header">header</div> <div class="footer" slot="footer">footer</div> </body-content> </div> //当父组件child标签内没有内容,则会显示<slot>默认内容</slot> Vue.component('body-content',{ // 插槽设置默认值 template:` <div> <slot name="header"><h1>default header</h1></slot> <div class="content">content</div> <slot name="footer"></slot> </div>` }); var vm = new Vue({ el:"#exp", });
9.Vue中的作用域插槽
-
应用场景,当子组件做循环,其DOM结构由外部传递给子组件,子组件可以向插槽传递数据,父组件可以通过slot-scope接收数据并渲染。
<div id="exp"> <child> <!--父组件调用子组件给子组件传入一个插槽--> <!--此插槽为作用域插槽,必须是template标签--> <!--声明slot-scope表示从子组件接收的数据都放在myData里--> <template slot-scope="myData"> <!--通过myData调用每一项数据--> <li>{{myData.item}}</li> </template> </child> </div> <script> Vue.component('child',{ data:function(){ return { list:[1,2,3,4,5] } }, // 通过v-for形成插槽,并给每个插槽绑定数据 也就是item template:` <div> <ul> <slot v-for="item of list" :item=item ></slot> </ul> </div>` }); var vm = new Vue({ // el限制一个vue实例的管理范围。 el:"#exp", }); </script>
10.动态组件与v-once指令
-
动态组件
<div id="exp"> <!--根据type动态显示相应组件--> <component :is="type"></component> <!--监听点击事件更改type数据--> <button @click="handleClick">change</button> </div> <script> Vue.component("child-one",{ template:`<div>child one</div>` }); Vue.component("child-two",{ template:`<div>child two</div>` }); var vm = new Vue({ // el限制一个vue实例的管理范围。 el:"#exp", data:{ type:'child-one' }, methods:{ handleClick:function () { this.type = this.type === "child-one" ? "child-two":"child-one" } } }); </script>
-
v-once
看下面代码,会有什么问题
<div id="exp"> <child-one v-if="type === 'child-one'"></child-one> <child-two v-if="type === 'child-two'"></child-two> <button @click="handleClick">change</button> </div> Vue.component("child-one",{ template:`<div>child one</div>` }); Vue.component("child-two",{ template:`<div>child two</div>` }); var vm = new Vue({ // el限制一个vue实例的管理范围。 el:"#exp", data:{ type:'child-one' }, methods:{ handleClick:function () { this.type = this.type === "child-one" ? "child-two":"child-one" } } });
每次点击button按钮其实相当于销毁当前组件创建另一个组件,这样频繁的切换导致创建销毁,挺耗费性能的,如果说我们定义的要切换的组件的内容相似,可以加一个v-once指令。通过v-once会将渲染的页面放在内存中,这样如果再切换回来直接从内存取,会提高静态内容展示效率,只需在子组件template里添加v-once
Vue.component("child-one",{ template:`<div v-once>child one</div>` }); Vue.component("child-two",{ template:`<div v-once>child two</div>` });
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库