我想将组织的应用程序从淘汰赛切换到Vue,但某些概念丢失了,或者我误解了vueJs的理念。所以我无法重现相同的行为。
根据我的阅读,VueJs实际上专注于组件。
每个组件管理都是自己的DOM。
https://fr.vuejs.org/v2/guide/reactivity.html
https://fr.vuejs.org/v2/guide/list.html
...(在开始输入键盘之前,我已经阅读了本指南的大部分内容:p)
此行为对于需要共享的简单组件很好,但在我的情况下,这有点令人沮丧,因为我需要链接一些模块(最后请参见有关上下文的问题)
我读过另一篇很棒的文章(https://jes.al/2017/05/migrating-from-knockoutjs-to-vuejs/),内容涉及“从淘汰赛向Vuejs过渡”,但缺少如此具体的细节。
例如:它的解释是“订阅”(在KO中)可以由“观看”(在Vue中)代替,但没有解释“何时”我们可以应用这些观察者(请参阅我的问题结尾)>
这是一个非常小的代码提取,可以总结出我的大多数特定需求。
HTML
<div id="app">
<div data-bind="text: title"></div>
<i data-bind="visible: changeTracker.hasChanges">save your change dude !!</i>
<div data-bind="with: model">
<!-- the binging "with" allow us to move context to model for the current node and prevent typing "model." each time (ex: model.prop1, modeld.pro2,) -->
<label data-bind="text: name"></label>
<input type="text" data-bind="value: firstName"/>
<span data-bind="text: $parent.nameAndFirstName">
<!-- "$parent" allow us to access vm context itself -->
<input type="text" data-bind="value: city"/>
</div>
<div>
<button data-bind="click: changeTracker.undo, enabled: changeTracker.hasChanges"></button>
<button data-bind="click: saveData, enabled: changeTracker.hasChanges"></button>
</div>
</div>
JavaScript
var changeTrackerVM_Factory = function(){
var self = {};
self.initialState = null; // no need to be ko.observable since it's used for internal manipulation only
// flag that will tell the UI that modification exist
self.hasChanges = ko.observable(false);
self.init = function(modelToTrack){
// some piece of code .... subscribe ... and so on
}
self.undo = function(){
// some piece of code that revrt the object to it's initial state
};
return self;
};
var userVM_Factory = function(){
var self = {};
// data from-to database
self.model = {
id: "", //-- don't need to be observable since it's not rendered and not modifiable
name: ko.observable(""),
firstName: ko.observable(""),
city: ko.observable("")
};
self.nameAndFirstName = ko.computed(function(){
return self.model.name() + "-" + self.model.firstname();
});
// build the custom tracker module
self.changeTracker = changeTrackerVM_Factory();
self.init = function(){
//some ajaxRequest
$.ajax(....).then(function(data){
// map recieved datas
self.model.name(data.name);
......
// apply custom observation AFTER data mapping
self.model.city.subscribe(function(newvalue){
alert("yeaah !! YOU changed the city value");
});
// apply the "custom tracking module" used to show the state in the UI
self.changeTracker.init(self.model);
});
}
self.save = function(){
// some piece of code to send to DATABASE
}
return self;
};
// initialise the relation between the UI and the VM
var userVM = userVM_Factory();
ko.applybinding(userVM , "#app");
如果我想将此代码转换为vueJS并且我有相同的行为,我需要回答:
我如何仅跟踪“模型”的几个属性(我敢肯定,因为这样使用过的libray会受到性能优化的关注)
仅在首次初始化后如何才能启动“观看”(并防止在开始时出现“警告”弹出窗口)
如您所见,我还没有“一个用于其DOM的模块”,例如:changeTracker.hasChanges用于DOM的顶部和底部
如果我仅使用组件自己的DOM来使用组件来管理“模型”,那么在???
答案 0 :(得分:3)
您要问的是一个相当繁重的问题(或多个问题,我应该说)。从根本上讲,这些答案就足够了-以及提供的示例(涵盖了许多问题)。如有任何问题,请告诉我。
如果要跟踪某些属性,则可以使用computed
属性,也可以使用watch
属性。 Computed properties vs Watched properties
如果要跳过watch
属性中的第一个更改,则必须集成某种逻辑,例如设置bool
标志。 More on that here
在组件中使用“外部” js文件有几种不同的方法-您可以将其导入并使用必要的功能,等等。也可以使用mixin
。 More on mixins here
子组件emit
会将数据传递给父组件,父组件通过props
将数据传递给子组件。下面的示例显示了这一点。
编辑: :您正在询问mixins
以及如何向组件中添加“第三方”模块。This CodePen does会产生相同的结果结果与我在下面提供的原始结果相同,只是它使用了mixin
。这说明了如何通过mixin
在任何组件中执行“任何操作”。(或者至少希望如此)...
示例代码:
/*****************************/
/* User VM Factory Component */
/*****************************/
const userVmFactoryComponent = {
name: "userVmFactoryComponent",
template: "#userVmFactoryComponent",
props: {
id: [String, Number],
name: String,
lastName: String,
city: String,
},
data() {
return {
user: {
id: "",
name: "",
lastName: "",
city: "",
}
}
},
methods: {
emitNameChanged(){
this.$emit('name-changed', this.fullName);
}
},
computed: {
fullName() { // using fullName vs nameAndFirstName
return this.user.name + " " + this.user.lastName;
}
},
mounted(){
this.user.id = this.id;
this.user.name = this.name;
this.user.lastName = this.lastName;
this.user.city = this.city;
}
}
/****************/
/* Main Vue App */
/****************/
new Vue({
el: "#app",
components: {
userVmFactoryComponent,
},
data: {
users: [],
},
methods: {
handleNameChange(info) {
alert("You changed the name! (alerted from parent) " + "'" + info + "'")
}
},
mounted() {
// pretend you're getting this data from an API
let firstUser = {
id: 100,
name: 'John',
lastName: 'Smith',
city: 'Paris',
};
let secondUser = {
id: 200,
name: "Jane",
lastName: "Doe",
city: "New York",
}
this.users.push(firstUser);
this.users.push(secondUser);
}
})
.user-input {
margin-bottom: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<!-- MAIN VUE APP -->
<div id="app">
<div>
<div>
<div>Without Looping</div>
<user-vm-factory-component
@name-changed="handleNameChange"
:id="users[0].id"
:name="users[0].name"
:last-name="users[0].lastName"
:city="users[0].city"
></user-vm-factory-component>
<br/>
<user-vm-factory-component
@name-changed="handleNameChange"
:id="users[1].id"
:name="users[1].name"
:last-name="users[1].lastName"
:city="users[1].city"
></user-vm-factory-component>
</div>
<br/><hr/><br/>
<div>
<div>With Looping</div>
<div>
<div v-for="(user, index) in users">
<user-vm-factory-component
@name-changed="handleNameChange"
:id="user.id"
:name="user.name"
:last-name="user.lastName"
:city="user.city"
></user-vm-factory-component>
<br/>
</div>
</div>
</div>
</div>
</div>
<!-- ===================================== -->
<!-- THIS SIMULATES userVmFactoryComponent -->
<!-- ===================================== -->
<script type="text/x-template" id="userVmFactoryComponent">
<div>
Id
<div class="user-input">
<input type="text" v-model="user.id" />
</div>
Name (alerts when changed)
<div class="user-input">
<input type="text" @input="emitNameChanged" v-model="user.name" />
</div>
LastName
<div class="user-input">
<input type="text" v-model="user.lastName" />
</div>
FullName
<div class="user-input">
<input type="text" v-model="fullName" />
</div>
City
<div class="user-input">
<input type="text" v-model="user.city" />
</div>
</div>
</script>