马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1.v-model的原理
v-model本质上是一个语法糖,
- 在input文本框中,它是由value属性和oninput变乱构成的
- 在多选框中,它是由checked属性和onchange变乱构成的
- 在select下拉菜单中,它是由value属性和onchange变乱构成的
1.1.验证:在input文本输入框中不使用v-model实现双向数据绑定
- <!-- 1.验证v-model在input文本框中的拆分 -->
- <input type="text" v-model="msg">
- <p>输出msg的当前值:{{msg}}</p>
- <!-- 此时v-model是一个语法糖,由value属性和oninput事件组成
- 其中,value是让数据向视图单向绑定,oninput是view向model单向绑定,
- 若要验证可以删掉其中一个看效果 -->
- <input type="text" :value="msg" @input="msg=$event.target.value">
复制代码 其中,
1.数据厘革,令视图跟着厘革==>:value
2.视图厘革,令数据跟着厘革==>@input
$event.target.value表现输入框用户输入的值,
msg表现model层的数据
1.2.验证:v-model在下拉菜单中的拆分
- <!-- 2.验证v-model在select下拉菜单中的拆分 -->
- <!-- 使用v-model双向绑定: -->
- <select name="" id="" v-model="cityId">
- <option value="101">北京</option>
- <option value="102">上海</option>
- <option value="103">广州</option>
- <option value="104">深圳</option>
- </select>
- <!-- 在下拉菜单中,v-model这个语法糖是由value属性和onchange事件构成的,验证如下: -->
- <select name="" id="" :value="cityId" @change="cityId=$event.target.value">
- <option value="101">北京</option>
- <option value="102">上海</option>
- <option value="103">广州</option>
- <option value="104">深圳</option>
- </select>
复制代码 2.表单类组件的封装
2.1.原理或步调
- 父传子:数据从父组件传过来,因为父组件要举行表单提交
绑定数据:绑定的是v-model的拆解,因为不能让子组件直接修改父组件数据
- 子传父
nchange变乱监听用户对数据的修改,监听的效果传值给父组件,让父组件修改数据
- 父组件:(使用)
- //<BaseSelect :cityId="selectId" @事件名="selectId=最新值"></BaseSelect>
- <BaseSelect :cityId="selectId" @changeId="selectId=$event"></BaseSelect>
- //父组件提供数据
- data(){return{selectId:102}}
- 子组件:(封装)
- 注意这里不能用v-model,要把它拆解成value属性和onchange事件
- <select :value="cityId" @change="handleChange">
- <option value="101">北京</option>
- ...
- </select>
- props:{
- cityId:String
- },
- methods:{
- handleChange(e){
- //console.log(e.target.value);//是否拿到104
- //this.$emit("事件名".e.target.value);
- this.$emit("changeId".e.target.value);
- }
- }
- }
复制代码 2.2.示例:表单类组件封装之下拉菜单select的封装
父组件:App.vue
- //html
- <!-- $event是获得当前事件的形参 -->
- <base-v-model :cityId="selectId" @changeId="selectId=$event"></base-v-model>
-
- //js
- import BaseVModel from "./components/BaseVModel.vue"
- export default {
- components: {
- BaseVModel,
- },
- data(){
- selectId:'102',//此处改成数数字然后子组件的props限制改成Number也可以
- }
- }
复制代码 子组件:BaseVModel.vue
- //html
- <select name="" id="" :value="cityId" @change="handleChange">
- <option value="101">北京</option>
- <option value="102">上海</option>
- <option value="103">广州</option>
- <option value="104">深圳</option>
- </select>
- //js
- props:{
- cityId:String//父传子:接收父组件传过来的数据
- },
- methods: {
- handleChange(e){
- console.log(e.target.value);//获取用户改变城市后对应的id:102,103...
- this.$emit("changeId",e.target.value);//子传父:把监听到的用户输入传给父组件
- },
- }
复制代码 3.使用v-model简化代码
使用v-model举行对上例代码简化,思绪是把绑定的变乱和属性凑成value+input的情势
- 子组件:把:value=cityId更换为:value=value
- 子组件:把this.$emit("changeId",e.target.value)更换成this.$emit("input",e.target.value)
- 父组件:把:cityId:selectId更换成:value:selectId
- 父组件:把@changeId="selectId=$event"更换成@input="selectId=$event"
- 当父组件凑够:value和@input后,可以使用v-model更换它们,即v-model="selectId"
完备代码
父组件:App.vue
- //html
- <!-- <base-v-model :value="selectId" @input="selectId=$event"></base-v-model> -->
- <!-- 凑齐了:value和@input之后,就可以把它们改成v-model,从而达到了简化代码的目的 -->
- <base-v-model v-model="selectId"></base-v-model>
- //js
- data:
- selectId:'102'
复制代码 子组件:BaseVModel.vue
- //html
- <select name="" id="" :value="value" @change="handleChange">
- <option value="101">北京</option>
- <option value="102">上海</option>
- <option value="103">广州</option>
- <option value="104">深圳</option>
- </select>
- //js
- props:{
- // cityId:String
- value:String//改成用value接收,input的拓展示例也用这个value属性
- },
- methods: {
- handleChange(e){
- console.log(e.target.value);
- // this.$emit("changeId",e.target.value);
- this.$emit("input",e.target.value);
- },
复制代码 4.拓展示例:完成input文本输入框的组件化封装
父组件:App.vue
- //html
- <!-- 拓展示例 -->
- <base-v-model v-model="inputMsg"></base-v-model>
- <p>input输入了什么:{{inputMsg}}</p>
- //js
- data(){
- inputMsg:"你好世界"
- }
复制代码 子组件:BaseVModel.vue
- //html
- <!-- 5.拓展和应用:把一个input文本框改成组件 -->
- <input type="text" :value="value" @input="inputFunc">
- //js
- props:{
- // cityId:String
- value:String//改成用value接收,input的拓展示例也用这个value属性
- },
- methods: {
- inputFunc(e){
- this.$emit("input",e.target.value);
- }
- },
复制代码 5..sync修饰符
5.1.介绍
和v-model一样,.sync修饰符同样可以用于父组件和子组件的数据之间的双向绑定,区别在于
前者的props属性名固定为value,这就限定了它的使用场景,而后者的属性名不固定,更为机动
.sync修饰符的本质是:属性名和@update:属性名的合写
5.2.示例:实现弹框类子组件与父组件的双向绑定,实现父组件控制其显隐,要求props通报的属性名为visible
父组件:App.vue
- //html
- <base-dialog :visible.sync="visible"><base-dialog>
- <button @click="visible=true">点击弹出窗口</button>
- //js
- data(){
- visible:false
- }
复制代码 子组件:BaseDialog.vue
- <template>
- <div class="wrapper">
- <!-- step1:弹出框设置v-show并动态绑定visible -->
- <div class="modal-mask" v-show="visible">
- <div class="base-dialog">
- <div class="title">
- <h3>温馨提示</h3>
- <span class="close" @click="handleClick">×</span>
- </div>
- <div class="content">
- <p>你确认要退出本系统吗?</p>
- </div>
- <div class="footer">
- <button class="btn cancel">取消</button>
- <!-- step2:点击确认时,触发事件handleClick -->
- <button class="btn confirm" @click="handleClick">确认</button>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- export default {
- // step3:props接收父组件传过来的属性
- props: {
- visible:Boolean//限制传递的属性为布尔类型
- },
- // step4:把监听到的用户行为(确认关闭)返回给父组件
- methods: {
- handleClick(){
- this.$emit("update:visible",false);//固定搭配--update:属性名
- }
- }
- };
- </script>
- <style scoped>
- /* 通过deekseek写的样式 */
- /* 遮罩层样式 */
- .modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- background: rgba(0, 0, 0, 0.5);
- z-index: 1000;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- /* 弹窗容器 */
- .base-dialog {
- background: #fff;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
- width: 480px;
- max-width: 90vw;
- max-height: 80vh;
- display: flex;
- flex-direction: column;
- }
- /* 标题区域 */
- .title {
- padding: 16px 24px;
- border-bottom: 1px solid #e8e8e8;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .title h3 {
- margin: 0;
- font-size: 18px;
- font-weight: 600;
- color: rgba(0, 0, 0, 0.85);
- }
- .close {
- cursor: pointer;
- font-size: 24px;
- color: #999;
- transition: color 0.3s;
- }
- .close:hover {
- color: #666;
- }
- /* 内容区域 */
- .content {
- padding: 24px;
- flex: 1;
- overflow-y: auto;
- line-height: 1.6;
- color: rgba(0, 0, 0, 0.65);
- }
- /* 底部按钮区域 */
- .footer {
- padding: 16px 24px;
- border-top: 1px solid #e8e8e8;
- text-align: right;
- }
- .btn {
- padding: 8px 20px;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- margin-left: 12px;
- transition: all 0.3s;
- }
- .btn.confirm {
- background: #1890ff;
- color: white;
- }
- .btn.confirm:hover {
- background: #40a9ff;
- box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
- }
- .btn.cancel {
- background: transparent;
- border: 1px solid #d9d9d9;
- color: rgba(0, 0, 0, 0.65);
- }
- .btn.cancel:hover {
- border-color: #1890ff;
- color: #1890ff;
- }
- </style>
复制代码 效果:略
|